uint32_t v_count_age_owners(uint32_t ageInfoId) { PostgresStrings<2> parms; parms.set(0, ageInfoId); parms.set(1, DS::Vault::e_AgeOwnersFolder); PGresult* result = PQexecParams(s_postgres, "SELECT idx FROM vault.find_folder($1, $2);", 2, 0, parms.m_values, 0, 0, 0); uint32_t owners = 0; if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return owners; } parms.set(0, PQgetvalue(result, 0, 0)); PQclear(result); result = PQexecParams(s_postgres, "SELECT COUNT(*) FROM vault.\"NodeRefs\" WHERE \"ParentIdx\"=$1", 1, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) == PGRES_TUPLES_OK) { owners = strtoul(PQgetvalue(result, 0, 0), 0, 10); } else { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); } PQclear(result); return owners; }
DS::Vault::NodeRef v_send_node(uint32_t nodeId, uint32_t playerId, uint32_t senderId) { DS::Vault::NodeRef ref; ref.m_child = ref.m_owner = ref.m_parent = 0; PostgresStrings<2> parms; parms.set(0, playerId); parms.set(1, DS::Vault::e_InboxFolder); PGresult* result = PQexecParams(s_postgres, "SELECT idx FROM vault.find_folder($1, $2);", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return ref; } DS_DASSERT(PQntuples(result) == 1); uint32_t inbox = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); if (v_ref_node(inbox, nodeId, senderId)) { ref.m_child = nodeId; ref.m_owner = senderId; ref.m_parent = inbox; } return ref; }
bool v_has_node(uint32_t parentId, uint32_t childId) { if (parentId == 0) return false; if (parentId == childId) return true; PostgresStrings<2> parms; parms.set(0, parentId); parms.set(1, childId); check_postgres(); PGresult* result = PQexecParams(s_postgres, "SELECT vault.has_node($1, $2)", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } DS_DASSERT(PQntuples(result) == 1); bool retval = (*PQgetvalue(result, 0, 0) == 't'); PQclear(result); return retval != 0; }
bool v_fetch_tree(uint32_t nodeId, std::vector<DS::Vault::NodeRef>& refs) { PostgresStrings<1> parm; parm.set(0, nodeId); PGresult* result = PQexecParams(s_postgres, "SELECT \"ParentIdx\", \"ChildIdx\", \"OwnerIdx\", \"Seen\"" " FROM vault.fetch_tree($1);", 1, 0, parm.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } refs.resize(PQntuples(result)); for (size_t i=0; i<refs.size(); ++i) { refs[i].m_parent = strtoul(PQgetvalue(result, i, 0), 0, 10); refs[i].m_child = strtoul(PQgetvalue(result, i, 1), 0, 10); refs[i].m_owner = strtoul(PQgetvalue(result, i, 2), 0, 10); refs[i].m_seen = strtoul(PQgetvalue(result, i, 3), 0, 10); } PQclear(result); return true; }
bool v_find_public_ages(const DS::String& ageFilename, std::vector<Auth_PubAgeRequest::NetAgeInfo>& ages) { PostgresStrings<2> parms; parms.set(0, DS::Vault::e_NodeAgeInfo); parms.set(1, ageFilename); // ageInfoId, Uuid, InstName, UserName, Description, SeqNumber, Language PGresult* result = PQexecParams(s_postgres, "SELECT idx, \"Uuid_1\", \"String64_3\", \"String64_4\"," " \"Text_1\",\"Int32_1\", \"Int32_3\" FROM vault.\"Nodes\"" " WHERE \"NodeType\"=$1 AND \"Int32_2\"=1 AND \"String64_2\"=$2" " ORDER BY \"ModifyTime\" LIMIT 50", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } for (int i = 0; i < PQntuples(result); ++i) { Auth_PubAgeRequest::NetAgeInfo ai; ai.m_instance = DS::Uuid(PQgetvalue(result, i, 1)); ai.m_instancename = PQgetvalue(result, i, 2); ai.m_username = PQgetvalue(result, i, 3); ai.m_description = PQgetvalue(result, i, 4); ai.m_sequence = strtoul(PQgetvalue(result, i, 5), 0, 10); ai.m_language = strtoul(PQgetvalue(result, i, 6), 0, 10); ai.m_curPopulation = v_count_age_population(PQgetvalue(result, i, 1)); ai.m_population = v_count_age_owners(strtoul(PQgetvalue(result, i, 0), 0 , 10)); ages.push_back(ai); } PQclear(result); return true; }
static std::tuple<uint32_t, uint32_t> find_a_friendly_neighborhood_for_our_new_visitor() { PGresult* result = PQexec(s_postgres, "SELECT idx FROM vault.\"Nodes\" WHERE \"String64_2\"=" " 'Neighborhood' AND \"String64_4\" = '" HOOD_USER_NAME "'" " ORDER BY \"Int32_1\""); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return std::make_tuple<uint32_t, uint32_t>(0, 0); } uint32_t theHoodInfo = 0; for (int i = 0; i < PQntuples(result); ++i) { uint32_t ageInfoId = strtoul(PQgetvalue(result, i, 0), 0, 10); uint32_t owners = v_count_age_owners(ageInfoId); if (owners < HOOD_POPULATION_THRESHOLD) { theHoodInfo = ageInfoId; break; } } PQclear(result); // Need new hood? if (theHoodInfo == 0) { AuthServer_AgeInfo age; age.m_ageId = gen_uuid(); age.m_filename = "Neighborhood"; age.m_instName = HOOD_INSTANCE_NAME; age.m_userName = HOOD_USER_NAME; age.m_description = HOOD_USER_NAME " " HOOD_INSTANCE_NAME; age.m_seqNumber = -1; // Auto-generate theHoodInfo = std::get<1>(v_create_age(age, e_AgePublic)); } // It's important to BCast new hood members, so we'll return the ageOwners folder PostgresStrings<2> parms; parms.set(0, theHoodInfo); parms.set(1, DS::Vault::e_AgeOwnersFolder); result = PQexecParams(s_postgres, "SELECT idx FROM vault.find_folder($1, $2);", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) == PGRES_TUPLES_OK) { uint32_t ownersFolder = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); return std::make_tuple(theHoodInfo, ownersFolder); } else { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return std::make_tuple(0, 0); } }
bool dm_vault_init() { PostgresStrings<1> sparm; sparm.set(0, DS::Vault::e_NodeSystem); PGresult* result = PQexecParams(s_postgres, "SELECT \"idx\" FROM vault.\"Nodes\"" " WHERE \"NodeType\"=$1", 1, 0, sparm.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } int count = PQntuples(result); if (count == 0) { PQclear(result); fputs("[Vault] Initializing empty DirtSand vault\n", stderr); // Create system and global inbox nodes DS::Vault::Node node; node.set_NodeType(DS::Vault::e_NodeSystem); s_systemNode = v_create_node(node); if (s_systemNode == 0) return false; node.set_NodeType(DS::Vault::e_NodeFolder); node.set_Int32_1(DS::Vault::e_GlobalInboxFolder); uint32_t globalInbox = v_create_node(node); if (globalInbox == 0) return false; if (!v_ref_node(s_systemNode, globalInbox, 0)) return false; std::list<AuthServer_AgeInfo> ages = configure_static_ages(); for (auto iter = ages.begin(); iter != ages.end(); ++iter) { if (std::get<0>(v_create_age(*iter, e_AgePublic)) == 0) return false; } } else { DS_DASSERT(count == 1); s_systemNode = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); } return true; }
static uint32_t find_public_age_1(const DS::String& filename) { PGresult* result; { PostgresStrings<1> parm; parm.set(0, filename); result = PQexecParams(s_postgres, "SELECT \"AgeUuid\" FROM game.\"PublicAges\"" " WHERE \"AgeFilename\"=$1 AND \"SeqNumber\"=0", 1, 0, parm.m_values, 0, 0, 0); } if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return 0; } DS_DASSERT(PQntuples(result) == 1); DS::Uuid ageId(PQgetvalue(result, 0, 0)); PQclear(result); { PostgresStrings<2> parms; parms.set(0, DS::Vault::e_NodeAgeInfo); parms.set(1, ageId.toString()); result = PQexecParams(s_postgres, "SELECT idx FROM vault.\"Nodes\"" " WHERE \"NodeType\"=$1 AND \"Uuid_1\"=$2", 2, 0, parms.m_values, 0, 0, 0); } if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return 0; } if (PQntuples(result) == 0) { // Public age not found PQclear(result); return 0; } DS_DASSERT(PQntuples(result) == 1); uint32_t ageInfoNode = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); return ageInfoNode; }
void dm_game_shutdown(GameHost_Private* host) { { std::lock_guard<std::mutex> clientGuard(host->m_clientMutex); for (auto client_iter = host->m_clients.begin(); client_iter != host->m_clients.end(); ++client_iter) DS::CloseSock(client_iter->second->m_sock); } for (auto clone_iter = host->m_clones.begin(); clone_iter != host->m_clones.end(); ++clone_iter) clone_iter->second->unref(); host->m_clones.clear(); bool complete = false; for (int i=0; i<50 && !complete; ++i) { host->m_clientMutex.lock(); size_t alive = host->m_clients.size(); host->m_clientMutex.unlock(); if (alive == 0) complete = true; std::this_thread::sleep_for(std::chrono::milliseconds(100)); } if (!complete) fputs("[Game] Clients didn't die after 5 seconds!\n", stderr); s_gameHostMutex.lock(); hostmap_t::iterator host_iter = s_gameHosts.begin(); while (host_iter != s_gameHosts.end()) { if (host_iter->second == host) host_iter = s_gameHosts.erase(host_iter); else ++host_iter; } s_gameHostMutex.unlock(); if (host->m_temp) { PostgresStrings<1> params; params.set(0, host->m_serverIdx); PQexecParams(host->m_postgres, "DELETE FROM game.\"Servers\" " " WHERE \"idx\"=$1;", 1, 0, params.m_values, 0, 0, 0); } PQfinish(host->m_postgres); delete host; }
bool v_unref_node(uint32_t parentIdx, uint32_t childIdx) { PostgresStrings<2> parms; parms.set(0, parentIdx); parms.set(1, childIdx); PGresult* result = PQexecParams(s_postgres, "DELETE FROM vault.\"NodeRefs\"" " WHERE \"ParentIdx\"=$1 AND \"ChildIdx\"=$2", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres DELETE error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } PQclear(result); return true; }
static uint32_t find_public_age_1(const DS::String& filename) { PostgresStrings<1> parm; parm.set(0, filename); PGresult* result = PQexecParams(s_postgres, "SELECT idx FROM vault.\"Nodes\"" " WHERE \"Int32_2\" = 1 AND \"String64_2\"=$1", 1, 0, parm.m_values, 0, 0, 0); uint32_t ageInfoId = 0; if (PQresultStatus(result) == PGRES_TUPLES_OK) { DS_DASSERT(PQntuples(result) == 1); ageInfoId = strtoul(PQgetvalue(result, 0, 0), 0, 10); } else { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); } PQclear(result); return ageInfoId; }
uint32_t v_count_age_population(const char* uuid) { PostgresStrings<2> parms; parms.set(0, DS::Vault::e_NodePlayerInfo); parms.set(1, uuid); PGresult* result = PQexecParams(s_postgres, "SELECT COUNT(*) FROM vault.\"Nodes\" WHERE \"NodeType\"=$1 AND" " \"Int32_1\"=1 AND \"Uuid_1\"=$2", 2, 0, parms.m_values, 0, 0, 0); uint32_t population = 0; if (PQresultStatus(result) == PGRES_TUPLES_OK) { population = strtoul(PQgetvalue(result, 0, 0), 0, 10); } else { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); } PQclear(result); return population; }
bool v_ref_node(uint32_t parentIdx, uint32_t childIdx, uint32_t ownerIdx) { PostgresStrings<3> parms; parms.set(0, parentIdx); parms.set(1, childIdx); parms.set(2, ownerIdx); PGresult* result = PQexecParams(s_postgres, "INSERT INTO vault.\"NodeRefs\"" " (\"ParentIdx\", \"ChildIdx\", \"OwnerIdx\")" " VALUES ($1, $2, $3)", 3, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres INSERT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } PQclear(result); return true; }
void dm_save_sdl_state(GameHost_Private* host, const DS::String& descriptor, const MOUL::Uoid& object, const SDL::State& state) { check_postgres(host); DS::Blob sdlBlob = state.toBlob(); PostgresStrings<4> parms; host->m_buffer.truncate(); object.write(&host->m_buffer); parms.set(0, host->m_serverIdx); parms.set(1, descriptor); parms.set(2, DS::Base64Encode(host->m_buffer.buffer(), host->m_buffer.size())); parms.set(3, DS::Base64Encode(sdlBlob.buffer(), sdlBlob.size())); PGresult* result = PQexecParams(host->m_postgres, "SELECT idx FROM game.\"AgeStates\"" " WHERE \"ServerIdx\"=$1 AND \"Descriptor\"=$2 AND \"ObjectKey\"=$3", 3, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(host->m_postgres)); PQclear(result); return; } if (PQntuples(result) == 0) { PQclear(result); result = PQexecParams(host->m_postgres, "INSERT INTO game.\"AgeStates\"" " (\"ServerIdx\", \"Descriptor\", \"ObjectKey\", \"SdlBlob\")" " VALUES ($1, $2, $3, $4)", 4, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres INSERT error: %s\n", __FILE__, __LINE__, PQerrorMessage(host->m_postgres)); PQclear(result); return; } PQclear(result); } else { DS_DASSERT(PQntuples(result) == 1); parms.set(0, DS::String(PQgetvalue(result, 0, 0))); parms.set(1, parms.m_strings[3]); // SDL blob PQclear(result); result = PQexecParams(host->m_postgres, "UPDATE game.\"AgeStates\"" " SET \"SdlBlob\"=$2 WHERE idx=$1", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres UPDATE error: %s\n", __FILE__, __LINE__, PQerrorMessage(host->m_postgres)); PQclear(result); return; } PQclear(result); } }
bool v_update_node(const DS::Vault::Node& node) { /* This should be plenty to store everything we need without a bunch * of dynamic reallocations */ PostgresStrings<32> parms; char fieldbuf[1024]; size_t parmcount = 1; char* fieldp = fieldbuf; #define SET_FIELD(name, value) \ { \ parms.set(parmcount++, value); \ fieldp += sprintf(fieldp, "\"" #name "\"=$%Zu,", parmcount); \ } int now = time(0); SET_FIELD(ModifyTime, now); if (node.has_CreateAgeName()) SET_FIELD(CreateAgeName, node.m_CreateAgeName); if (node.has_CreateAgeUuid()) SET_FIELD(CreateAgeUuid, node.m_CreateAgeUuid.toString()); if (node.has_CreatorUuid()) SET_FIELD(CreatorUuid, node.m_CreatorUuid.toString()); if (node.has_CreatorIdx()) SET_FIELD(CreatorIdx, node.m_CreatorIdx); if (node.has_NodeType()) SET_FIELD(NodeType, node.m_NodeType); if (node.has_Int32_1()) SET_FIELD(Int32_1, node.m_Int32_1); if (node.has_Int32_2()) SET_FIELD(Int32_2, node.m_Int32_2); if (node.has_Int32_3()) SET_FIELD(Int32_3, node.m_Int32_3); if (node.has_Int32_4()) SET_FIELD(Int32_4, node.m_Int32_4); if (node.has_Uint32_1()) SET_FIELD(Uint32_1, node.m_Uint32_1); if (node.has_Uint32_2()) SET_FIELD(Uint32_2, node.m_Uint32_2); if (node.has_Uint32_3()) SET_FIELD(Uint32_3, node.m_Uint32_3); if (node.has_Uint32_4()) SET_FIELD(Uint32_4, node.m_Uint32_4); if (node.has_Uuid_1()) SET_FIELD(Uuid_1, node.m_Uuid_1.toString()); if (node.has_Uuid_2()) SET_FIELD(Uuid_2, node.m_Uuid_2.toString()); if (node.has_Uuid_3()) SET_FIELD(Uuid_3, node.m_Uuid_3.toString()); if (node.has_Uuid_4()) SET_FIELD(Uuid_4, node.m_Uuid_4.toString()); if (node.has_String64_1()) SET_FIELD(String64_1, node.m_String64_1); if (node.has_String64_2()) SET_FIELD(String64_2, node.m_String64_2); if (node.has_String64_3()) SET_FIELD(String64_3, node.m_String64_3); if (node.has_String64_4()) SET_FIELD(String64_4, node.m_String64_4); if (node.has_String64_5()) SET_FIELD(String64_5, node.m_String64_5); if (node.has_String64_6()) SET_FIELD(String64_6, node.m_String64_6); if (node.has_IString64_1()) SET_FIELD(IString64_1, node.m_IString64_1); if (node.has_IString64_2()) SET_FIELD(IString64_2, node.m_IString64_2); if (node.has_Text_1()) SET_FIELD(Text_1, node.m_Text_1); if (node.has_Text_2()) SET_FIELD(Text_2, node.m_Text_2); if (node.has_Blob_1()) SET_FIELD(Blob_1, DS::Base64Encode(node.m_Blob_1.buffer(), node.m_Blob_1.size())); if (node.has_Blob_2()) SET_FIELD(Blob_2, DS::Base64Encode(node.m_Blob_2.buffer(), node.m_Blob_2.size())); #undef SET_FIELD DS_DASSERT(fieldp - fieldbuf < 1024); *(fieldp - 1) = 0; // Get rid of the last comma DS::String queryStr = "UPDATE vault.\"Nodes\"\n SET "; queryStr += fieldbuf; queryStr += "\n WHERE idx=$1"; parms.set(0, node.m_NodeIdx); check_postgres(); PGresult* result = PQexecParams(s_postgres, queryStr.c_str(), parmcount, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres UPDATE error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } PQclear(result); return true; }
DS::Vault::Node v_fetch_node(uint32_t nodeIdx) { PostgresStrings<1> parm; parm.set(0, nodeIdx); PGresult* result = PQexecParams(s_postgres, "SELECT idx, \"CreateTime\", \"ModifyTime\", \"CreateAgeName\"," " \"CreateAgeUuid\", \"CreatorUuid\", \"CreatorIdx\", \"NodeType\"," " \"Int32_1\", \"Int32_2\", \"Int32_3\", \"Int32_4\"," " \"Uint32_1\", \"Uint32_2\", \"Uint32_3\", \"Uint32_4\"," " \"Uuid_1\", \"Uuid_2\", \"Uuid_3\", \"Uuid_4\"," " \"String64_1\", \"String64_2\", \"String64_3\", \"String64_4\"," " \"String64_5\", \"String64_6\", \"IString64_1\", \"IString64_2\"," " \"Text_1\", \"Text_2\", \"Blob_1\", \"Blob_2\"" " FROM vault.\"Nodes\" WHERE idx=$1", 1, 0, parm.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return DS::Vault::Node(); } if (PQntuples(result) == 0) { PQclear(result); return DS::Vault::Node(); } DS_DASSERT(PQntuples(result) == 1); DS::Vault::Node node; node.set_NodeIdx(strtoul(PQgetvalue(result, 0, 0), 0, 10)); node.set_CreateTime(strtoul(PQgetvalue(result, 0, 1), 0, 10)); node.set_ModifyTime(strtoul(PQgetvalue(result, 0, 2), 0, 10)); if (!PQgetisnull(result, 0, 3)) node.set_CreateAgeName(PQgetvalue(result, 0, 3)); if (!PQgetisnull(result, 0, 4)) node.set_CreateAgeUuid(PQgetvalue(result, 0, 4)); if (!PQgetisnull(result, 0, 5)) node.set_CreatorUuid(PQgetvalue(result, 0, 5)); if (!PQgetisnull(result, 0, 6)) node.set_CreatorIdx(strtoul(PQgetvalue(result, 0, 6), 0, 10)); node.set_NodeType(strtoul(PQgetvalue(result, 0, 7), 0, 10)); if (!PQgetisnull(result, 0, 8)) node.set_Int32_1(strtol(PQgetvalue(result, 0, 8), 0, 10)); if (!PQgetisnull(result, 0, 9)) node.set_Int32_2(strtol(PQgetvalue(result, 0, 9), 0, 10)); if (!PQgetisnull(result, 0, 10)) node.set_Int32_3(strtol(PQgetvalue(result, 0, 10), 0, 10)); if (!PQgetisnull(result, 0, 11)) node.set_Int32_4(strtol(PQgetvalue(result, 0, 11), 0, 10)); if (!PQgetisnull(result, 0, 12)) node.set_Uint32_1(strtoul(PQgetvalue(result, 0, 12), 0, 10)); if (!PQgetisnull(result, 0, 13)) node.set_Uint32_2(strtoul(PQgetvalue(result, 0, 13), 0, 10)); if (!PQgetisnull(result, 0, 14)) node.set_Uint32_3(strtoul(PQgetvalue(result, 0, 14), 0, 10)); if (!PQgetisnull(result, 0, 15)) node.set_Uint32_4(strtoul(PQgetvalue(result, 0, 15), 0, 10)); if (!PQgetisnull(result, 0, 16)) node.set_Uuid_1(PQgetvalue(result, 0, 16)); if (!PQgetisnull(result, 0, 17)) node.set_Uuid_2(PQgetvalue(result, 0, 17)); if (!PQgetisnull(result, 0, 18)) node.set_Uuid_3(PQgetvalue(result, 0, 18)); if (!PQgetisnull(result, 0, 19)) node.set_Uuid_4(PQgetvalue(result, 0, 19)); if (!PQgetisnull(result, 0, 20)) node.set_String64_1(PQgetvalue(result, 0, 20)); if (!PQgetisnull(result, 0, 21)) node.set_String64_2(PQgetvalue(result, 0, 21)); if (!PQgetisnull(result, 0, 22)) node.set_String64_3(PQgetvalue(result, 0, 22)); if (!PQgetisnull(result, 0, 23)) node.set_String64_4(PQgetvalue(result, 0, 23)); if (!PQgetisnull(result, 0, 24)) node.set_String64_5(PQgetvalue(result, 0, 24)); if (!PQgetisnull(result, 0, 25)) node.set_String64_6(PQgetvalue(result, 0, 25)); if (!PQgetisnull(result, 0, 26)) node.set_IString64_1(PQgetvalue(result, 0, 26)); if (!PQgetisnull(result, 0, 27)) node.set_IString64_2(PQgetvalue(result, 0, 27)); if (!PQgetisnull(result, 0, 28)) node.set_Text_1(PQgetvalue(result, 0, 28)); if (!PQgetisnull(result, 0, 29)) node.set_Text_2(PQgetvalue(result, 0, 29)); if (!PQgetisnull(result, 0, 30)) node.set_Blob_1(DS::Base64Decode(PQgetvalue(result, 0, 30))); if (!PQgetisnull(result, 0, 31)) node.set_Blob_2(DS::Base64Decode(PQgetvalue(result, 0, 31))); PQclear(result); return node; }
GameHost_Private* start_game_host(uint32_t ageMcpId) { PGconn* postgres = PQconnectdb(DS::String::Format( "host='%s' port='%s' user='******' password='******' dbname='%s'", DS::Settings::DbHostname(), DS::Settings::DbPort(), DS::Settings::DbUsername(), DS::Settings::DbPassword(), DS::Settings::DbDbaseName()).c_str()); if (PQstatus(postgres) != CONNECTION_OK) { fprintf(stderr, "Error connecting to postgres: %s", PQerrorMessage(postgres)); PQfinish(postgres); return 0; } PostgresStrings<1> parms; parms.set(0, ageMcpId); PGresult* result = PQexecParams(postgres, "SELECT \"AgeUuid\", \"AgeFilename\", \"AgeIdx\", \"SdlIdx\", \"Temporary\"" " FROM game.\"Servers\" WHERE idx=$1", 1, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(postgres)); PQclear(result); PQfinish(postgres); return 0; } if (PQntuples(result) == 0) { fprintf(stderr, "[Game] Age MCP %u not found\n", ageMcpId); PQclear(result); PQfinish(postgres); return 0; } else { DS_DASSERT(PQntuples(result) == 1); GameHost_Private* host = new GameHost_Private(); host->m_instanceId = PQgetvalue(result, 0, 0); host->m_ageFilename = PQgetvalue(result, 0, 1); host->m_ageIdx = strtoul(PQgetvalue(result, 0, 2), 0, 10); host->m_gameMaster = 0; host->m_serverIdx = ageMcpId; host->m_postgres = postgres; host->m_temp = strcmp("t", PQgetvalue(result, 0, 4)) == 0; // Fetch the age states Auth_FetchSDL sdlFetch; AuthClient_Private fakeClient; sdlFetch.m_client = &fakeClient; sdlFetch.m_ageFilename = host->m_ageFilename; sdlFetch.m_sdlNodeId = strtoul(PQgetvalue(result, 0, 3), 0, 10); PQclear(result); s_authChannel.putMessage(e_AuthFetchSDL, reinterpret_cast<void*>(&sdlFetch)); DS::FifoMessage reply = fakeClient.m_channel.getMessage(); if (reply.m_messageType != DS::e_NetSuccess) { fputs("[Game] Error fetching Age SDL\n", stderr); PQfinish(postgres); delete host; return 0; } host->m_sdlIdx = sdlFetch.m_sdlNodeId; host->m_globalState = sdlFetch.m_globalState; // Load the local state and see if it needs to be updated try { host->m_localState = SDL::State::FromBlob(sdlFetch.m_localState); } catch (DS::EofException&) { fprintf(stderr, "[SDL] Error parsing Age SDL state for %s\n", host->m_ageFilename.c_str()); PQfinish(postgres); delete host; return 0; } if (host->m_localState.update()) { DS::Blob local = host->m_localState.toBlob(); dm_local_sdl_update(host, local); host->m_ageSdlHook = SDL::State::FromBlob(local); } else { host->m_ageSdlHook = SDL::State::FromBlob(sdlFetch.m_localState); } host->m_ageSdlHook.merge(host->m_globalState); s_gameHostMutex.lock(); s_gameHosts[ageMcpId] = host; s_gameHostMutex.unlock(); // Fetch initial server state PostgresStrings<1> parms; parms.set(0, host->m_serverIdx); PGresult* result = PQexecParams(host->m_postgres, "SELECT \"Descriptor\", \"ObjectKey\", \"SdlBlob\"" " FROM game.\"AgeStates\" WHERE \"ServerIdx\"=$1", 1, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(host->m_postgres)); } else { int count = PQntuples(result); for (int i=0; i<count; ++i) { DS::BlobStream bsObject(DS::Base64Decode(PQgetvalue(result, i, 1))); DS::Blob sdlblob = DS::Base64Decode(PQgetvalue(result, i, 2)); MOUL::Uoid key; key.read(&bsObject); try { SDL::State state = SDL::State::FromBlob(sdlblob); state.update(); GameState gs; gs.m_isAvatar = false; gs.m_persist = true; gs.m_state = state; host->m_states[key][PQgetvalue(result, i, 0)] = gs; } catch (DS::EofException) { fprintf(stderr, "[SDL] Error parsing state %s for [%04X]%s\n", PQgetvalue(result, i, 0), key.m_type, key.m_name.c_str()); } } } PQclear(result); std::thread threadh(&dm_gameHost, host); threadh.detach(); return host; } }
bool dm_vault_init() { PostgresStrings<1> sparm; sparm.set(0, DS::Vault::e_NodeSystem); PGresult* result = PQexecParams(s_postgres, "SELECT \"idx\" FROM vault.\"Nodes\"" " WHERE \"NodeType\"=$1", 1, 0, sparm.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return false; } int count = PQntuples(result); if (count == 0) { PQclear(result); fprintf(stderr, "[Vault] Initializing empty DirtSand vault\n"); // Create system and global inbox nodes DS::Vault::Node node; node.set_NodeType(DS::Vault::e_NodeSystem); s_systemNode = v_create_node(node); if (s_systemNode == 0) return false; node.set_NodeType(DS::Vault::e_NodeFolder); node.set_Int32_1(DS::Vault::e_GlobalInboxFolder); uint32_t globalInbox = v_create_node(node); if (globalInbox == 0) return false; if (!v_ref_node(s_systemNode, globalInbox, 0)) return false; AuthServer_AgeInfo age; age.m_ageId = gen_uuid(); age.m_filename = "city"; age.m_instName = "Ae'gura"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "Neighborhood02"; age.m_instName = "Kirel"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "Kveer"; age.m_instName = "K'veer"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "GreatTreePub"; age.m_instName = "The Watcher's Pub"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "GuildPub-Cartographers"; age.m_instName = "The Cartographers' Guild Pub"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "GuildPub-Greeters"; age.m_instName = "The Greeters' Guild Pub"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "GuildPub-Maintainers"; age.m_instName = "The Maintainers' Guild Pub"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "GuildPub-Messengers"; age.m_instName = "The Messengers' Guild Pub"; if (v_create_age(age, e_AgePublic).first == 0) return false; age.m_ageId = gen_uuid(); age.m_filename = "GuildPub-Writers"; age.m_instName = "The Writers' Guild Pub"; if (v_create_age(age, e_AgePublic).first == 0) return false; } else { DS_DASSERT(count == 1); s_systemNode = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); } return true; }
std::tuple<uint32_t, uint32_t, uint32_t> v_create_player(DS::Uuid acctId, const AuthServer_PlayerInfo& player) { DS::Vault::Node node; node.set_NodeType(DS::Vault::e_NodePlayer); node.set_CreatorUuid(acctId); node.set_Int32_2(player.m_explorer); node.set_Uuid_1(acctId); node.set_String64_1(player.m_avatarModel); node.set_IString64_1(player.m_playerName); uint32_t playerIdx = v_create_node(node); if (playerIdx == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfo); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Uint32_1(playerIdx); node.set_IString64_1(player.m_playerName); uint32_t playerInfoNode = v_create_node(node); if (playerInfoNode == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfoList); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_BuddyListFolder); uint32_t buddyList = v_create_node(node); if (buddyList == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfoList); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_IgnoreListFolder); uint32_t ignoreList = v_create_node(node); if (ignoreList == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_PlayerInviteFolder); uint32_t invites = v_create_node(node); if (invites == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeInfoList); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_AgesIOwnFolder); uint32_t agesNode = v_create_node(node); if (agesNode == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_AgeJournalsFolder); uint32_t journals = v_create_node(node); if (journals == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_ChronicleFolder); uint32_t chronicles = v_create_node(node); if (chronicles == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeInfoList); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_AgesICanVisitFolder); uint32_t visitFolder = v_create_node(node); if (visitFolder == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_AvatarOutfitFolder); uint32_t outfit = v_create_node(node); if (outfit == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_AvatarClosetFolder); uint32_t closet = v_create_node(node); if (closet == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_InboxFolder); uint32_t inbox = v_create_node(node); if (inbox == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfoList); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Int32_1(DS::Vault::e_PeopleIKnowAboutFolder); uint32_t peopleNode = v_create_node(node); if (peopleNode == 0) return std::make_tuple(0, 0, 0); DS::Blob link(reinterpret_cast<const uint8_t*>("Default:LinkInPointDefault:;"), strlen("Default:LinkInPointDefault:;")); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeLink); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Blob_1(link); uint32_t reltoLink = v_create_node(node); if (reltoLink == 0) return std::make_tuple(0, 0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeLink); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Blob_1(link); uint32_t hoodLink = v_create_node(node); if (hoodLink == 0) return std::make_tuple(0, 0, 0); link = DS::Blob(reinterpret_cast<const uint8_t*>("Ferry Terminal:LinkInPointFerry:;"), strlen("Ferry Terminal:LinkInPointFerry:;")); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeLink); node.set_CreatorUuid(acctId); node.set_CreatorIdx(playerIdx); node.set_Blob_1(link); uint32_t cityLink = v_create_node(node); if (hoodLink == 0) return std::make_tuple(0, 0, 0); AuthServer_AgeInfo relto; relto.m_ageId = gen_uuid(); relto.m_filename = "Personal"; relto.m_instName = "Relto"; relto.m_userName = player.m_playerName + "'s"; relto.m_description = relto.m_userName + " " + relto.m_instName; std::tuple<uint32_t, uint32_t> reltoAge = v_create_age(relto, 0); if (std::get<0>(reltoAge) == 0) return std::make_tuple(0, 0, 0); { PostgresStrings<2> parms; parms.set(0, std::get<1>(reltoAge)); parms.set(1, DS::Vault::e_AgeOwnersFolder); PGresult* result = PQexecParams(s_postgres, "SELECT idx FROM vault.find_folder($1, $2);", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return std::make_tuple(0, 0, 0); } DS_DASSERT(PQntuples(result) == 1); uint32_t ownerFolder = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); if (!v_ref_node(ownerFolder, playerInfoNode, 0)) return std::make_tuple(0, 0, 0); } std::tuple<uint32_t, uint32_t> hoodAge = find_a_friendly_neighborhood_for_our_new_visitor(); if (std::get<0>(hoodAge) == 0) return std::make_tuple(0, 0, 0); uint32_t cityAge = find_public_age_1("city"); if (cityAge == 0) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, s_systemNode, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, playerInfoNode, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, buddyList, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, ignoreList, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, invites, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, agesNode, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, journals, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, chronicles, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, visitFolder, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, outfit, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, closet, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, inbox, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(playerIdx, peopleNode, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(agesNode, reltoLink, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(agesNode, hoodLink, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(agesNode, cityLink, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(reltoLink, std::get<1>(reltoAge), 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(hoodLink, std::get<0>(hoodAge), 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(cityLink, cityAge, 0)) return std::make_tuple(0, 0, 0); if (!v_ref_node(std::get<0>(reltoAge), agesNode, 0)) return std::make_tuple(0, 0, 0); return std::make_tuple(playerIdx, playerInfoNode, std::get<1>(hoodAge)); }
std::tuple<uint32_t, uint32_t> v_create_age(AuthServer_AgeInfo age, uint32_t flags) { if (age.m_ageId.isNull()) age.m_ageId = gen_uuid(); int seqNumber = age.m_seqNumber; if (seqNumber < 0) { check_postgres(); PGresult* result = PQexec(s_postgres, "SELECT nextval('game.\"AgeSeqNumber\"'::regclass)"); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return std::make_pair(0, 0); } DS_DASSERT(PQntuples(result) == 1); seqNumber = strtol(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); } DS::Vault::Node node; node.set_NodeType(DS::Vault::e_NodeAge); node.set_CreatorUuid(age.m_ageId); node.set_Uuid_1(age.m_ageId); if (!age.m_parentId.isNull()) node.set_Uuid_2(age.m_parentId); node.set_String64_1(age.m_filename); uint32_t ageNode = v_create_node(node); if (ageNode == 0) return std::make_pair(0, 0); // TODO: Global SDL node node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_ChronicleFolder); uint32_t chronFolder = v_create_node(node); if (chronFolder == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfoList); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_PeopleIKnowAboutFolder); uint32_t knownFolder = v_create_node(node); if (knownFolder == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeInfoList); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_SubAgesFolder); uint32_t subAgesFolder = v_create_node(node); if (subAgesFolder == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeInfo); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(seqNumber); node.set_Int32_2((flags & e_AgePublic) != 0 ? 1 : 0); node.set_Int32_3(age.m_language); node.set_Uint32_1(ageNode); node.set_Uint32_2(0); // Czar ID node.set_Uint32_3(0); // Flags node.set_Uuid_1(age.m_ageId); if (!age.m_parentId.isNull()) node.set_Uuid_2(age.m_parentId); node.set_String64_2(age.m_filename); if (!age.m_instName.isNull()) node.set_String64_3(age.m_instName); if (!age.m_userName.isEmpty()) node.set_String64_4(age.m_userName); if (!age.m_description.isEmpty()) node.set_Text_1(age.m_description); uint32_t ageInfoNode = v_create_node(node); if (ageInfoNode == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeFolder); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_AgeDevicesFolder); uint32_t devsFolder = v_create_node(node); if (devsFolder == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfoList); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_CanVisitFolder); uint32_t canVisitList = v_create_node(node); if (canVisitList == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeSDL); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(0); node.set_String64_1(age.m_filename); node.set_Blob_1(gen_default_sdl(age.m_filename)); uint32_t ageSdlNode = v_create_node(node); if (ageSdlNode == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodePlayerInfoList); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_AgeOwnersFolder); uint32_t ageOwners = v_create_node(node); if (ageOwners == 0) return std::make_pair(0, 0); node.clear(); node.set_NodeType(DS::Vault::e_NodeAgeInfoList); node.set_CreatorUuid(age.m_ageId); node.set_CreatorIdx(ageNode); node.set_Int32_1(DS::Vault::e_ChildAgesFolder); uint32_t childAges = v_create_node(node); if (childAges == 0) return std::make_pair(0, 0); if (!v_ref_node(ageNode, s_systemNode, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageNode, chronFolder, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageNode, knownFolder, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageNode, subAgesFolder, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageNode, ageInfoNode, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageNode, devsFolder, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageInfoNode, canVisitList, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageInfoNode, ageSdlNode, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageInfoNode, ageOwners, 0)) return std::make_pair(0, 0); if (!v_ref_node(ageInfoNode, childAges, 0)) return std::make_pair(0, 0); // Register with the server database { DS::String agedesc = !age.m_description.isEmpty() ? age.m_description : !age.m_instName.isEmpty() ? age.m_instName : age.m_filename; PostgresStrings<5> parms; parms.set(0, age.m_ageId.toString()); parms.set(1, age.m_filename); parms.set(2, agedesc); parms.set(3, ageNode); parms.set(4, ageSdlNode); PGresult* result = PQexecParams(s_postgres, "INSERT INTO game.\"Servers\"" " (\"AgeUuid\", \"AgeFilename\", \"DisplayName\", \"AgeIdx\", \"SdlIdx\")" " VALUES ($1, $2, $3, $4, $5)", 5, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres INSERT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return std::make_pair(0, 0); } PQclear(result); } return std::make_tuple(ageNode, ageInfoNode); }
static uint32_t find_a_friendly_neighborhood_for_our_new_visitor(uint32_t playerInfoId) { PGresult* result = PQexec(s_postgres, "SELECT \"AgeUuid\" FROM game.\"PublicAges\"" " WHERE \"AgeFilename\" = 'Neighborhood'" " AND \"Population\" < 20 AND \"SeqNumber\" <> 0"); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return 0; } std::pair<uint32_t, uint32_t> ageNode; DS::Uuid ageId; if (PQntuples(result) != 0) { ageId = DS::Uuid(PQgetvalue(result, 0, 0)); PQclear(result); PostgresStrings<2> parms; parms.set(0, DS::Vault::e_NodeAgeInfo); parms.set(1, ageId.toString()); result = PQexecParams(s_postgres, "SELECT idx FROM vault.\"Nodes\"" " WHERE \"NodeType\"=$1 AND \"Uuid_1\"=$2", 2, 0, parms.m_values, 0, 0, 0); if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return 0; } DS_DASSERT(PQntuples(result) == 1); ageNode.second = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); } else { PQclear(result); AuthServer_AgeInfo age; age.m_ageId = gen_uuid(); age.m_filename = "Neighborhood"; age.m_instName = "Neighborhood"; age.m_userName = "******"; age.m_description = "DS Neighborhood"; age.m_seqNumber = -1; // Auto-generate ageNode = v_create_age(age, e_AgePublic); if (ageNode.second == 0) return 0; } { PostgresStrings<2> parms; parms.set(0, ageNode.second); parms.set(1, DS::Vault::e_AgeOwnersFolder); result = PQexecParams(s_postgres, "SELECT idx FROM vault.find_folder($1, $2);", 2, 0, parms.m_values, 0, 0, 0); } if (PQresultStatus(result) != PGRES_TUPLES_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return 0; } DS_DASSERT(PQntuples(result) == 1); uint32_t ownerFolder = strtoul(PQgetvalue(result, 0, 0), 0, 10); PQclear(result); if (!v_ref_node(ownerFolder, playerInfoId, 0)) return 0; { PostgresStrings<1> parms; parms.set(0, ageId.toString()); result = PQexecParams(s_postgres, "UPDATE game.\"PublicAges\"" " SET \"Population\" = \"Population\"+1" " WHERE \"AgeUuid\" = $1", 1, 0, parms.m_values, 0, 0, 0); } if (PQresultStatus(result) != PGRES_COMMAND_OK) { fprintf(stderr, "%s:%d:\n Postgres SELECT error: %s\n", __FILE__, __LINE__, PQerrorMessage(s_postgres)); PQclear(result); return 0; } PQclear(result); return ageNode.second; }