#include "stdafx.h" #include "StructureTable.h" #include "../Minecraft.World/StringHelpers.h" unordered_map StructureTable::s_structureFeatureNamesMap; unordered_map StructureTable::s_structurePieceNamesMap; unordered_map StructureTable::s_generateObjectNamesMap; unordered_map StructureTable::s_generateEntityNamesMap; unordered_map StructureTable::s_generateStructureNamesMap; const wchar_t *StructureTable::StructureFeatureElements[eMinecraftStructureFeature_Count] = { L"NOTSET", L"VillageFeature", }; const wchar_t *StructureTable::StructurePieceElements[eMinecraftStructurePiece_Count] = { L"NOTSET", L"DesertPyramidPiece", L"SimpleHouse", L"SmallTemple", L"BookHouse", L"SmallHut", L"PigHouse", L"DoubleFarmland", L"Farmland", L"Smithy", L"TwoRoomHouse", L"LightPost", L"Well", }; const wchar_t *StructureTable::GenerateObjectElements[eGenerateObject_Count] = { L"Chest", L"Dispenser", }; const wchar_t *StructureTable::GenerateEntityElements[eGenerateEntity_Count] = { L"Villager", L"Witch", }; const wchar_t *StructureTable::GenerateStructureElements[eGenerateStructure_Count] = { L"Block", L"maybeGenerateBlock", L"AirBox", L"Box", L"MaybeBox", L"UpperHalfSphere", L"FullSphere", L"AirColumnUp", L"fillColumnDown", L"fillBoxDown", L"generateAirBoxUp", L"Crops", L"CreateDoor", L"CheckBlock", }; void StructureTable::staticCtor() { for(unsigned int i = 0; i < eMinecraftStructureFeature_Count; ++i) { s_structureFeatureNamesMap.insert( unordered_map::value_type( StructureFeatureElements[i], (eMinecraftStructureFeature)i) ); } for(unsigned int i = 0; i < eMinecraftStructurePiece_Count; ++i) { s_structurePieceNamesMap.insert(unordered_map::value_type( StructurePieceElements[i], (eMinecraftStructurePiece)i) ); } for(unsigned int i = 0; i < eGenerateObject_Count; ++i) { s_generateObjectNamesMap.insert( unordered_map::value_type( GenerateObjectElements[i], (eGenerateObject)i) ); } for(unsigned int i = 0; i < eGenerateEntity_Count; ++i) { s_generateEntityNamesMap.insert( unordered_map::value_type( GenerateEntityElements[i], (eGenerateEntity)i) ); } for(unsigned int i = 0; i < eGenerateStructure_Count; ++i) { s_generateStructureNamesMap.insert(unordered_map::value_type( GenerateStructureElements[i], (eGenerateStructure)i) ); } } StructureTable::StructureTable(PBYTE pbData, DWORD dwLength) { loadStructuresFromData(pbData, dwLength); } StructureTable::StructurePiece* StructureTable::getStructurePiece(eMinecraftStructurePiece piece) { return &m_structurePieces[(int)piece]; } StructureTable::StructureFeature* StructureTable::getStructureFeature(eMinecraftStructureFeature feature) { return &m_structureFeatures[(int)feature]; } void StructureTable::loadStructuresFromData(PBYTE pbData, DWORD dwLength) { byteArray src(pbData, dwLength); ByteArrayInputStream bais(src); DataInputStream dis(&bais); int versionNumber = dis.readInt(); int featureCount = dis.readInt(); int pieceCount = dis.readInt(); for(int i = 0; i < featureCount; ++i) { StructureFeature feature; feature.name = dis.readUTF(); int optionsCount = dis.readInt(); int tilesCount = dis.readInt(); for(int j = 0; j < optionsCount; ++j) { feature.options.push_back(dis.readInt()); } for(int j = 0; j < tilesCount; ++j) { std::wstring tile = dis.readUTF(); size_t comma = tile.find(L','); if(comma != std::wstring::npos) { int k = std::stoi(tile.substr(0, comma)); int v = std::stoi(tile.substr(comma + 1)); feature.tiles[k] = v; } } auto it = s_structureFeatureNamesMap.find(feature.name); if (it != s_structureFeatureNamesMap.end()) { m_structureFeatures[(int)it->second] = feature; } } for(int i = 0; i < pieceCount; ++i) { StructurePiece structurePiece; structurePiece.name = dis.readUTF(); structurePiece.width = dis.readInt(); structurePiece.height = dis.readInt(); structurePiece.depth = dis.readInt(); int treasureCount = dis.readInt(); int structuresCount = dis.readInt(); int objectsCount = dis.readInt(); int entitiesCount = dis.readInt(); // ? structurePiece.v8 = dis.readInt(); // @3UR: some sort of count/size? int unk_count1 = dis.readInt(); int numCropTiles = dis.readInt(); // ? for(int j = 0; j < unk_count1; ++j) { structurePiece.v11.push_back(dis.readInt()); } for(int j = 0; j < numCropTiles; ++j) { structurePiece.cropTiles.push_back(dis.readInt()); } for(int j = 0; j < treasureCount; ++j) { TreasureData t; t.itemId = dis.readInt(); t.auxValue = dis.readInt(); t.minCount = dis.readInt(); t.maxCount = dis.readInt(); t.weight = dis.readInt(); structurePiece.treasure.push_back(t); } for(int j = 0; j < structuresCount; ++j) { StructureData s; std::wstring name = dis.readUTF(); auto it = s_generateStructureNamesMap.find(name); s.id = (it != s_generateStructureNamesMap.end()) ? (int)it->second : 0; s.name = name; s.tileId = dis.readInt(); s.data = dis.readInt(); s.dataType = dis.readInt(); bool hasSecondTile = dis.readBoolean(); if(hasSecondTile) { s.secondTileId = dis.readInt(); s.secondData = dis.readInt(); s.secondDataType = dis.readInt(); } else { s.secondTileId = 0; s.secondData = 0; s.secondDataType = 0; } s.x0 = dis.readInt(); s.y0 = dis.readInt(); s.z0 = dis.readInt(); bool hasBounds = dis.readBoolean(); if(hasBounds) { s.x1 = dis.readInt(); s.y1 = dis.readInt(); s.z1 = dis.readInt(); } else { s.x1 = 0; s.y1 = 0; s.z1 = 0; } // ? bool hasStartRemaps = dis.readBoolean(); if(hasStartRemaps) { s.startRemap0 = dis.readInt(); s.startRemap1 = dis.readInt(); s.startRemap2 = dis.readInt(); } else { s.startRemap0 = -1; s.startRemap1 = -1; s.startRemap2 = -1; } // ? bool hasEndRemaps = dis.readBoolean(); if(hasEndRemaps) { s.endRemap0 = dis.readInt(); s.endRemap1 = dis.readInt(); s.endRemap2 = dis.readInt(); } else { s.endRemap0 = -1; s.endRemap1 = -1; s.endRemap2 = -1; } readIntSaveData(dis, s.cropAges); readIntSaveData(dis, s.v25); readIntSaveData(dis, s.v26); readIntSaveData(dis, s.v27); structurePiece.structures.push_back(s); } for(int j = 0; j < objectsCount; ++j) { ObjectData o; std::wstring name = dis.readUTF(); auto it = s_generateObjectNamesMap.find(name); o.id = (it != s_generateObjectNamesMap.end()) ? (int)it->second : 0; o.name = name; o.x = dis.readInt(); o.y = dis.readInt(); o.z = dis.readInt(); o.minEnchantedBooks = dis.readInt(); o.maxEnchantedBooks = dis.readInt(); o.enchantedBookWeight = dis.readInt(); o.rollCount = dis.readInt(); o.canGenEnchantedBooks = dis.readBoolean(); o.rollWeight = dis.readInt(); o.dispenserDir = dis.readInt(); structurePiece.objects.push_back(o); } for(int j = 0; j < entitiesCount; ++j) { EntityData e; std::wstring name = dis.readUTF(); auto it = s_generateEntityNamesMap.find(name); e.id = (it != s_generateEntityNamesMap.end()) ? (int)it->second : 0; e.x = dis.readInt(); e.y = dis.readInt(); e.z = dis.readInt(); e.count = dis.readInt(); std::wstring professionsCsv = dis.readUTF(); size_t start = 0, end; while((end = professionsCsv.find(L',', start)) != std::wstring::npos) { e.professions.push_back(std::stoi(professionsCsv.substr(start, end - start))); start = end + 1; } if(start < professionsCsv.size()) { e.professions.push_back(std::stoi(professionsCsv.substr(start))); } structurePiece.entities.push_back(e); } setStructurePiece(structurePiece.name, structurePiece); } bais.reset(); } void StructureTable::setStructurePiece(const wstring& name, const StructurePiece& piece) { auto it = s_structurePieceNamesMap.find(name); if (it != s_structurePieceNamesMap.end()) { m_structurePieces[(int)it->second] = piece; } } void StructureTable::readIntSaveData(DataInputStream& dis, vector& container) { wstring data = dis.readUTF(); vector tokens = stringSplit(data, L','); for (size_t i = 0; i < tokens.size(); ++i) { wistringstream wiss(tokens[i]); int outVal = 0; wiss >> dec >> outVal; container.push_back(outVal); } }