EMCSBiome StringToBiome(const AString & a_BiomeString) { // If it is a number, return it: int res = atoi(a_BiomeString.c_str()); if ((res != 0) || (a_BiomeString.compare("0") == 0)) { if ((res >= biFirstBiome) && (res < biNumBiomes)) { return (EMCSBiome)res; } else if ((res >= biFirstVariantBiome) && (res < biNumVariantBiomes)) { return (EMCSBiome)res; } // It was an invalid number return biInvalidBiome; } for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++) { if (NoCaseCompare(g_BiomeMap[i].m_String, a_BiomeString) == 0) { return g_BiomeMap[i].m_Biome; } } // for i - BiomeMap[] return biInvalidBiome; }
void cRoot::LoadWorlds(void) { cIniFile IniFile("settings.ini"); IniFile.ReadFile(); // First get the default world AString DefaultWorldName = IniFile.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld( DefaultWorldName.c_str() ); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; // Then load the other worlds unsigned int KeyNum = IniFile.FindKey("Worlds"); unsigned int NumWorlds = IniFile.GetNumValues( KeyNum ); if (NumWorlds <= 0) { return; } for (unsigned int i = 0; i < NumWorlds; i++) { AString ValueName = IniFile.GetValueName(KeyNum, i ); if (ValueName.compare("World") != 0) { continue; } AString WorldName = IniFile.GetValue(KeyNum, i ); if (WorldName.empty()) { continue; } cWorld* NewWorld = new cWorld( WorldName.c_str() ); m_WorldsByName[ WorldName ] = NewWorld; } // for i - Worlds }
AStringVector cPluginManager::GetFoldersToLoad(cSettingsRepositoryInterface & a_Settings) { // Check if the Plugins section exists. if (!a_Settings.KeyExists("Plugins")) { InsertDefaultPlugins(a_Settings); } // Get the list of plugins to load: AStringVector res; auto Values = a_Settings.GetValues("Plugins"); for (auto NameValue : Values) { AString ValueName = NameValue.first; if (ValueName.compare("Plugin") == 0) { AString PluginFile = NameValue.second; if (!PluginFile.empty()) { res.push_back(PluginFile); } } } // for i - ini values return res; }
bool cPlayer::IsInGroup( const AString & a_Group ) { for( GroupList::iterator itr = m_ResolvedGroups.begin(); itr != m_ResolvedGroups.end(); ++itr ) { if( a_Group.compare( (*itr)->GetName().c_str() ) == 0 ) return true; } return false; }
void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) { LOG("-- Loading Plugins --"); m_bReloadPlugins = false; UnloadPluginsNow(); FindPlugins(); cServer::BindBuiltInConsoleCommands(); // Check if the Plugins section exists. int KeyNum = a_SettingsIni.FindKey("Plugins"); // If it does, how many plugins are there? int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); if (KeyNum == -1) { InsertDefaultPlugins(a_SettingsIni); } else if (NumPlugins > 0) { for (int i = 0; i < NumPlugins; i++) { AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); if (ValueName.compare("Plugin") == 0) { AString PluginFile = a_SettingsIni.GetValue(KeyNum, i); if (!PluginFile.empty()) { if (m_Plugins.find(PluginFile) != m_Plugins.end()) { LoadPlugin(PluginFile); } } } } } size_t NumLoadedPlugins = GetNumPlugins(); if (NumLoadedPlugins == 0) { LOG("-- No Plugins Loaded --"); } else if (NumLoadedPlugins > 1) { LOG("-- Loaded %i Plugins --", (int)NumLoadedPlugins); } else { LOG("-- Loaded 1 Plugin --"); } CallHookPluginsLoaded(); }
BLOCKTYPE BlockStringToType(const AString & a_BlockTypeString) { int res = atoi(a_BlockTypeString.c_str()); if ((res != 0) || (a_BlockTypeString.compare("0") == 0)) { // It was a valid number, return that return res; } return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString)); }
// for debugging void cMonster::SetState(const AString & a_State) { if (a_State.compare("Idle") == 0) { m_EMState = IDLE; } else if (a_State.compare("Attacking") == 0) { m_EMState = ATTACKING; } else if (a_State.compare("Chasing") == 0) { m_EMState = CHASING; } else { LOGD("cMonster::SetState(): Invalid state"); ASSERT(!"Invalid state"); } }
EMCSBiome StringToBiome(const AString & a_BiomeString) { // If it is a number, return it: int res = atoi(a_BiomeString.c_str()); if ((res != 0) || (a_BiomeString.compare("0") == 0)) { // It was a valid number return (EMCSBiome)res; } // Convert using the built-in map: static struct { EMCSBiome m_Biome; const char * m_String; } BiomeMap[] = { {biOcean, "Ocean"} , {biPlains, "Plains"}, {biDesert, "Desert"}, {biExtremeHills, "ExtremeHills"}, {biForest, "Forest"}, {biTaiga, "Taiga"}, {biSwampland, "Swampland"}, {biRiver, "River"}, {biNether, "Hell"}, {biNether, "Nether"}, {biEnd, "Sky"}, {biEnd, "End"}, {biFrozenOcean, "FrozenOcean"}, {biFrozenRiver, "FrozenRiver"}, {biIcePlains, "IcePlains"}, {biIcePlains, "Tundra"}, {biIceMountains, "IceMountains"}, {biMushroomIsland, "MushroomIsland"}, {biMushroomShore, "MushroomShore"}, {biBeach, "Beach"}, {biDesertHills, "DesertHills"}, {biForestHills, "ForestHills"}, {biTaigaHills, "TaigaHills"}, {biExtremeHillsEdge, "ExtremeHillsEdge"}, {biJungle, "Jungle"}, {biJungleHills, "JungleHills"}, } ; for (int i = 0; i < ARRAYCOUNT(BiomeMap); i++) { if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0) { return BiomeMap[i].m_Biome; } } // for i - BiomeMap[] return (EMCSBiome)-1; }
int BlockStringToType(const AString & a_BlockTypeString) { int res = atoi(a_BlockTypeString.c_str()); if ((res != 0) || (a_BlockTypeString.compare("0") == 0)) { // It was a valid number, return that return res; } if (!gsBlockIDMap.m_bHasRunInit) { gsBlockIDMap.init(); } return gsBlockIDMap.Resolve(TrimString(a_BlockTypeString)); }
void cPluginManager::ReloadPluginsNow(cIniFile & a_SettingsIni) { LOG("-- Loading Plugins --"); m_bReloadPlugins = false; UnloadPluginsNow(); FindPlugins(); cServer::BindBuiltInConsoleCommands(); unsigned int KeyNum = a_SettingsIni.FindKey("Plugins"); unsigned int NumPlugins = ((KeyNum != -1) ? (a_SettingsIni.GetNumValues(KeyNum)) : 0); if (KeyNum == -1) { InsertDefaultPlugins(a_SettingsIni); } else if (NumPlugins > 0) { for(unsigned int i = 0; i < NumPlugins; i++) { AString ValueName = a_SettingsIni.GetValueName(KeyNum, i); if (ValueName.compare("Plugin") == 0) { AString PluginFile = a_SettingsIni.GetValue(KeyNum, i); if (!PluginFile.empty()) { if (m_Plugins.find(PluginFile) != m_Plugins.end()) { LoadPlugin( PluginFile ); } } } } } if (GetNumPlugins() == 0) { LOG("-- No Plugins Loaded --"); } else if (GetNumPlugins() > 1) { LOG("-- Loaded %i Plugins --", GetNumPlugins()); } else { LOG("-- Loaded 1 Plugin --"); } }
void cRoot::LoadWorlds(cIniFile & IniFile) { // First get the default world AString DefaultWorldName = IniFile.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld(DefaultWorldName.c_str()); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; // Then load the other worlds int KeyNum = IniFile.FindKey("Worlds"); int NumWorlds = IniFile.GetNumValues(KeyNum); if (NumWorlds <= 0) { return; } bool FoundAdditionalWorlds = false; for (int i = 0; i < NumWorlds; i++) { AString ValueName = IniFile.GetValueName(KeyNum, i); if (ValueName.compare("World") != 0) { continue; } AString WorldName = IniFile.GetValue(KeyNum, i); if (WorldName.empty()) { continue; } FoundAdditionalWorlds = true; cWorld* NewWorld = new cWorld( WorldName.c_str()); m_WorldsByName[ WorldName ] = NewWorld; } // for i - Worlds if (!FoundAdditionalWorlds) { if (IniFile.GetKeyComment("Worlds", 0) != " World=secondworld") { IniFile.DeleteKeyComment("Worlds", 0); IniFile.AddKeyComment("Worlds", " World=secondworld"); } } }
void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings) { // First get the default world AString DefaultWorldName = a_Settings.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld(DefaultWorldName.c_str()); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; // Then load the other worlds auto Worlds = a_Settings.GetValues("Worlds"); if (Worlds.size() <= 0) { return; } bool FoundAdditionalWorlds = false; for (auto WorldNameValue : Worlds) { AString ValueName = WorldNameValue.first; if (ValueName.compare("World") != 0) { continue; } AString WorldName = WorldNameValue.second; if (WorldName.empty()) { continue; } FoundAdditionalWorlds = true; cWorld * NewWorld = new cWorld(WorldName.c_str()); m_WorldsByName[WorldName] = NewWorld; } // for i - Worlds if (!FoundAdditionalWorlds) { if (a_Settings.GetKeyComment("Worlds", 0) != " World=secondworld") { a_Settings.DeleteKeyComment("Worlds", 0); a_Settings.AddKeyComment("Worlds", " World=secondworld"); } } }
bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID, Json::Value & a_Properties) { LOGD("Trying to authenticate user %s", a_UserName.c_str()); // Create the GET request: AString ActualAddress = m_Address; ReplaceString(ActualAddress, "%USERNAME%", a_UserName); ReplaceString(ActualAddress, "%SERVERID%", a_ServerId); AString Request; Request += "GET " + ActualAddress + " HTTP/1.0\r\n"; Request += "Host: " + m_Server + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "\r\n"; AString Response; if (!cMojangAPI::SecureRequest(m_Server, Request, Response)) { return false; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("User %s failed to auth, bad HTTP status line received", a_UserName.c_str()); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return false; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("User %s failed to authenticate, bad HTTP response header received", a_UserName.c_str()); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return false; } Response.erase(0, idxHeadersEnd + 4); // Parse the Json response: if (Response.empty()) { return false; } Json::Value root; Json::Reader reader; if (!reader.parse(Response, root, false)) { LOGWARNING("cAuthenticator: Cannot parse received data (authentication) to JSON!"); return false; } a_UserName = root.get("name", "Unknown").asString(); a_UUID = cMojangAPI::MakeUUIDShort(root.get("id", "").asString()); a_Properties = root["properties"]; // Store the player's profile in the MojangAPI caches: cRoot::Get()->GetMojangAPI().AddPlayerProfile(a_UserName, a_UUID, a_Properties); return true; }
bool cBlockArea::LoadFromSchematicNBT(cParsedNBT & a_NBT) { int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials"); if ((TMaterials > 0) && (a_NBT.GetType(TMaterials) == TAG_String)) { AString Materials = a_NBT.GetString(TMaterials); if (Materials.compare("Alpha") != 0) { LOG("Materials tag is present and \"%s\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials.c_str()); return false; } } int TSizeX = a_NBT.FindChildByName(a_NBT.GetRoot(), "Width"); int TSizeY = a_NBT.FindChildByName(a_NBT.GetRoot(), "Height"); int TSizeZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "Length"); if ( (TSizeX < 0) || (TSizeY < 0) || (TSizeZ < 0) || (a_NBT.GetType(TSizeX) != TAG_Short) || (a_NBT.GetType(TSizeY) != TAG_Short) || (a_NBT.GetType(TSizeZ) != TAG_Short) ) { LOG("Dimensions are missing from the schematic file (%d, %d, %d), (%d, %d, %d)", TSizeX, TSizeY, TSizeZ, a_NBT.GetType(TSizeX), a_NBT.GetType(TSizeY), a_NBT.GetType(TSizeZ) ); return false; } int SizeX = a_NBT.GetShort(TSizeX); int SizeY = a_NBT.GetShort(TSizeY); int SizeZ = a_NBT.GetShort(TSizeZ); if ((SizeX < 1) || (SizeY < 1) || (SizeZ < 1)) { LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ); return false; } int TBlockTypes = a_NBT.FindChildByName(a_NBT.GetRoot(), "Blocks"); int TBlockMetas = a_NBT.FindChildByName(a_NBT.GetRoot(), "Data"); if ((TBlockTypes < 0) || (a_NBT.GetType(TBlockTypes) != TAG_ByteArray)) { LOG("BlockTypes are invalid in the schematic file: %d", TBlockTypes); return false; } bool AreMetasPresent = (TBlockMetas > 0) && (a_NBT.GetType(TBlockMetas) == TAG_ByteArray); Clear(); SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (baTypes | baMetas) : baTypes); // Copy the block types and metas: int NumBytes = m_SizeX * m_SizeY * m_SizeZ; if (a_NBT.GetDataLength(TBlockTypes) < NumBytes) { LOG("BlockTypes truncated in the schematic file (exp %d, got %d bytes). Loading partial.", NumBytes, a_NBT.GetDataLength(TBlockTypes) ); NumBytes = a_NBT.GetDataLength(TBlockTypes); } memcpy(m_BlockTypes, a_NBT.GetData(TBlockTypes), NumBytes); if (AreMetasPresent) { int NumBytes = m_SizeX * m_SizeY * m_SizeZ; if (a_NBT.GetDataLength(TBlockMetas) < NumBytes) { LOG("BlockMetas truncated in the schematic file (exp %d, got %d bytes). Loading partial.", NumBytes, a_NBT.GetDataLength(TBlockMetas) ); NumBytes = a_NBT.GetDataLength(TBlockMetas); } memcpy(m_BlockMetas, a_NBT.GetData(TBlockMetas), NumBytes); } return true; }
void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile) { if (a_IsNewIniFile) { a_Settings.AddValue("Worlds", "DefaultWorld", "world"); a_Settings.AddValue("Worlds", "World", "world_nether"); a_Settings.AddValue("Worlds", "World", "world_end"); m_pDefaultWorld = new cWorld("world"); m_WorldsByName["world"] = m_pDefaultWorld; m_WorldsByName["world_nether"] = new cWorld("world_nether", dimNether, "world"); m_WorldsByName["world_end"] = new cWorld("world_end", dimEnd, "world"); return; } // First get the default world AString DefaultWorldName = a_Settings.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld(DefaultWorldName.c_str()); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; auto Worlds = a_Settings.GetValues("Worlds"); // Then load the other worlds if (Worlds.size() <= 0) { return; } /* Here are the world creation rules. Note that these only apply for a world which is in settings.ini but has no world.ini file. If an ini file is present, it overrides the world linkages and the dimension type in cWorld::start() The creation rules are as follows: - If a world exists in settings.ini but has no world.ini, then: - If the world name is x_nether, create a world.ini with the dimension type "nether". - If a world called x exists, set it as x_nether's overworld. - Otherwise set the default world as x_nether's overworld. - If the world name is x_end, create a world.ini with the dimension type "end". - If a world called x exists, set it as x_end's overworld. - Otherwise set the default world as x_end's overworld. - If the world name is x (and doesn't end with _end or _nether) - Create a world.ini with a dimension type of "overworld". - If a world called x_nether exists, set it as x's nether world. - Otherwise set x's nether world to blank.h - If a world called x_end exists, set it as x's end world. - Otherwise set x's nether world to blank. */ bool FoundAdditionalWorlds = false; for (auto WorldNameValue : Worlds) { AString ValueName = WorldNameValue.first; if (ValueName.compare("World") != 0) { continue; } AString WorldName = WorldNameValue.second; if (WorldName.empty()) { continue; } FoundAdditionalWorlds = true; cWorld * NewWorld; AString LowercaseName = StrToLower(WorldName); AString NetherAppend="_nether"; AString EndAppend="_end"; // if the world is called x_nether if ((LowercaseName.size() > NetherAppend.size()) && (LowercaseName.substr(LowercaseName.size() - NetherAppend.size()) == NetherAppend)) { // The world is called x_nether, see if a world called x exists. If yes, choose it as the linked world, // otherwise, choose the default world as the linked world. // As before, any ini settings will completely override this if an ini is already present. AString LinkTo = WorldName.substr(0, WorldName.size() - NetherAppend.size()); if (GetWorld(LinkTo) == nullptr) { LinkTo = DefaultWorldName; } NewWorld = new cWorld(WorldName.c_str(), dimNether, LinkTo); } // if the world is called x_end else if ((LowercaseName.size() > EndAppend.size()) && (LowercaseName.substr(LowercaseName.size() - EndAppend.size()) == EndAppend)) { // The world is called x_end, see if a world called x exists. If yes, choose it as the linked world, // otherwise, choose the default world as the linked world. // As before, any ini settings will completely override this if an ini is already present. AString LinkTo = WorldName.substr(0, WorldName.size() - EndAppend.size()); if (GetWorld(LinkTo) == nullptr) { LinkTo = DefaultWorldName; } NewWorld = new cWorld(WorldName.c_str(), dimEnd, LinkTo); } else { NewWorld = new cWorld(WorldName.c_str()); } m_WorldsByName[WorldName] = NewWorld; } // for i - Worlds if (!FoundAdditionalWorlds) { if (a_Settings.GetKeyComment("Worlds", 0) != " World=secondworld") { a_Settings.DeleteKeyComment("Worlds", 0); a_Settings.AddKeyComment("Worlds", " World=secondworld"); } } }
// Returns 0 if true, < 0 if lhs is less than rhs, and > 0 if lhs is greater than rhs static ptrdiff_t comparison(const AString & lhs, const AString & rhs) {return lhs.compare(rhs, AStrCase_ignore);}
// Returns true if elements are equal static bool equals(const AString & lhs, const AString & rhs) {return (lhs.compare(rhs, AStrCase_ignore) == AEquate_equal);}
void cMojangAPI::CacheUUIDToProfile(const AString & a_UUID) { ASSERT(a_UUID.size() == 32); // Check if already present: { if (m_UUIDToProfile.find(a_UUID) != m_UUIDToProfile.end()) { return; } } // Create the request address: AString Address = m_UUIDToProfileAddress; ReplaceString(Address, "%UUID%", a_UUID); // Create the HTTP request: AString Request; Request += "GET " + Address + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_UUIDToProfileServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Length: 0\r\n"; Request += "\r\n"; // Get the response from the server: AString Response; if (!SecureRequest(m_UUIDToProfileServer, Request, Response)) { return; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; Json::Value root; if (!reader.parse(Response, root, false) || !root.isObject()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return; } /* Example response: { "id": "b1caf24202a841a78055a079c460eee7", "name": "xoft", "properties": [ { "name": "textures", "value": "eyJ0aW1lc3RhbXAiOjE0MDcwNzAzMjEyNzEsInByb2ZpbGVJZCI6ImIxY2FmMjQyMDJhODQxYTc4MDU1YTA3OWM0NjBlZWU3IiwicHJvZmlsZU5hbWUiOiJ4b2Z0IiwiaXNQdWJsaWMiOnRydWUsInRleHR1cmVzIjp7IlNLSU4iOnsidXJsIjoiaHR0cDovL3RleHR1cmVzLm1pbmVjcmFmdC5uZXQvdGV4dHVyZS9iNzc5YmFiZjVhNTg3Zjk0OGFkNjc0N2VhOTEyNzU0MjliNjg4Mjk1YWUzYzA3YmQwZTJmNWJmNGQwNTIifX19", "signature": "XCty+jGEF39hEPrPhYNnCX087kPaoCjYruzYI/DS4nkL5hbjnkSM5Rh15hnUyv/FHhC8OF5rif3D1tQjtMI19KSVaXoUFXpbJM8/+PB8GDgEbX8Fc3u9nYkzOcM/xfxdYsFAdFhLQMkvase/BZLSuPhdy9DdI+TCrO7xuSTZfYmmwVuWo3w5gCY+mSIAnqltnOzaOOTcly75xvO0WYpVk7nJdnR2tvSi0wfrQPDrIg/uzhX7p0SnDqijmBU4QaNez/TNKiFxy69dAzt0RSotlQzqkDbyVKhhv9a4eY8h3pXi4UMftKEj4FAKczxLImkukJXuOn5NN15/Q+le0rJVBC60/xjKIVzltEsMN6qjWD0lQjey7WEL+4pGhCVuWY5KzuZjFvgqszuJTFz7lo+bcHiceldJtea8/fa02eTRObZvdLxbWC9ZfFY0IhpOVKfcLdno/ddDMNMQMi5kMrJ8MZZ/PcW1w5n7MMGWPGCla1kOaC55AL0QYSMGRVEZqgU9wXI5M7sHGZKGM4mWxkbEJYBkpI/p3GyxWgV6v33ZWlsz65TqlNrR1gCLaoFCm7Sif8NqPBZUAONHYon0roXhin/DyEanS93WV6i6FC1Wisscjq2AcvnOlgTo/5nN/1QsMbjNumuMGo37sqjRqlXoPb8zEUbAhhztYuJjEfQ2Rd8=" } ] } */ // Store the returned result into caches: AString PlayerName = root.get("name", "").asString(); if (PlayerName.empty()) { // No valid playername, bail out return; } Json::Value Properties = root.get("properties", ""); Int64 Now = time(NULL); { cCSLock Lock(m_CSUUIDToProfile); m_UUIDToProfile[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { cCSLock Lock(m_CSUUIDToName); m_UUIDToName[a_UUID] = sProfile(PlayerName, a_UUID, Properties, Now); } { cCSLock Lock(m_CSNameToUUID); m_NameToUUID[StrToLower(PlayerName)] = sProfile(PlayerName, a_UUID, Properties, Now); } }
void cMojangAPI::CacheNamesToUUIDs(const AStringVector & a_PlayerNames) { // Create a list of names to query, by removing those that are already cached: AStringVector NamesToQuery; NamesToQuery.reserve(a_PlayerNames.size()); { cCSLock Lock(m_CSNameToUUID); for (AStringVector::const_iterator itr = a_PlayerNames.begin(), end = a_PlayerNames.end(); itr != end; ++itr) { if (m_NameToUUID.find(*itr) == m_NameToUUID.end()) { NamesToQuery.push_back(*itr); } } // for itr - a_PlayerNames[] } // Lock(m_CSNameToUUID) while (!NamesToQuery.empty()) { // Create the request body - a JSON containing up to MAX_PER_QUERY playernames: Json::Value root; int Count = 0; AStringVector::iterator itr = NamesToQuery.begin(), end = NamesToQuery.end(); for (; (itr != end) && (Count < MAX_PER_QUERY); ++itr, ++Count) { Json::Value req(*itr); root.append(req); } // for itr - a_PlayerNames[] NamesToQuery.erase(NamesToQuery.begin(), itr); Json::FastWriter Writer; AString RequestBody = Writer.write(root); // Create the HTTP request: AString Request; Request += "POST " + m_NameToUUIDAddress + " HTTP/1.0\r\n"; // We need to use HTTP 1.0 because we don't handle Chunked transfer encoding Request += "Host: " + m_NameToUUIDServer + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "Content-Type: application/json\r\n"; Request += Printf("Content-Length: %u\r\n", (unsigned)RequestBody.length()); Request += "\r\n"; Request += RequestBody; // Get the response from the server: AString Response; if (!SecureRequest(m_NameToUUIDServer, Request, Response)) { continue; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("%s failed: bad HTTP status line received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("%s failed: bad HTTP response header received", __FUNCTION__); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } Response.erase(0, idxHeadersEnd + 4); // Parse the returned string into Json: Json::Reader reader; if (!reader.parse(Response, root, false) || !root.isArray()) { LOGWARNING("%s failed: Cannot parse received data (NameToUUID) to JSON!", __FUNCTION__); LOGD("Response body:\n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); continue; } // Store the returned results into cache: size_t JsonCount = root.size(); Int64 Now = time(NULL); { cCSLock Lock(m_CSNameToUUID); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_NameToUUID[StrToLower(JsonName)] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } // cCSLock (m_CSNameToUUID) // Also cache the UUIDToName: { cCSLock Lock(m_CSUUIDToName); for (size_t idx = 0; idx < JsonCount; ++idx) { Json::Value & Val = root[idx]; AString JsonName = Val.get("name", "").asString(); AString JsonUUID = MakeUUIDShort(Val.get("id", "").asString()); if (JsonUUID.empty()) { continue; } m_UUIDToName[JsonUUID] = sProfile(JsonName, JsonUUID, "", "", Now); } // for idx - root[] } } // while (!NamesToQuery.empty()) }
static inline bool matches(const char *find, const AString &key) { return key.compare(find) == 0; }
bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID, Json::Value & a_Properties) { LOGD("Trying to authenticate user %s", a_UserName.c_str()); // Create the GET request: AString ActualAddress = m_Address; ReplaceString(ActualAddress, "%USERNAME%", a_UserName); ReplaceString(ActualAddress, "%SERVERID%", a_ServerId); AString Request; Request += "GET " + ActualAddress + " HTTP/1.0\r\n"; Request += "Host: " + m_Server + "\r\n"; Request += "User-Agent: MCServer\r\n"; Request += "Connection: close\r\n"; Request += "\r\n"; AString Response; if (!SecureGetFromAddress(StarfieldCACert(), m_Server, Request, Response)) { return false; } // Check the HTTP status line: const AString Prefix("HTTP/1.1 200 OK"); AString HexDump; if (Response.compare(0, Prefix.size(), Prefix)) { LOGINFO("User %s failed to auth, bad HTTP status line received", a_UserName.c_str()); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return false; } // Erase the HTTP headers from the response: size_t idxHeadersEnd = Response.find("\r\n\r\n"); if (idxHeadersEnd == AString::npos) { LOGINFO("User %s failed to authenticate, bad HTTP response header received", a_UserName.c_str()); LOGD("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str()); return false; } Response.erase(0, idxHeadersEnd + 4); // Parse the Json response: if (Response.empty()) { return false; } Json::Value root; Json::Reader reader; if (!reader.parse(Response, root, false)) { LOGWARNING("cAuthenticator: Cannot parse received data (authentication) to JSON!"); return false; } a_UserName = root.get("name", "Unknown").asString(); a_UUID = root.get("id", "").asString(); a_Properties = root["properties"]; // If the UUID doesn't contain the hashes, insert them at the proper places: if (a_UUID.size() == 32) { a_UUID.insert(8, "-"); a_UUID.insert(13, "-"); a_UUID.insert(18, "-"); a_UUID.insert(23, "-"); } return true; }
void cRoot::LoadWorlds(cSettingsRepositoryInterface & a_Settings, bool a_IsNewIniFile) { if (a_IsNewIniFile) { a_Settings.AddValue("Worlds", "DefaultWorld", "world"); a_Settings.AddValue("Worlds", "World", "world_nether"); a_Settings.AddValue("Worlds", "World", "world_end"); m_pDefaultWorld = new cWorld("world"); m_WorldsByName["world"] = m_pDefaultWorld; m_WorldsByName["world_nether"] = new cWorld("world_nether", dimNether, "world"); m_WorldsByName["world_end"] = new cWorld("world_end", dimEnd, "world"); return; } // First get the default world AString DefaultWorldName = a_Settings.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld(DefaultWorldName.c_str()); m_WorldsByName[ DefaultWorldName ] = m_pDefaultWorld; auto Worlds = a_Settings.GetValues("Worlds"); // Fix servers that have default world configs created prior to #2815. See #2810. // This can probably be removed several years after 2016 // We start by inspecting the world linkage and determining if it's the default one if ((DefaultWorldName == "world") && (Worlds.size() == 1)) { auto DefaultWorldIniFile= cpp14::make_unique<cIniFile>(); if (DefaultWorldIniFile->ReadFile("world/world.ini")) { AString NetherName = DefaultWorldIniFile->GetValue("LinkedWorlds", "NetherWorldName", ""); AString EndName = DefaultWorldIniFile->GetValue("LinkedWorlds", "EndWorldName", ""); if ((NetherName.compare("world_nether") == 0) && (EndName.compare("world_end") == 0)) { // This is a default world linkage config, see if the nether and end are in settings.ini // If both of them are not in settings.ini, then this is a pre-#2815 default config // so we add them to settings.ini // Note that if only one of them is not in settings.ini, it's nondefault and we don't touch it bool NetherInSettings = false; bool EndInSettings = false; for (auto WorldNameValue : Worlds) { AString ValueName = WorldNameValue.first; if (ValueName.compare("World") != 0) { continue; } AString WorldName = WorldNameValue.second; if (WorldName.compare("world_nether") == 0) { NetherInSettings = true; } else if (WorldName.compare("world_end") == 0) { EndInSettings = true; } } if ((!NetherInSettings) && (!EndInSettings)) { a_Settings.AddValue("Worlds", "World", "world_nether"); a_Settings.AddValue("Worlds", "World", "world_end"); Worlds = a_Settings.GetValues("Worlds"); // Refresh the Worlds list so that the rest of the function works as usual LOG("The server detected an old default config with bad world linkages. This has been autofixed by adding \"world_nether\" and \"world_end\" to settings.ini"); } } } } // Then load the other worlds if (Worlds.size() <= 0) { return; } /* Here are the world creation rules. Note that these only apply for a world which is in settings.ini but has no world.ini file. If an ini file is present, it overrides the world linkages and the dimension type in cWorld::start() The creation rules are as follows: - If a world exists in settings.ini but has no world.ini, then: - If the world name is x_nether, create a world.ini with the dimension type "nether". - If a world called x exists, set it as x_nether's overworld. - Otherwise set the default world as x_nether's overworld. - If the world name is x_end, create a world.ini with the dimension type "end". - If a world called x exists, set it as x_end's overworld. - Otherwise set the default world as x_end's overworld. - If the world name is x (and doesn't end with _end or _nether) - Create a world.ini with a dimension type of "overworld". - If a world called x_nether exists, set it as x's nether world. - Otherwise set x's nether world to blank.h - If a world called x_end exists, set it as x's end world. - Otherwise set x's nether world to blank. */ bool FoundAdditionalWorlds = false; for (auto WorldNameValue : Worlds) { AString ValueName = WorldNameValue.first; if (ValueName.compare("World") != 0) { continue; } AString WorldName = WorldNameValue.second; if (WorldName.empty()) { continue; } FoundAdditionalWorlds = true; cWorld * NewWorld; AString LowercaseName = StrToLower(WorldName); AString NetherAppend="_nether"; AString EndAppend="_end"; // if the world is called x_nether if ((LowercaseName.size() > NetherAppend.size()) && (LowercaseName.substr(LowercaseName.size() - NetherAppend.size()) == NetherAppend)) { // The world is called x_nether, see if a world called x exists. If yes, choose it as the linked world, // otherwise, choose the default world as the linked world. // As before, any ini settings will completely override this if an ini is already present. AString LinkTo = WorldName.substr(0, WorldName.size() - NetherAppend.size()); if (GetWorld(LinkTo) == nullptr) { LinkTo = DefaultWorldName; } NewWorld = new cWorld(WorldName.c_str(), dimNether, LinkTo); } // if the world is called x_end else if ((LowercaseName.size() > EndAppend.size()) && (LowercaseName.substr(LowercaseName.size() - EndAppend.size()) == EndAppend)) { // The world is called x_end, see if a world called x exists. If yes, choose it as the linked world, // otherwise, choose the default world as the linked world. // As before, any ini settings will completely override this if an ini is already present. AString LinkTo = WorldName.substr(0, WorldName.size() - EndAppend.size()); if (GetWorld(LinkTo) == nullptr) { LinkTo = DefaultWorldName; } NewWorld = new cWorld(WorldName.c_str(), dimEnd, LinkTo); } else { NewWorld = new cWorld(WorldName.c_str()); } m_WorldsByName[WorldName] = NewWorld; } // for i - Worlds if (!FoundAdditionalWorlds) { if (a_Settings.GetKeyComment("Worlds", 0) != " World=secondworld") { a_Settings.DeleteKeyComment("Worlds", 0); a_Settings.AddKeyComment("Worlds", " World=secondworld"); } } }
bool cSchematicFileSerializer::LoadFromSchematicNBT(cBlockArea & a_BlockArea, cParsedNBT & a_NBT) { int TMaterials = a_NBT.FindChildByName(a_NBT.GetRoot(), "Materials"); if ((TMaterials > 0) && (a_NBT.GetType(TMaterials) == TAG_String)) { AString Materials = a_NBT.GetString(TMaterials); if (Materials.compare("Alpha") != 0) { LOG("Materials tag is present and \"%s\" instead of \"Alpha\". Possibly a wrong-format schematic file.", Materials.c_str()); return false; } } int TSizeX = a_NBT.FindChildByName(a_NBT.GetRoot(), "Width"); int TSizeY = a_NBT.FindChildByName(a_NBT.GetRoot(), "Height"); int TSizeZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "Length"); if ( (TSizeX < 0) || (TSizeY < 0) || (TSizeZ < 0) || (a_NBT.GetType(TSizeX) != TAG_Short) || (a_NBT.GetType(TSizeY) != TAG_Short) || (a_NBT.GetType(TSizeZ) != TAG_Short) ) { LOG("Dimensions are missing from the schematic file (%d, %d, %d), (%d, %d, %d)", TSizeX, TSizeY, TSizeZ, (TSizeX >= 0) ? a_NBT.GetType(TSizeX) : -1, (TSizeY >= 0) ? a_NBT.GetType(TSizeY) : -1, (TSizeZ >= 0) ? a_NBT.GetType(TSizeZ) : -1 ); return false; } int SizeX = a_NBT.GetShort(TSizeX); int SizeY = a_NBT.GetShort(TSizeY); int SizeZ = a_NBT.GetShort(TSizeZ); if ((SizeX < 1) || (SizeX > 65535) || (SizeY < 1) || (SizeY > cChunkDef::Height) || (SizeZ < 1) || (SizeZ > 65535)) { LOG("Dimensions are invalid in the schematic file: %d, %d, %d", SizeX, SizeY, SizeZ); return false; } int TBlockTypes = a_NBT.FindChildByName(a_NBT.GetRoot(), "Blocks"); int TBlockMetas = a_NBT.FindChildByName(a_NBT.GetRoot(), "Data"); if ((TBlockTypes < 0) || (a_NBT.GetType(TBlockTypes) != TAG_ByteArray)) { LOG("BlockTypes are invalid in the schematic file: %d", TBlockTypes); return false; } bool AreMetasPresent = (TBlockMetas > 0) && (a_NBT.GetType(TBlockMetas) == TAG_ByteArray); a_BlockArea.Clear(); a_BlockArea.SetSize(SizeX, SizeY, SizeZ, AreMetasPresent ? (cBlockArea::baTypes | cBlockArea::baMetas) : cBlockArea::baTypes); int TOffsetX = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetX"); int TOffsetY = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetY"); int TOffsetZ = a_NBT.FindChildByName(a_NBT.GetRoot(), "WEOffsetZ"); if ( (TOffsetX < 0) || (TOffsetY < 0) || (TOffsetZ < 0) || (a_NBT.GetType(TOffsetX) != TAG_Int) || (a_NBT.GetType(TOffsetY) != TAG_Int) || (a_NBT.GetType(TOffsetZ) != TAG_Int) ) { // Not every schematic file has an offset, so we shoudn't give a warn message. a_BlockArea.SetWEOffset(0, 0, 0); } else { a_BlockArea.SetWEOffset(a_NBT.GetInt(TOffsetX), a_NBT.GetInt(TOffsetY), a_NBT.GetInt(TOffsetZ)); } // Copy the block types and metas: size_t NumTypeBytes = a_BlockArea.GetBlockCount(); if (a_NBT.GetDataLength(TBlockTypes) < NumTypeBytes) { LOG("BlockTypes truncated in the schematic file (exp %u, got %u bytes). Loading partial.", static_cast<unsigned>(NumTypeBytes), static_cast<unsigned>(a_NBT.GetDataLength(TBlockTypes)) ); NumTypeBytes = a_NBT.GetDataLength(TBlockTypes); } memcpy(a_BlockArea.GetBlockTypes(), a_NBT.GetData(TBlockTypes), NumTypeBytes); if (AreMetasPresent) { size_t NumMetaBytes = a_BlockArea.GetBlockCount(); if (a_NBT.GetDataLength(TBlockMetas) < NumMetaBytes) { LOG("BlockMetas truncated in the schematic file (exp %u, got %u bytes). Loading partial.", static_cast<unsigned>(NumMetaBytes), static_cast<unsigned>(a_NBT.GetDataLength(TBlockMetas)) ); NumMetaBytes = a_NBT.GetDataLength(TBlockMetas); } memcpy(a_BlockArea.GetBlockMetas(), a_NBT.GetData(TBlockMetas), NumMetaBytes); } return true; }