diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..4a24aec43 --- /dev/null +++ b/.clang-format @@ -0,0 +1,46 @@ +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: BlockIndent +AlignArrayOfStructures: Left +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AlignConsecutiveAssignments: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: true + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowAllArgumentsOnNextLine: false +AlignOperands: AlignAfterOperator +AlignConsecutiveBitFields: + Enabled: true + AcrossEmptyLines: false + AcrossComments: false +AllowShortLambdasOnASingleLine: All +AllowShortBlocksOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: AllIfsAndElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakTemplateDeclarations: 'Yes' +BinPackArguments: false +BinPackParameters: false +BreakBeforeBraces: Custom +BreakBeforeBinaryOperators: NonAssignment +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +ConstructorInitializerIndentWidth: 0 +IndentWidth: 4 +Language: Cpp +MaxEmptyLinesToKeep: 2 +PackConstructorInitializers: CurrentLine +PointerAlignment: Left +TabWidth: 4 +UseTab: Never +SortIncludes: CaseSensitive diff --git a/.clangd b/.clangd new file mode 100644 index 000000000..f19b895c8 --- /dev/null +++ b/.clangd @@ -0,0 +1,18 @@ +Diagnostics: + UnusedIncludes: Strict + MissingIncludes: Strict + Suppress: + - "-Wmicrosoft-enum-forward-reference" + - "-Wc++11-narrowing" + - "-Wc++2b-extensions" + - "-Wmicrosoft-cast" +CompileFlags: + Add: + - "-ferror-limit=0" + - '-D__FUNCTION__="dummy"' + - '-D__clangd__' + - "-Yusrc/ll/Global.h" + - "-FIsrc/ll/Global.h" # clangd bug can't find pch file + Remove: + - "/YuGlobal.h" + - "/FIGlobal.h" diff --git a/src/DataExtractor.cpp b/src/DataExtractor.cpp index 135398432..78eb0470a 100644 --- a/src/DataExtractor.cpp +++ b/src/DataExtractor.cpp @@ -3,990 +3,900 @@ using json = nlohmann::json; using namespace std; -static Minecraft* mc = nullptr; -static Dimension* overworld = nullptr; -static MinecraftCommands* commands = nullptr; -static unsigned int blockStateCounter = 0; -static AABB ZERO_AABB = AABB(Vec3(0, 0, 0), Vec3(0, 0, 0)); - -#pragma region HOOK -LL_AUTO_TYPED_INSTANCE_HOOK( - PlayerChatEventHook, - ll::memory::HookPriority::Normal, - ServerNetworkHandler, - "?handle@ServerNetworkHandler@@UEAAXAEBVNetworkIdentifier@@AEBVTextPacket@@@Z", - void, - void* networkIdentifier,//通过空指针的魔法,不用声明类型就能调用 - void* textPk +static Minecraft* mc = nullptr; +static Dimension* overworld = nullptr; +static MinecraftCommands* commands = nullptr; +static unsigned int blockStateCounter = 0; +static AABB ZERO_AABB = AABB(Vec3(0, 0, 0), Vec3(0, 0, 0)); + +#pragma region HOOK +ll::Logger hookLogger("DataExtractor-Hook"); + +LL_AUTO_TYPE_INSTANCE_HOOK( + PlayerChatEventHook, + ll::memory::HookPriority::Normal, + ServerNetworkHandler, + "?handle@ServerNetworkHandler@@" + "UEAAXAEBVNetworkIdentifier@@AEBVTextPacket@@@Z", + void, + void* networkIdentifier, + void* textPk ) { - std::string originMessage = ll::memory::dAccess(textPk, 88);//通过LL提供的memory库直接基于偏移量动态访问这个地址所在的内容 - origin(networkIdentifier, textPk); - if (originMessage == "ext") { - extractData(); - } - return; + std::string originMessage = ll::memory::dAccess( + textPk, + 88 + ); // 通过LL提供的memory库直接基于偏移量动态访问这个地址所在的内容 + origin(networkIdentifier, textPk); + if (originMessage == "ext") { + extractData(); + } } // Dimension -LL_AUTO_TYPED_INSTANCE_HOOK( - DimensionService, - ll::memory::HookPriority::Normal, - Dimension, - "?init@Dimension@@UEAAXXZ", - void*, - Dimension* a1 +LL_AUTO_TYPE_INSTANCE_HOOK( + DimensionService, + ll::memory::HookPriority::Normal, + Dimension, + "?init@Dimension@@UEAAXAEBVStructureSetRegistry@worldgen@br@@@Z", + void*, + Dimension* a1 ) { - if (a1->getHeight() > 256) { - std::cout << "INJECT DIMENSION INSTANCE" << std::endl; - overworld = a1; - } - return origin(a1); -} - -//Recipe packet -LL_AUTO_TYPED_INSTANCE_HOOK( - CraftingDataPacketHook, - ll::memory::HookPriority::Normal, - CraftingDataPacket, - "?write@CraftingDataPacket@@UEBAXAEAVBinaryStream@@@Z", - void, - BinaryStream& stream + if (a1->getHeight() > 256) { + hookLogger.info("INJECT DIMENSION INSTANCE"); + overworld = a1; + } + return origin(a1); +} + +// Recipe packet +LL_AUTO_TYPE_INSTANCE_HOOK( + CraftingDataPacketHook, + ll::memory::HookPriority::Normal, + CraftingDataPacket, + "?write@CraftingDataPacket@@UEBAXAEAVBinaryStream@@@Z", + void, + BinaryStream& stream +) { + origin(stream); + const std::string& data = stream.getAndReleaseData(); + std::string datacopy = data; + stream.writeString(data, nullptr, nullptr); + auto out = ofstream("data/crafting_data_packet.bin", ofstream::out | ofstream::binary | ofstream::trunc); + out << datacopy; + out.close(); + hookLogger.info("create crafting_data_packet.bin success!"); +} + +LL_AUTO_TYPE_INSTANCE_HOOK( + AvailableCommandsPacketHook, + ll::memory::HookPriority::Normal, + AvailableCommandsPacket, + "?write@AvailableCommandsPacket@@UEBAXAEAVBinaryStream@@@Z", + void, + BinaryStream& stream ) { - origin(stream); - const std::string& data = stream.getAndReleaseData(); - std::string datacopy = data; - stream.writeString(data, nullptr, nullptr); - auto out = ofstream("data/crafting_data_packet.bin", ofstream::out | ofstream::binary | ofstream::trunc); - out << datacopy; - out.close(); - Logger logger; - logger.info("create crafting_data_packet.bin success!"); + origin(stream); + const std::string& data = stream.getAndReleaseData(); + const std::string datacopy = data; + stream.writeString(data, nullptr, nullptr); + auto out = std::ofstream( + "data/available_commands_packet.bin", + std::ofstream::out | std::ofstream::binary | std::ofstream::trunc + ); + out << datacopy; + out.close(); + hookLogger.info("Create available_commands_packet.bin success!"); } // Minecraft -LL_AUTO_TYPED_INSTANCE_HOOK( - MinecraftHook, - HookPriority::Normal, - Minecraft, - "?initAsDedicatedServer@Minecraft@@QEAAXXZ", - void +LL_AUTO_TYPE_INSTANCE_HOOK( + MinecraftHook, + HookPriority::Normal, + Minecraft, + "?initAsDedicatedServer@Minecraft@@QEAAXXZ", + void ) { - mc = this; - origin(); - std::cout << "INJECT MINECRAFT INSTANCE" << std::endl; + mc = this; + origin(); + hookLogger.info("INJECT MINECRAFT INSTANCE"); } // MinecraftCommands -LL_AUTO_TYPED_INSTANCE_HOOK( - MinecraftCommandsHook, - HookPriority::Normal, - MinecraftCommands, - "?initCoreEnums@MinecraftCommands@@QEAAXVItemRegistryRef@@AEBVIWorldRegistriesProvider@@AEBVActorFactory@" - "@AEBVExperiments@@AEBVBaseGameVersion@@@Z", - void, - void* a2, - int64 a3, - int64 a4, - void* a5, - void* a6 +LL_AUTO_TYPE_INSTANCE_HOOK( + MinecraftCommandsHook, + HookPriority::Normal, + MinecraftCommands, + "?initCoreEnums@MinecraftCommands@@QEAAXVItemRegistryRef@@" + "AEBVIWorldRegistriesProvider@@AEBVActorFactory@" + "@AEBVExperiments@@AEBVBaseGameVersion@@@Z", + void, + void* a2, + int64 a3, + int64 a4, + void* a5, + void* a6 ) { - commands = this; - origin(a2, a3, a4, a5, a6); - std::cout << "INJECT MINECRAFTCOMMANDS INSTANCE" << std::endl; + commands = this; + origin(a2, a3, a4, a5, a6); + hookLogger.info("INJECT MINECRAFTCOMMANDS INSTANCE"); } + +// MinecraftCommands +LL_AUTO_TYPE_INSTANCE_HOOK(BlockHOOK, HookPriority::Normal, Block, "__gen_??1Block@@UEAA@XZ" void) { origin(); } + #pragma endregion HOOK #pragma region TOOL_FUNCTION -static bool folderExists(std::string folderName) { - struct stat info {}; - if (stat(folderName.c_str(), &info) != 0) { - return false; - } - else if (info.st_mode & S_IFDIR) { - return true; - } - else { - return false; - } -} - -static void createFolder(std::string folderName) { - Logger logger; - int result = _mkdir(folderName.c_str()); - if (result != 0) { - logger.error("Failed to create folder."); - } - else { - logger.info("Folder " + string(folderName) + " created successfully."); - } -} - -static void saveFile(string const& name, vector& blocks) { - sort(blocks.begin(), blocks.end(), [](string const& a, string const& b) { return a < b; }); - auto out = ofstream("block_categories/" + name + ".txt", ofstream::out | ofstream::trunc); - for (string& b : blocks) { - out << b << endl; - } - out.close(); -} - -static bool gzip_compress(const std::string& original_str, std::string& str) { - z_stream d_stream = { 0 }; - if (Z_OK != deflateInit2(&d_stream, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 9, Z_DEFAULT_STRATEGY)) { - return false; - } - unsigned long len = compressBound(original_str.size()); - auto* buf = (unsigned char*)malloc(len); - if (!buf) { - return false; - } - d_stream.next_in = (unsigned char*)(original_str.c_str()); - d_stream.avail_in = original_str.size(); - d_stream.next_out = buf; - d_stream.avail_out = len; - deflate(&d_stream, Z_SYNC_FLUSH); - deflateEnd(&d_stream); - str.assign((char*)buf, d_stream.total_out); - free(buf); - return true; -} - -static void writeNBT(const string& fileName, CompoundTag* tag) { - void* vtbl; - auto tmp = BigEndianStringByteOutput(); - vtbl = *(void**)&tmp; - string result = ""; - void* iDataOutput[2] = { vtbl, &result }; - NbtIo::write(tag, (IDataOutput&)iDataOutput); - string v; - gzip_compress(result, v); - auto out = ofstream(fileName, ofstream::out | ofstream::binary | ofstream::trunc); - out << v; - out.close(); -} - -static void writeJSON(const string& fileName, const nlohmann::json& json) { - auto out = ofstream(fileName, ofstream::out | ofstream::trunc); - out << json.dump(4); - out.close(); -} - -static void writeJSON(const string& fileName, const Json::Value& json) { - auto out = ofstream(fileName, ofstream::out | ofstream::trunc); - out << json.toStyledString(); - out.close(); -} - -static std::unique_ptr createCompound() { - return std::make_unique(); -} - -static std::unique_ptr createListTag() { - return std::make_unique(); -} - -static std::string aabbToStr(const AABB& aabb) { - stringstream aabbStr; - aabbStr << aabb.min.x << "," << aabb.min.y << "," << aabb.min.z << "," << aabb.max.x << "," << aabb.max.y << "," << aabb.max.z; - return aabbStr.str(); +inline bool isValidPtr(void* p) { return (p >= (void*)0x10000ull) && (p < (void*)0x000F000000000000ull); } + +std::vector>> dumpVtable(void* obj) { + auto vtab = *(uintptr_t**)obj; + int count = 0; + std::vector>> res; + for (;; count++) { + if (isValidPtr((void*)vtab[count])) { + size_t* address = 0; + auto result = pl::symbol_provider::pl_lookup_symbol((void*)vtab[count], address); + std::string str = *result; + if (*address != 0) { + res.push_back({(void*)vtab[count], str}); + } + } else { + break; + } + } + return res; +} + + +bool folderExists(const std::string& folderName) { + struct stat info {}; + if (stat(folderName.c_str(), &info) != 0) { + return false; + } + return info.st_mode & S_IFDIR; +} + +void createFolder(const ll::Logger& logger, const std::string& folderName) { + if (const int result = _mkdir(folderName.c_str()); result != 0) { + logger.error("Failed to create folder."); + } else { + logger.info("Folder " + std::string(folderName) + " created successfully."); + } +} + +bool gzip_compress(const std::string& original_str, std::string& str) { + z_stream d_stream = {nullptr}; + if (Z_OK != deflateInit2(&d_stream, Z_BEST_COMPRESSION, Z_DEFLATED, MAX_WBITS + 16, 9, Z_DEFAULT_STRATEGY)) { + return false; + } + const unsigned long len = compressBound(original_str.size()); + auto* buf = (unsigned char*)malloc(len); + if (!buf) { + return false; + } + d_stream.next_in = (unsigned char*)(original_str.c_str()); + d_stream.avail_in = original_str.size(); + d_stream.next_out = buf; + d_stream.avail_out = len; + deflate(&d_stream, Z_SYNC_FLUSH); + deflateEnd(&d_stream); + str.assign((char*)buf, d_stream.total_out); + free(buf); + return true; +} + +void writeNBT(const std::string& fileName, const CompoundTag& tag) { + std::string compressed; + gzip_compress(tag.toBinaryNbt(false), compressed); + auto out = std::ofstream(fileName, std::ofstream::out | std::ofstream::binary | std::ofstream::trunc); + out << compressed; + out.close(); +} + +template +void writeNlohmannJSON(const std::string& fileName, JSON_TYPE& json) { + auto out = std::ofstream(fileName, std::ofstream::out | std::ofstream::trunc); + out << json.dump(4); + out.close(); +} + +void writeJSON(const std::string& fileName, const Json::Value& json) { + auto out = std::ofstream(fileName, std::ofstream::out | std::ofstream::trunc); + out << json.toStyledString(); + out.close(); +} + +std::string aabbToStr(const AABB& aabb) { + std::stringstream aabbStr; + aabbStr << aabb.min.x << "," << aabb.min.y << "," << aabb.min.z << "," << aabb.max.x << "," << aabb.max.y << "," + << aabb.max.z; + return aabbStr.str(); } #pragma endregion TOOL_FUNCTION void PluginInit() { - Logger logger; - logger.info("DataExtractor plugin loaded!"); - if (!folderExists("data")) { - createFolder("data"); - } + ll::Logger logger("dataextractor"); + logger.info("DataExtractor plugin loaded!"); } void extractData() { - dumpCreativeItemData(); - dumpBlockAttributesData(); - dumpItemData(); - dumpEntityData(); - dumpPalette(); - dumpBlockIdToItemIdMap(); - dumpBiomeData(); - dumpPropertyTypeData(); - dumpItemTags(); - dumpBlockTags(); - //dumpCommandArgData(); - //dumpAvailableCommand(); -} - -void dumpCreativeItemData() { - Logger logger; - - logger.info("Extracting creative items..."); - - auto global = createCompound(); - unsigned int index = 0; - CreativeItemRegistry::forEachCreativeItemInstance([&logger, &index, &global](const ItemInstance& itemInstance) { - if (itemInstance.getName().empty()) { - logger.warn("Failed to extract creative item - " + itemInstance.getName() + ", index: " + to_string(index)); - return true; - } - logger.text("Extracting creative item - " + itemInstance.getName() + ", index: " + to_string(index)); - auto obj = createCompound(); - obj->putInt64("index", index); - obj->putString("name", itemInstance.getItem()->getFullItemName()); - obj->putInt("damage", itemInstance.getAuxValue()); - if (itemInstance.isBlock()) { - obj->putInt("blockStateHash", itemInstance.getBlock()->computeRawSerializationIdHashForNetwork()); - } - auto nbt = itemInstance.save(); - if (nbt->contains("tag")) { - obj->put("tag", nbt->getCompound("tag")->copy()); - } - global->put(to_string(index), obj->copy()); - index++; - }); - writeNBT("data/creative_items.nbt", global.get()); - global.release(); - logger.info(R"(Creative items data has been saved to "data/creative_items.nbt")"); -} - -std::unique_ptr generateNBTFromBlockState(const Block& block) { - Logger logger; - auto nbt = createCompound(); - try { - auto& legacy = block.getLegacyBlock(); - auto name = legacy.getNamespace() + ":" + legacy.getRawNameId(); - logger.text("Extracting block state - " + name + ":" + to_string(block.getRuntimeId())); - const Material& material = legacy.getMaterial(); - auto sid = block.getSerializationId().clone(); - nbt->putString("name", sid->getString("name")); - nbt->putString("descriptionId", block.getDescriptionId()); - nbt->putString("blockEntityName", string(magic_enum::enum_name(block.getBlockEntityType()))); - nbt->putCompound("states", sid->getCompound("states")->clone()); - nbt->putFloat("thickness", block.getThickness()); - nbt->putFloat("friction", block.getFriction()); - nbt->putFloat("hardness", block.getDestroySpeed()); - nbt->putFloat("explosionResistance", block.getExplosionResistance()); - nbt->putFloat("translucency", material.getTranslucency()); - nbt->putInt("version", sid->getInt("version")); - nbt->putInt("runtimeId", block.getRuntimeId()); - nbt->putInt("blockStateHash", ((name != "minecraft:unknown") ? block.computeRawSerializationIdHashForNetwork() : -2)); - nbt->putInt("burnChance", block.getFlameOdds()); - nbt->putInt("burnAbility", block.getBurnOdds()); - nbt->putInt("lightDampening", (int)block.getLight().value);//挡光 - nbt->putInt("lightEmission", (int)block.getLightEmission().value);//发光 - mce::Color color = block.getMapColor(overworld->getBlockSourceFromMainChunkSource(), BlockPos(0, 10, 0)); - auto colornbt = createCompound(); - colornbt->putInt("r", (int)(color.r * 255)); - colornbt->putInt("g", (int)(color.g * 255)); - colornbt->putInt("b", (int)(color.b * 255)); - colornbt->putInt("a", (int)(color.a * 255)); - colornbt->putString("hexString", color.toHexString()); - nbt->putCompound("color", colornbt->clone()); - AABB tmp = AABB(0, 0, 0, 0, 0, 0); - block.getCollisionShapeForCamera(tmp, *(IConstBlockSource*)&overworld->getBlockSourceFromMainChunkSource(), BlockPos(0, 0, 0)); - nbt->putString("aabbVisual", aabbToStr(tmp)); - AABB tmp2 = AABB(0, 0, 0, 0, 0, 0); - class optional_ref nullRef {}; - block.getCollisionShape(tmp2, *(IConstBlockSource*)&overworld->getBlockSourceFromMainChunkSource(), BlockPos(0, 0, 0), nullRef); - nbt->putString("aabbCollision", aabbToStr(tmp2)); - - nbt->putBoolean("hasCollision", tmp2 != ZERO_AABB); - nbt->putBoolean("hasBlockEntity", block.getBlockEntityType() != BlockActorType::Undefined); - nbt->putBoolean("isAir", block.isAir()); - nbt->putBoolean("isBounceBlock", block.isAir()); - nbt->putBoolean("isButtonBlock", block.isButtonBlock()); - nbt->putBoolean("isCropBlock", block.isCropBlock()); - nbt->putBoolean("isDoorBlock", block.isDoorBlock()); - nbt->putBoolean("isFenceBlock", block.isFenceBlock()); - nbt->putBoolean("isFenceGateBlock", block.isFenceGateBlock()); - nbt->putBoolean("isThinFenceBlock", block.isThinFenceBlock()); - nbt->putBoolean("isFallingBlock", block.isFallingBlock()); - nbt->putBoolean("isStemBlock", block.isStemBlock()); - nbt->putBoolean("isSlabBlock", block.isSlabBlock()); - nbt->putBoolean("isLiquid", material.isLiquid()); - nbt->putBoolean("isAlwaysDestroyable", material.isAlwaysDestroyable());//是否可以被空手破坏且获取方块 - nbt->putBoolean("isLavaFlammable", block.isLavaFlammable());//是否可燃 - nbt->putBoolean("isUnbreakable", block.isUnbreakable());//是否不可破坏 - nbt->putBoolean("isPowerSource", block.isSignalSource()); - //nbt->putBoolean("breaksFallingBlocks", block.breaksFallingBlocks(BaseGameVersion()));未知作用 - nbt->putBoolean("isWaterBlocking", block.isWaterBlocking());//是否能阻挡水 - nbt->putBoolean("isMotionBlockingBlock", block.isMotionBlockingBlock());//是否能阻挡移动 - nbt->putBoolean("hasComparatorSignal", block.hasComparatorSignal());//是否能产生比较器信号 - nbt->putBoolean("pushesUpFallingBlocks", block.pushesUpFallingBlocks());//活塞类方块 - //nbt->putBoolean("waterSpreadCausesSpawn", block.waterSpreadCausesSpawn());未知作用 - nbt->putBoolean("canContainLiquid", block.getLegacyBlock().canContainLiquid()); - //nbt->putBoolean("canBeMovingBlock", material.getBlocksMotion());和isMotionBlockingBlock一个作用 - //nbt->putBoolean("blocksPrecipitation", material.getBlocksPrecipitation());未知作用 - nbt->putBoolean("superHot", material.isSuperHot());//可以导致着火的方块 - //nbt->putBoolean("canBeBrokenFromFalling", block.canBeBrokenFromFalling());未知作用 - nbt->putBoolean("isSolid", block.isSolid()); - //nbt->putBoolean("isSolidBlocking", material.isSolidBlocking());未知作用 - nbt->putBoolean("isContainerBlock", block.isContainerBlock()); - - } - catch (exception& e) { - logger.error("Exception caught : " + string(e.what())); - } - - return nbt; -} - -void dumpBlockAttributesData() { - Logger logger; - logger.info("Extracting block states' attributes..."); - const auto& palette = mc->getLevel()->getBlockPalette(); - int airCount = 0; - auto array = json::array(); - - auto tag = createCompound(); - auto list = createListTag(); - blockStateCounter = 0; - while (true) { - const auto& block = palette.getBlock(blockStateCounter); - //HACK: 用于确定最大size - if (block.getName().getString() == "minecraft:air") { - airCount++; - if (airCount == 2) { - blockStateCounter--; - break; - } - } - auto obj2 = generateNBTFromBlockState(block); - list->add(obj2->copy()); - blockStateCounter++; - } - tag->put("block", list->copyList()); - logger.info("Successfully extract " + to_string(blockStateCounter) + " block states' attributes!"); - writeNBT("data/block_attributes.nbt", tag.get()); - logger.info(R"(Block attribute data have been saved to "data/block_attributes.nbt")"); - tag.release(); - list.release(); -} - - -std::unique_ptr generateNBTFromItem(const Item& item) { - Logger logger; - std::unique_ptr nbt = createCompound(); - logger.info("Extracting item - " + item.getFullItemName()); - nbt->putShort("id", item.getId()); - try { - if (!item.getLegacyBlock().expired() && item.getLegacyBlock().get() != nullptr) - nbt->putString("blockId", item.getLegacyBlock()->getNamespace() + ":" + item.getLegacyBlock()->getRawNameId()); - } - catch (exception& e) { - logger.warn("Exception occur when trying to get block for item " + item.getFullItemName()); - } - nbt->putBoolean("isComponentBased", item.isComponentBased()); - nbt->putString("name", item.getFullItemName()); - nbt->putShort("maxDamage", item.getMaxDamage());//最大耐久 - nbt->putBoolean("isArmor", item.isArmor()); - nbt->putBoolean("isBlockPlanterItem", item.isBlockPlanterItem()); - nbt->putBoolean("isDamageable", item.isDamageable()); - nbt->putBoolean("isDye", item.isDye()); - nbt->putString("itemColorName", ItemColorUtil::getName(item.getItemColor())); - nbt->putInt("itemColorRGB", ItemColorUtil::getRGBColor(item.getItemColor())); - nbt->putBoolean("isFertilizer", item.isFertilizer()); - nbt->putBoolean("isThrowable", item.isThrowable()); - nbt->putBoolean("isFood", item.isFood()); - nbt->putBoolean("isUseable", item.isUseable()); - nbt->putBoolean("isElytra", item.isElytra()); - nbt->putBoolean("canBeDepleted", item.canBeDepleted()); - nbt->putBoolean("canDestroyInCreative", item.canDestroyInCreative()); - nbt->putBoolean("canUseOnSimTick", item.canUseOnSimTick()); - nbt->putBoolean("canBeCharged", item.canBeCharged()); - nbt->putString("creativeGroup", item.getCreativeGroup()); - nbt->putInt("creativeCategory", (int)item.getCreativeCategory()); - nbt->putInt("armorValue", item.getArmorValue()); - nbt->putInt("attackDamage", item.getAttackDamage()); - nbt->putInt("toughnessValue", item.getToughnessValue()); - nbt->putFloat("viewDamping", item.getViewDamping()); - nbt->putInt("cooldownTime", item.getCooldownTime()); - nbt->putString("cooldownType", item.getCooldownType().getString()); - nbt->putInt("maxStackSize", (int)ItemStack(item, 1, 0, 0).getMaxStackSize()); - CompoundTag descriptionId; - std::set uniqueStr; - for (int i = 0; i <= 256; ++i) { - try { - if (item.isValidAuxValue(i)) { - const auto itemstack = ItemStack(item, 1, i);//ignore some invaild aux exception - if (!uniqueStr.contains(itemstack.getDescriptionId())) { - uniqueStr.insert(itemstack.getDescriptionId()); - descriptionId.putString(to_string(i), itemstack.getDescriptionId()); - } - } - } - catch (...) {} - } - nbt->putCompound("descriptionId", descriptionId); - return nbt; -} - -void dumpItemData() { - Logger logger; - auto tag = createCompound(); - auto list = createListTag(); - short counter = 0; - for (short id = -2000; id <= 2000; id++) { - const WeakPtr item = ItemRegistryManager::getItemRegistry().getItem(id); - if (item.expired()) { - continue; - } - std::unique_ptr obj2 = generateNBTFromItem(*item); - list->add(obj2->copy()); - obj2.release(); - counter++; - } - tag->put("item", list->copyList()); - list.release(); - logger.info("Successfully extract " + to_string(counter) + " items' data!"); - writeNBT("data/item_data.nbt", tag.get()); - tag.release(); - logger.info(R"(Items' data have been saved to "data/item_data.nbt")"); -} - -void dumpEntityAABB(const Level* level, const pair& pair, - nlohmann::basic_json>& obj) { - Logger logger; - Mob* actor = level->getSpawner().spawnMob(overworld->getBlockSourceFromMainChunkSource(), *pair.second, nullptr, Vec3(0, 64, 0), false, true, false); - if (actor == nullptr) { - logger.warn("Failed to spawn entity: " + pair.first); - logger.warn("It is possible to solve this problem by adding a ticking area around 0 64 0"); - logger.warn("AABB data for this entity will be missing!"); - } - else { - auto& aabb = actor->getAABB(); - stringstream aabbStr; - aabbStr << aabb.min.x << "," << aabb.min.y << "," << aabb.min.z << "," << aabb.max.x - << "," << aabb.max.y << "," << aabb.max.z; - obj["aabb"] = aabbStr.str(); - //todo: nbt - actor->kill(); - } -} - -void dumpEntityData() { - Logger logger; - - auto level = mc->getLevel(); - auto& exp = level->getLevelData().getExperiments(); - auto& actorFactory = level->getActorFactory(); - auto list = actorFactory.buildSummonEntityTypeEnum(exp); - - auto global = json::object(); - for (auto& pair : list) { - if (global.contains(pair.second->getCanonicalName())) - continue; - logger.info("Extracting entity - " + pair.second->getCanonicalName()); - - auto obj = json::object(); - obj["canonicalName"] = pair.second->getCanonicalName(); - obj["initEvent"] = pair.second->getInitEvent(); - obj["legacyActorType"] = static_cast<__int32>(pair.second->_getLegacyActorType()); - - dumpEntityAABB(level, pair, obj); - - global[pair.second->getCanonicalName()] = obj; - } - writeJSON("data/entity_data.json", global); - logger.info("Entities' data have been saved to \"data/entity_data.json\""); -} - -void dumpPalette() { - Logger logger; - - logger.info("Extracting block palette..."); - - auto& palette = mc->getLevel()->getBlockPalette(); - - auto global = createCompound(); - auto blocks = createListTag(); - for (int i = 0; i <= blockStateCounter; ++i) { - blocks->add(palette.getBlock(i).getSerializationId().clone()); - } - global->put("blocks", blocks->copyList()); - writeNBT("data/block_palette.nbt", global.get()); - global.release(); - blocks.release(); - logger.info(R"(Block palette table has been saved to "data/block_palette.nbt"))"); -} - -void dumpBlockIdToItemIdMap() { - Logger logger; - logger.info("Extracting block id to item id map..."); - auto nbt = createCompound(); - json json; - - int i = -2000; - while (i <= 2000) { - auto item = ItemRegistryManager::getItemRegistry().getItem(static_cast(i)); - i++; - if (item.expired() || item.get() == nullptr) { - continue; - } - logger.text("Extracting block id to item id map:" + item.get()->getFullItemName()); - string item_id = item->getFullItemName(); - auto& block = item->getLegacyBlock(); - string block_id; - bool hasBlock = !block.expired() && block.get() != nullptr; - if (hasBlock) - block_id = block->getNamespace() + ":" + block->getRawNameId(); - //HACK: 这是一个BDS的bug, 我们需要手动修复 - //TODO: 删除这个HACK当BDS修复了之后 - if (item_id.ends_with("_hanging_sign") || item_id == "minecraft:bamboo_door" || item_id == "minecraft:cherry_door") { - hasBlock = true; - block_id = item_id; - } - if (hasBlock) { - nbt->putString(block_id, item_id); - json[block_id] = item_id; - logger.info(block_id + " -> " + item_id); - } - } - - writeNBT("data/block_id_to_item_id_map.nbt", nbt.get()); - nbt.release(); - writeJSON("data/block_id_to_item_id_map.json", json); - logger.info(R"(Block id to item id map has been saved to "data/block_id_to_item_id_map.json", "data/block_id_to_item_id_map.nbt"))"); -} - - -void dumpBiomeData() { - Logger logger; - BiomeRegistry const& registry = mc->getLevel()->getBiomeRegistry(); - auto biomeInfoMap = json::object(); - auto biomes = createCompound(); - registry.forEachBiome([&biomes, ®istry, &logger, &biomeInfoMap](Biome& biome) { - string name = ll::memory::dAccess(&biome, 8).getString(); - int id = ll::memory::dAccess(&biome, 136); - logger.info("Extracting biome data - " + name); - auto tag = createCompound(); - TagRegistry, IDType>& tagRegistry = const_cast, struct IDType>&>(registry.getTagRegistry()); - biome.writePacketData(*tag, tagRegistry); - biomes->put(name, tag->copy()); - - auto obj = json::object(); - obj["id"] = id; - obj["type"] = string(magic_enum::enum_name(biome.getBiomeType())); - biomeInfoMap[name] = obj; - }); - writeNBT("data/biome_definitions.nbt", biomes.get()); - biomes.release(); - writeJSON("data/biome_id_and_type.json", biomeInfoMap); - logger.info(R"(Biome definitions has been saved to "data/biome_definitions.nbt" and "data/biome_id_and_type.json")"); -} - -void dumpCommandArgData() { - //Logger logger; - - //CommandRegistry& registry = commands->getRegistry(); - //auto global = json::object(); - //registry.forEachNonTerminal([&logger, &global,®istry](auto symbol) { - // //buggy toString - // string sym = registry.symbolToString(symbol); - // logger.info("Extracting command arg type - " + sym); - // auto obj = json::object(); - // obj["value"] = symbol.value(); - // obj["index"] = symbol.toIndex(); - // global[sym] = obj; - // }); - //writeJSON("data/command_arg_types.json", global); - //logger.info("Command arg type data have been saved to \"data/command_arg_types.json\""); -} - -void dumpAvailableCommand() { - /*Logger logger; - - CommandRegistry& registry = commands->getRegistry(); - auto aCmdPk = registry.serializeAvailableCommands(); - logger.info("Extracting available command data..."); - - auto global = json::object(); - - logger.info("Extracting all enums..."); - global["allEnums"] = aCmdPk.mEnumValues; - logger.info("Extracting all suffix..."); - global["allSuffix"] = aCmdPk.mPostfixes; - - logger.info("Extracting enum data array..."); - auto enumDataArray = json::array(); - for (auto& enumData : aCmdPk.mEnums) { - auto obj = json::object(); - - obj["name"] = enumData.name; - obj["valueIndices"] = enumData.valueIndices; - - enumDataArray.push_back(obj); - } - global["enumDatas"] = enumDataArray; - - logger.info("Extracting chained subcommand value array..."); - global["chainedSubcommandValues"] = aCmdPk.mSubcommandValues; - - logger.info("Extracting chained subcommand array..."); - auto chainedSubcommandArray = json::array(); - for (auto& chainedSubcommand : aCmdPk.mSubcommands) { - auto chainedSubcommandDataObj = json::object(); - - chainedSubcommandDataObj["name"] = chainedSubcommand.name; - - auto valueIndices = json::array(); - for (auto& valueIndice : chainedSubcommand.valueIndices) { - auto valueIndicesObj = json::object(); - valueIndicesObj["index"] = valueIndice.index; - valueIndicesObj["value"] = valueIndice.value; - - valueIndices.push_back(valueIndicesObj); - } - - chainedSubcommandDataObj["valueIndices"] = valueIndices; - - chainedSubcommandArray.push_back(chainedSubcommandDataObj); - } - global["chainedSubcommands"] = chainedSubcommandArray; - - logger.info("Extracting command data array..."); - auto commandDataArray = json::array(); - for (auto& commandData : aCmdPk.mCommands) { - auto obj = json::object(); - - obj["name"] = commandData.name; - obj["description"] = commandData.description; - obj["flag"] = commandData.flag.value; - obj["perm"] = commandData.perm; - auto overloads = json::array(); - for (auto& overload : commandData.overloads) { - auto overloadData = json::object(); - auto overloadParams = json::array(); - - for (auto& paramData : overload.datas) { - auto paramObj = json::object(); - - paramObj["description"] = paramData.desc; - paramObj["sym"] = paramData.sym; - paramObj["optional"] = paramData.optional; - paramObj["paramOptions"] = paramData.paramOptions; - overloadParams.push_back(paramObj); - } - - overloadData["datas"] = overloadParams; - overloadData["chained"] = overload.chained; - - overloads.push_back(overloadData); - } - obj["overloads"] = overloads; - obj["chainedOffsets"] = commandData.chainedOffsets; - obj["aliasIndex"] = commandData.aliasEnumIndex; - - commandDataArray.push_back(obj); - } - global["commandData"] = commandDataArray; - - logger.info("Extracting soft enum data array..."); - auto softEnumDataArray = json::array(); - for (auto& softEnumData : aCmdPk.mSoftEnums) { - auto softEnumDataObj = json::object(); - - softEnumDataObj["name"] = softEnumData.name; - softEnumDataObj["values"] = softEnumData.values; + // ll::Logger logger("dataextractor"); + // logger.info("DataExtractor plugin start!"); + // if (!folderExists("data")) { + // createFolder(logger, "data"); + // } + // dumpCommandNameSymbol(logger); + // dumpCommonCommandArgData(logger); + // dumpFullCommandArgData(logger); + // dumpCommandmConstrainedValues(logger); + // dumpBiomeData(logger); + // dumpCreativeItemData(logger); + // dumpBlockAttributesData(logger); + // dumpItemData(logger); + // dumpPalette(logger); + // dumpBlockTags(logger); + // dumpItemTags(logger); + // dumpPropertyTypeData(logger); +} + +void dumpCreativeItemData(const ll::Logger& logger) { + logger.info("Extracting creative items..."); + + auto global = CompoundTag(); + unsigned int index = 0; + CreativeItemRegistry::forEachCreativeItemInstance([&logger, &index, &global](const ItemInstance& itemInstance) { + if (itemInstance.getName().empty()) { + logger.warn( + "Failed to extract creative item - " + itemInstance.getName() + ", index: " + std::to_string(index) + ); + return true; + } + logger.info("Extracting creative item - " + itemInstance.getName() + ", index: " + std::to_string(index)); + auto obj = CompoundTag(); + obj.putInt64("index", index); + obj.putString("name", itemInstance.getItem()->getFullItemName()); + obj.putInt("damage", itemInstance.getAuxValue()); + if (itemInstance.isBlock()) { + obj.putInt("blockStateHash", itemInstance.getBlock()->computeRawSerializationIdHashForNetwork()); + } + if (const auto nbt = itemInstance.save(); nbt->contains("tag")) { + obj.put("tag", nbt->getCompound("tag")->copy()); + } + global.put(std::to_string(index), obj.copy()); + index++; + return true; + }); + writeNBT("data/creative_items.nbt", global); + logger.info(R"(Creative items data has been saved to "data/creative_items.nbt")"); +} + +void extractBlock(ListTag& dest, const Block& block, const ll::Logger& logger) { + auto nbt = CompoundTag(); + try { + auto& legacy = block.getLegacyBlock(); + auto name = legacy.getNamespace() + ":" + legacy.getRawNameId(); + logger.info("Extracting block state - " + name + ":" + std::to_string(block.getRuntimeId())); + const Material& material = legacy.getMaterial(); + auto sid = block.getSerializationId().clone(); + nbt.putString("name", sid->getString("name")); + nbt.putString("descriptionId", block.getDescriptionId()); + nbt.putString("blockEntityName", std::string(magic_enum::enum_name(block.getBlockEntityType()))); + nbt.putCompound("states", sid->getCompound("states")->clone()); + nbt.putFloat("thickness", block.getThickness()); + nbt.putFloat("friction", block.getFriction()); + nbt.putFloat("hardness", block.getDestroySpeed()); + nbt.putFloat("explosionResistance", block.getExplosionResistance()); + nbt.putFloat("translucency", material.getTranslucency()); + nbt.putInt("version", sid->getInt("version")); + nbt.putInt("runtimeId", block.getRuntimeId()); + if (name != "minecraft:unknown") nbt.putInt("blockStateHash", block.computeRawSerializationIdHashForNetwork()); + else nbt.putInt("blockStateHash", -2); + nbt.putInt("burnChance", block.getFlameOdds()); + nbt.putInt("burnAbility", block.getBurnOdds()); + nbt.putInt("lightDampening", block.getLight().value); + nbt.putInt("lightEmission", block.getLightEmission().value); + mce::Color color = block.getMapColor(overworld->getBlockSourceFromMainChunkSource(), BlockPos(0, 10, 0)); + auto colornbt = CompoundTag(); + colornbt.putInt("r", static_cast(color.r * 255)); + colornbt.putInt("g", static_cast(color.g * 255)); + colornbt.putInt("b", static_cast(color.b * 255)); + colornbt.putInt("a", static_cast(color.a * 255)); + colornbt.putString("hexString", color.toHexString()); + nbt.putCompound("color", colornbt); + auto tmp = AABB(0, 0, 0, 0, 0, 0); + block.getCollisionShapeForCamera( + tmp, + *reinterpret_cast(&overworld->getBlockSourceFromMainChunkSource()), + BlockPos(0, 0, 0) + ); + nbt.putString("aabbVisual", aabbToStr(tmp)); + auto tmp2 = AABB(0, 0, 0, 0, 0, 0); + optional_ref nullRef{}; + block.getCollisionShape( + tmp2, + *reinterpret_cast(&overworld->getBlockSourceFromMainChunkSource()), + BlockPos(0, 0, 0), + nullRef + ); + nbt.putString("aabbCollision", aabbToStr(tmp2)); + nbt.putBoolean("hasCollision", tmp2 != ZERO_AABB); + nbt.putBoolean("hasBlockEntity", block.getBlockEntityType() != BlockActorType::Undefined); + nbt.putBoolean("isAir", block.isAir()); + nbt.putBoolean("isBounceBlock", block.isAir()); + nbt.putBoolean("isButtonBlock", block.isButtonBlock()); + nbt.putBoolean("isCropBlock", block.isCropBlock()); + nbt.putBoolean("isDoorBlock", block.isDoorBlock()); + nbt.putBoolean("isFenceBlock", block.isFenceBlock()); + nbt.putBoolean("isFenceGateBlock", block.isFenceGateBlock()); + nbt.putBoolean("isThinFenceBlock", block.isThinFenceBlock()); + nbt.putBoolean("isFallingBlock", block.isFallingBlock()); + nbt.putBoolean("isStemBlock", block.isStemBlock()); + nbt.putBoolean("isSlabBlock", block.isSlabBlock()); + nbt.putBoolean("isLiquid", material.isLiquid()); + nbt.putBoolean("isAlwaysDestroyable", material.isAlwaysDestroyable()); + nbt.putBoolean("isLavaFlammable", block.isLavaFlammable()); + nbt.putBoolean("isUnbreakable", block.isUnbreakable()); + nbt.putBoolean("isPowerSource", block.isSignalSource()); + // nbt->putBoolean("breaksFallingBlocks", block.breaksFallingBlocks(BaseGameVersion())); + nbt.putBoolean("isWaterBlocking", block.isWaterBlocking()); + nbt.putBoolean("isMotionBlockingBlock", block.isMotionBlockingBlock()); + nbt.putBoolean("hasComparatorSignal", block.hasComparatorSignal()); + nbt.putBoolean("pushesUpFallingBlocks", block.pushesUpFallingBlocks()); + // nbt->putBoolean("waterSpreadCausesSpawn", block.waterSpreadCausesSpawn()); + nbt.putBoolean("canContainLiquid", block.getLegacyBlock().canContainLiquid()); + // nbt->putBoolean("canBeMovingBlock", material.getBlocksMotion()); + // nbt->putBoolean("blocksPrecipitation", material.getBlocksPrecipitation()); + nbt.putBoolean("superHot", material.isSuperHot()); + // nbt->putBoolean("canBeBrokenFromFalling", block.canBeBrokenFromFalling()); + nbt.putBoolean("isSolid", block.isSolid()); + // nbt->putBoolean("isSolidBlocking", material.isSolidBlocking()); + nbt.putBoolean("isContainerBlock", block.isContainerBlock()); + } catch (char* e) { + logger.error("Exception caught {}", e); + } + + dest.add(nbt); +} + +void dumpBlockAttributesData(const ll::Logger& logger) { + logger.info("Extracting block states' attributes..."); + const auto& palette = mc->getLevel()->getBlockPalette(); + int airCount = 0; + auto array = nlohmann::json::array(); + + auto tag = CompoundTag(); + auto list = ListTag(); + blockStateCounter = 0; + while (true) { + const auto& block = palette.getBlock(blockStateCounter); + if (block.getName().getString() == "minecraft:air") { + airCount++; + if (airCount == 2) { + blockStateCounter--; + break; + } + } + extractBlock(list, block, logger); + blockStateCounter++; + } + tag.put("block", list.copyList()); + logger.info("Successfully extract " + std::to_string(blockStateCounter) + " block states' attributes!"); + writeNBT("data/block_attributes.nbt", tag); + logger.info(R"(Block attribute data have been saved to "data/block_attributes.nbt")"); +} - softEnumDataArray.push_back(softEnumDataObj); - } - global["softEnumData"] = softEnumDataArray; +void extractItem(ListTag& dest, const Item& item, const ll::Logger& logger) { + auto nbt = CompoundTag(); + logger.info("Extracting item - " + item.getFullItemName()); + nbt.putShort("id", item.getId()); + try { + if (!item.getLegacyBlock().expired() && item.getLegacyBlock().get() != nullptr) + nbt.putString( + "blockId", + item.getLegacyBlock()->getNamespace() + ":" + item.getLegacyBlock()->getRawNameId() + ); + } catch (std::exception& e) { + logger.warn("Exception occur when trying to get block for item " + item.getFullItemName()); + } + nbt.putBoolean("isComponentBased", item.isComponentBased()); + nbt.putString("name", item.getFullItemName()); + nbt.putShort("maxDamage", item.getMaxDamage()); + nbt.putBoolean("isArmor", item.isArmor()); + nbt.putBoolean("isBlockPlanterItem", item.isBlockPlanterItem()); + nbt.putBoolean("isDamageable", item.isDamageable()); + nbt.putBoolean("isDye", item.isDye()); + nbt.putString("itemColorName", ItemColorUtil::getName(item.getItemColor())); + nbt.putInt("itemColorRGB", ItemColorUtil::getRGBColor(item.getItemColor())); + nbt.putBoolean("isFertilizer", item.isFertilizer()); + nbt.putBoolean("isThrowable", item.isThrowable()); + nbt.putBoolean("isFood", item.isFood()); + nbt.putBoolean("isUseable", item.isUseable()); + nbt.putBoolean("isElytra", item.isElytra()); + nbt.putBoolean("canBeDepleted", item.canBeDepleted()); + nbt.putBoolean("canDestroyInCreative", item.canDestroyInCreative()); + nbt.putBoolean("canUseOnSimTick", item.canUseOnSimTick()); + nbt.putBoolean("canBeCharged", item.canBeCharged()); + nbt.putString("creativeGroup", item.getCreativeGroup()); + nbt.putInt("creativeCategory", static_cast(item.getCreativeCategory())); + nbt.putInt("armorValue", item.getArmorValue()); + nbt.putInt("attackDamage", item.getAttackDamage()); + nbt.putInt("toughnessValue", item.getToughnessValue()); + nbt.putFloat("viewDamping", item.getViewDamping()); + nbt.putInt("cooldownTime", item.getCooldownTime()); + nbt.putString("cooldownType", item.getCooldownType().getString()); + nbt.putInt("maxStackSize", item.getMaxStackSize(item.buildDescriptor(0, nullptr))); + CompoundTag descriptionId; + std::set uniqueStr; + for (int i = 0; i <= 256; ++i) { + try { + if (item.isValidAuxValue(i)) { + const auto itemstack = ItemStack(item, 1, i); // ignore some invaild aux exception + if (!uniqueStr.contains(itemstack.getDescriptionId())) { + uniqueStr.insert(itemstack.getDescriptionId()); + descriptionId.putString(std::to_string(i), itemstack.getDescriptionId()); + } + } + } catch (...) {} + } + nbt.putCompound("descriptionId", descriptionId); + dest.add(nbt); +} + +void dumpItemData(const ll::Logger& logger) { + auto tag = CompoundTag(); + auto list = ListTag(); + short counter = 0; + for (const auto& item : ItemRegistryManager::getItemRegistry().getNameToItemMap() | std::views::values) { + extractItem(list, *item, logger); + counter++; + } + tag.put("item", list); + logger.info("Successfully extract " + std::to_string(counter) + " items' data!"); + writeNBT("data/item_data.nbt", tag); + logger.info(R"(Items' data have been saved to "data/item_data.nbt")"); +} + +void dumpPalette(const ll::Logger& logger) { + logger.info("Extracting block palette..."); + + const auto& palette = mc->getLevel()->getBlockPalette(); + + auto global = CompoundTag(); + auto blocks = ListTag(); + for (int i = 0; i <= blockStateCounter; ++i) { + blocks.add(palette.getBlock(i).getSerializationId().clone()); + } + global.put("blocks", blocks); + writeNBT("data/block_palette.nbt", global); + logger.info(R"(Block palette table has been saved to "data/block_palette.nbt"))"); +} + +bool compareCmdSymbolByIndex(const CommandRegistry::Symbol& s1, const CommandRegistry::Symbol& s2) { + return s1.toIndex() < s2.toIndex(); +} + +bool compareCmdSymbolByValue(const CommandRegistry::Symbol& s1, const CommandRegistry::Symbol& s2) { + return s1.value() < s2.value(); +} + +template +void dumpCmdSymbol1( + const ll::Logger& logger, + const CommandRegistry& registry, + JSON_TYPE& json, + const CommandRegistry::Symbol& symbol +) { + const std::string name = registry.symbolToString(symbol); + logger.info("Extracting command arg type - " + name); + auto obj = std::map(); + obj["description"] = registry.describe(symbol); + obj["index"] = std::to_string(symbol.toIndex()); + obj["value"] = std::to_string(symbol.value()); + json[name] = obj; +} + +template +void dumpCmdSymbol2( + const ll::Logger& logger, + const CommandRegistry& registry, + JSON_TYPE& json, + const CommandRegistry::Symbol& symbol, + const std::string& key +) { + const std::string name = registry.symbolToString(symbol); + logger.info("Extracting command arg type - " + name); + auto obj = std::map(); + obj["name"] = name; + obj["description"] = registry.describe(symbol); + obj["index"] = std::to_string(symbol.toIndex()); + obj["value"] = std::to_string(symbol.value()); + json[key] = obj; +} + +void dumpCommandNameSymbol(const ll::Logger& logger) { + const auto& registry = mc->getCommands().getRegistry(); + auto symbols_sortby_index = std::vector(); + auto symbols_sortby_value = std::vector(); + for (auto& symbol : registry.mCommandSymbols) { + if (!registry.isValid(symbol)) { + continue; + } + if (auto name = registry.symbolToString(symbol); name == "ll" || name == "ext") { + continue; + } + symbols_sortby_index.push_back(symbol); + symbols_sortby_value.push_back(symbol); + } + // Sort symbol by index + std::ranges::sort(symbols_sortby_index, compareCmdSymbolByIndex); + std::ranges::sort(symbols_sortby_value, compareCmdSymbolByValue); + nlohmann::ordered_json global1; + for (auto& symbol : symbols_sortby_index) { + dumpCmdSymbol1(logger, registry, global1, symbol); + } + writeNlohmannJSON("data/command_name_symbol_i.json", global1); + nlohmann::ordered_json global2; + for (auto& symbol : symbols_sortby_value) { + dumpCmdSymbol1(logger, registry, global2, symbol); + } + writeNlohmannJSON("data/command_name_symbol_v.json", global2); + logger.info("Command name symbol have been saved to \"data/command_name_symbol_(i/v).json\""); +} + +void dumpCommonCommandArgData(const ll::Logger& logger) { + const auto& registry = mc->getCommands().getRegistry(); + nlohmann::ordered_json global; + for (int i = 0; i < 1000; i++) { + if (const int symbol = i | 0x100000; registry.isValid(symbol)) { + dumpCmdSymbol1(logger, registry, global, symbol); + } + } + writeNlohmannJSON("data/command_arg_types_common_i.json", global); + logger.info("Common command arg type have been saved to \"data/command_arg_types_common_i.json\""); +} + +void dumpFullCommandArgData(const ll::Logger& logger) { + auto& registry = mc->getCommands().getRegistry(); + auto symbols_sortby_index = std::vector(); + auto symbols_sortby_value = std::vector(); + registry.forEachNonTerminal( + [®istry, &symbols_sortby_index, &symbols_sortby_value](const CommandRegistry::Symbol& symbol) { + if (!registry.isValid(symbol)) { + return; + } + symbols_sortby_index.push_back(symbol); + symbols_sortby_value.push_back(symbol); + } + ); + // Sort symbol by index + std::ranges::sort(symbols_sortby_index, compareCmdSymbolByIndex); + nlohmann::ordered_json global1; + for (auto& symbol : symbols_sortby_index) { + dumpCmdSymbol1(logger, registry, global1, symbol); + } + writeNlohmannJSON("data/command_arg_types_full_i.json", global1); + nlohmann::ordered_json global2; + for (auto& symbol : symbols_sortby_value) { + dumpCmdSymbol1(logger, registry, global2, symbol); + } + writeNlohmannJSON("data/command_arg_types_full_v.json", global2); + logger.info("Full command arg type data have been saved to \"data/command_arg_types_full_(i/v).json\""); +} - logger.info("Extracting constrained value data array..."); - auto constrainedValueDataArray = json::array(); - for (auto& constrainedValueData : aCmdPk.mConstraints) { - auto constrainedValueDataObj = json::object(); - - constrainedValueDataObj["enumIndex"] = constrainedValueData.enumValueIndex; - constrainedValueDataObj["enumNameIndex"] = constrainedValueData.enumNameIndex; - constrainedValueDataObj["indices"] = constrainedValueData.indices; - - constrainedValueDataArray.push_back(constrainedValueDataObj); - } - global["constrainedValueData"] = constrainedValueDataArray; - writeJSON("data/available_commands.json", global); - logger.info("Available commands' data has been saved to \"data/available_commands.json\"");*/ +void dumpCommandmConstrainedValues(const ll::Logger& logger) { + auto& registry = mc->getCommands().getRegistry(); + auto array = nlohmann::json::array(); + for (auto& [mValue, mEnum, mConstraints] : registry.mConstrainedValues) { + auto obj = nlohmann::json::object(); + dumpCmdSymbol2(logger, registry, obj, mValue, "value"); + dumpCmdSymbol2(logger, registry, obj, mEnum, "enum"); + obj["constraints"] = mConstraints; + array.push_back(obj); + } + writeNlohmannJSON("data/command_constrained_values.json", array); + logger.info("Command constrained values data have been saved to \"data/command_constrained_values.json\""); +} + +void dumpBiomeData(const ll::Logger& logger) { + BiomeRegistry& registry = mc->getLevel()->getBiomeRegistry(); + auto biomeInfoMap = nlohmann::json::object(); + auto biomes = CompoundTag(); + TagRegistry, IDType>& tagReg = registry.getTagRegistry(); + registry.forEachBiome([&biomes, &logger, &tagReg, &biomeInfoMap](Biome& biome) { + auto& name = biome.getName(); + int id = biome.getId(); + logger.info("Extracting biome data - " + name); + auto tag = CompoundTag(); + biome.writePacketData(tag, tagReg); + biomes.put(name, tag); + auto obj = nlohmann::json::object(); + obj["id"] = id; + obj["type"] = std::string(magic_enum::enum_name(biome.getBiomeType())); + biomeInfoMap[name] = obj; + }); + writeNBT("data/biome_definitions.nbt", biomes); + writeNlohmannJSON("data/biome_id_and_type.json", biomeInfoMap); + logger.info(R"(Biome definitions has been saved to "data/biome_definitions.nbt" and "data/biome_id_and_type.json")" + ); } struct PropertyType { - std::string serializationName; - std::string valueType; - std::set values; - std::string blockName; - - bool operator==(const PropertyType& other) const { - return serializationName == other.serializationName && valueType == other.valueType && values.size() == other.values.size(); - } + std::string serializationName; + std::string valueType; + std::set values; + std::string blockName; + + bool operator==(const PropertyType& other) const { + return serializationName == other.serializationName && valueType == other.valueType + && values.size() == other.values.size(); + } }; -void dumpPropertyTypeData() { - Logger logger; - logger.info("Extracting property type data..."); - - std::map>> blockToBlockStateData; - - auto& palette = mc->getLevel()->getBlockPalette(); - for (int i = 0; i <= blockStateCounter; ++i) { - const Block& block = palette.getBlock(i); - auto name = block.getLegacyBlock().getRawNameId(); - if (!blockToBlockStateData.contains(name)) { - blockToBlockStateData[name] = std::vector>(); - } - auto& blockStates = blockToBlockStateData[name]; - auto nbt = block.getSerializationId().clone(); - if (nbt->contains("states") && !nbt->getCompound("states")->isEmpty()) { - blockStates.push_back(nbt->getCompound("states")->clone()); - } - } - - std::map> blockToPropertyTypeMap; - - for (auto& entry : blockToBlockStateData) { - auto& states = entry.second; - std::map propertyTypeMap; - - for (auto& state : states) { - for (auto& valueEntry : state->rawView()) { - if (!propertyTypeMap.contains(valueEntry.first)) { - PropertyType p; - p.serializationName = valueEntry.first; - p.blockName = entry.first; - propertyTypeMap[p.serializationName] = p; - } - auto& propertyType = propertyTypeMap[valueEntry.first]; - switch (valueEntry.second.get()->getId()) { - case Tag::Type::Byte: - if (propertyType.valueType.empty()) { - propertyType.valueType = "BOOLEAN"; - } - propertyType.values.insert(state->getBoolean(valueEntry.first) ? "true" : "false"); - break; - case Tag::Type::Int: - if (propertyType.valueType.empty()) { - propertyType.valueType = "INTEGER"; - } - propertyType.values.insert(to_string(state->getInt(valueEntry.first))); - break; - case Tag::Type::String: - if (propertyType.valueType.empty()) { - propertyType.valueType = "ENUM"; - } - propertyType.values.insert(state->getString(valueEntry.first)); - break; - default: - if (propertyType.valueType.empty()) { - propertyType.valueType = "UNKNOWN"; - } - logger.warn("Unknown tag type when dumping property type data: " + valueEntry.first); - break; - } - } - } - blockToPropertyTypeMap[entry.first] = propertyTypeMap; - } - - std::set differentSizePropertyTypes; - std::map> specialBlockTypes; - std::map tmpLookUp; - - for (auto& entry : blockToPropertyTypeMap) { - for (auto& entryInside : entry.second) { - auto& propertyName = entryInside.first; - auto& propertyType = entryInside.second; - if (!tmpLookUp.contains(propertyName)) { - tmpLookUp[propertyName] = propertyType; - } - else if (tmpLookUp[propertyName] != propertyType && !differentSizePropertyTypes.contains(propertyName)) { - //取值范围不同的同名方块属性 - logger.warn("Property type \"" + propertyName + "\" has different size in different blocks!"); - differentSizePropertyTypes.insert(propertyName); - auto fullBlockName = "minecraft:" + entry.first; - if (!specialBlockTypes.contains(fullBlockName)) { - specialBlockTypes[fullBlockName] = std::map(); - } - } - } - } - - std::map globalPropertyTypeMap; - - for (auto& entry : blockToPropertyTypeMap) { - for (auto& entryInside : entry.second) { - auto& propertyName = entryInside.first; - auto& propertyType = entryInside.second; - auto keyName = std::string(propertyName); - string::size_type pos = 0; - while ((pos = keyName.find(':', pos)) != string::npos) - { - keyName.replace(pos, 1, "_"); - pos++; - } - if (!differentSizePropertyTypes.contains(propertyName)) { - globalPropertyTypeMap[keyName] = propertyType; - } - else { - auto newKey = keyName + "_" + to_string(propertyType.values.size()); - auto fullBlockName = "minecraft:" + entry.first; - specialBlockTypes[fullBlockName][keyName] = newKey; - globalPropertyTypeMap[newKey] = propertyType; - } - } - } - - auto globalJson = json::object(); - auto propertyTypes = json::object(); - - for (auto& propertyTypeEntry : globalPropertyTypeMap) { - if (propertyTypeEntry.second.serializationName.empty()) { - continue; - } - auto obj = json::object(); - - obj["serializationName"] = propertyTypeEntry.second.serializationName; - obj["valueType"] = propertyTypeEntry.second.valueType; - if (propertyTypeEntry.second.valueType == "INTEGER") { - //排序 propertyTypeEntry.second.values 中的值 - std::vector values; - for (auto& value : propertyTypeEntry.second.values) { - values.push_back(stoi(value)); - } - std::sort(values.begin(), values.end()); - obj["values"] = values; - } - else if (propertyTypeEntry.second.valueType == "BOOLEAN") { - //转换成bool - std::vector values{ false, true }; - obj["values"] = values; - } - else { - obj["values"] = propertyTypeEntry.second.values; - } - - propertyTypes[propertyTypeEntry.first] = obj; - } - globalJson["propertyTypes"] = propertyTypes; - globalJson["differentSizePropertyTypes"] = differentSizePropertyTypes; - globalJson["specialBlockTypes"] = specialBlockTypes; - writeJSON("data/block_property_types.json", globalJson); - logger.info("Block property type data have been saved to \"data/block_property_types.json\""); -} - -void dumpItemTags() { -#define DUMP(C) \ - do { \ - auto items = ItemRegistryManager::getItemRegistry().lookupByTag(VanillaItemTags::##C); \ - auto arr = nlohmann::json::array(); \ - for (auto item : items) { \ - arr.push_back(item->getFullItemName()); \ - } \ - res[VanillaItemTags::##C.getString()] = arr; \ - } while (false) - nlohmann::json res = nlohmann::json::object(); - DUMP(Armor); - DUMP(Arrows); - DUMP(Banners); - DUMP(Boat); - DUMP(Boats); - DUMP(BookshelfBooks); - DUMP(ChainmailTier); - DUMP(ChestBoat); - DUMP(Coals); - DUMP(Cooked); - DUMP(CrimsonStems); - DUMP(DecoratedPotSherds); - DUMP(DiamondTier); - DUMP(Digger); - DUMP(Door); - DUMP(Fishes); - DUMP(Food); - DUMP(GoldenTier); - DUMP(HangingActor); - DUMP(HangingSign); - DUMP(Hatchet); - DUMP(Hoe); - DUMP(HorseArmor); - DUMP(IronTier); - DUMP(LeatherTier); - DUMP(LecternBooks); - DUMP(Logs); - DUMP(LogsThatBurn); - DUMP(MangroveLogs); - DUMP(Meat); - DUMP(Minecart); - DUMP(MusicDiscs); - DUMP(NetheriteTier); - DUMP(Pickaxe); - DUMP(PiglinLoved); - DUMP(PiglinRepellents); - DUMP(Planks); - DUMP(Sand); - DUMP(Shovel); - DUMP(Sign); - DUMP(SoulFireBaseBlocks); - DUMP(SpawnEgg); - DUMP(StoneBricks); - DUMP(StoneCraftingMaterials); - DUMP(StoneTier); - DUMP(StoneToolMaterials); - DUMP(Sword); - DUMP(Tool); - DUMP(TransformMaterials); - DUMP(TransformTemplates); - DUMP(TransformableItems); - DUMP(Trident); - DUMP(TrimMaterials); - DUMP(TrimTemplates); - DUMP(TrimmableArmors); - DUMP(VibrationDamper); - DUMP(WarpedStems); - DUMP(WoodenSlabs); - DUMP(WoodenTier); - DUMP(Wool); +void dumpPropertyTypeData(const ll::Logger& logger) { + logger.info("Extracting property type data..."); + + std::map>> blockToBlockStateData; + + auto& palette = mc->getLevel()->getBlockPalette(); + for (int i = 0; i <= blockStateCounter; ++i) { + const Block& block = palette.getBlock(i); + auto name = block.getLegacyBlock().getRawNameId(); + if (!blockToBlockStateData.contains(name)) { + blockToBlockStateData[name] = std::vector>(); + } + auto& blockStates = blockToBlockStateData[name]; + if (auto nbt = block.getSerializationId().clone(); + nbt->contains("states") && !nbt->getCompound("states")->isEmpty()) { + blockStates.push_back(nbt->getCompound("states")->clone()); + } + } + + std::map> blockToPropertyTypeMap; + + for (auto& entry : blockToBlockStateData) { + auto& states = entry.second; + std::map propertyTypeMap; + + for (auto& state : states) { + for (auto& valueEntry : state->rawView()) { + if (!propertyTypeMap.contains(valueEntry.first)) { + PropertyType p; + p.serializationName = valueEntry.first; + p.blockName = entry.first; + propertyTypeMap[p.serializationName] = p; + } + auto& propertyType = propertyTypeMap[valueEntry.first]; + switch (valueEntry.second.getId()) { + case Tag::Type::Byte: + if (propertyType.valueType.empty()) { + propertyType.valueType = "BOOLEAN"; + } + propertyType.values.insert(state->getBoolean(valueEntry.first) ? "true" : "false"); + break; + case Tag::Type::Int: + if (propertyType.valueType.empty()) { + propertyType.valueType = "INTEGER"; + } + propertyType.values.insert(std::to_string(state->getInt(valueEntry.first))); + break; + case Tag::Type::String: + if (propertyType.valueType.empty()) { + propertyType.valueType = "ENUM"; + } + propertyType.values.insert(state->getString(valueEntry.first)); + break; + default: + if (propertyType.valueType.empty()) { + propertyType.valueType = "UNKNOWN"; + } + logger.warn("Unknown tag type when dumping property type data: " + valueEntry.first); + break; + } + } + } + blockToPropertyTypeMap[entry.first] = propertyTypeMap; + } + + std::set differentSizePropertyTypes; + std::map> specialBlockTypes; + std::map tmpLookUp; + + for (auto& entry : blockToPropertyTypeMap) { + for (auto& entryInside : entry.second) { + auto& propertyName = entryInside.first; + auto& propertyType = entryInside.second; + if (!tmpLookUp.contains(propertyName)) { + tmpLookUp[propertyName] = propertyType; + } else if (tmpLookUp[propertyName] != propertyType && !differentSizePropertyTypes.contains(propertyName)) { + logger.warn("Property type \"" + propertyName + "\" has different size in different blocks!"); + differentSizePropertyTypes.insert(propertyName); + auto fullBlockName = "minecraft:" + entry.first; + if (!specialBlockTypes.contains(fullBlockName)) { + specialBlockTypes[fullBlockName] = std::map(); + } + } + } + } + + std::map globalPropertyTypeMap; + + for (auto& entry : blockToPropertyTypeMap) { + for (auto& entryInside : entry.second) { + auto& propertyName = entryInside.first; + auto& propertyType = entryInside.second; + auto keyName = std::string(propertyName); + std::string::size_type pos = 0; + while ((pos = keyName.find(':', pos)) != std::string::npos) { + keyName.replace(pos, 1, "_"); + pos++; + } + if (!differentSizePropertyTypes.contains(propertyName)) { + globalPropertyTypeMap[keyName] = propertyType; + } else { + auto newKey = keyName + "_" + std::to_string(propertyType.values.size()); + auto fullBlockName = "minecraft:" + entry.first; + specialBlockTypes[fullBlockName][keyName] = newKey; + globalPropertyTypeMap[newKey] = propertyType; + } + } + } + + auto globalJson = nlohmann::json::object(); + auto propertyTypes = nlohmann::json::object(); + + for (auto& propertyTypeEntry : globalPropertyTypeMap) { + if (propertyTypeEntry.second.serializationName.empty()) { + continue; + } + auto obj = nlohmann::json::object(); + + obj["serializationName"] = propertyTypeEntry.second.serializationName; + obj["valueType"] = propertyTypeEntry.second.valueType; + if (propertyTypeEntry.second.valueType == "INTEGER") { + std::vector values; + for (auto& value : propertyTypeEntry.second.values) { + values.push_back(stoi(value)); + } + std::ranges::sort(values); + obj["values"] = values; + } else if (propertyTypeEntry.second.valueType == "BOOLEAN") { + std::vector values{false, true}; + obj["values"] = values; + } else { + obj["values"] = propertyTypeEntry.second.values; + } + + propertyTypes[propertyTypeEntry.first] = obj; + } + globalJson["propertyTypes"] = propertyTypes; + globalJson["differentSizePropertyTypes"] = differentSizePropertyTypes; + globalJson["specialBlockTypes"] = specialBlockTypes; + writeNlohmannJSON("data/block_property_types.json", globalJson); + logger.info("Block property type data have been saved to \"data/block_property_types.json\""); +} + +void dumpItemTags(const ll::Logger& logger) { + logger.info("Extracting item tags..."); + nlohmann::json res = nlohmann::json::object(); +#define DUMP(TAG) \ + do { \ + auto items = ItemRegistryManager::getItemRegistry().lookupByTag(VanillaItemTags::##TAG); \ + auto arr = nlohmann::json::array(); \ + for (auto item : items) { \ + arr.push_back(item->getFullItemName()); \ + } \ + res[VanillaItemTags::##TAG.getString()] = arr; \ + logger.info(VanillaItemTags::##TAG.getString()); \ + } while (false) + DUMP(Armor); + DUMP(Arrows); + DUMP(Banners); + DUMP(Boat); + DUMP(Boats); + DUMP(BookshelfBooks); + DUMP(ChainmailTier); + DUMP(ChestBoat); + DUMP(Coals); + DUMP(Cooked); + DUMP(CrimsonStems); + DUMP(DecoratedPotSherds); + DUMP(DiamondTier); + DUMP(Digger); + DUMP(Door); + DUMP(Fishes); + DUMP(Food); + DUMP(GoldenTier); + DUMP(HangingActor); + DUMP(HangingSign); + DUMP(Hatchet); + DUMP(Hoe); + DUMP(HorseArmor); + DUMP(IronTier); + DUMP(LeatherTier); + DUMP(LecternBooks); + DUMP(Logs); + DUMP(LogsThatBurn); + DUMP(MangroveLogs); + DUMP(Meat); + DUMP(Minecart); + DUMP(MusicDiscs); + DUMP(NetheriteTier); + DUMP(Pickaxe); + DUMP(PiglinLoved); + DUMP(PiglinRepellents); + DUMP(Planks); + DUMP(Sand); + DUMP(Shovel); + DUMP(Sign); + DUMP(SoulFireBaseBlocks); + DUMP(SpawnEgg); + DUMP(StoneBricks); + DUMP(StoneCraftingMaterials); + DUMP(StoneTier); + DUMP(StoneToolMaterials); + DUMP(Sword); + DUMP(Tool); + DUMP(TransformMaterials); + DUMP(TransformTemplates); + DUMP(TransformableItems); + DUMP(Trident); + DUMP(TrimMaterials); + DUMP(TrimTemplates); + DUMP(TrimmableArmors); + DUMP(VibrationDamper); + DUMP(WarpedStems); + DUMP(WoodenSlabs); + DUMP(WoodenTier); + DUMP(Wool); #undef DUMP - writeJSON("data/item_tags.json", res); -} - -void dumpBlockTags() { - nlohmann::json res = nlohmann::json::object(); -#define DUMP(TAG) \ - do { \ - auto arr = nlohmann::json::array(); \ - BlockTypeRegistry::forEachBlock([&arr](const BlockLegacy &b) { \ - if (b.hasTag(VanillaBlockTags::##TAG)) { \ - arr.push_back(b.getRawNameId()); \ - } \ - return true; \ - }); \ - res[VanillaBlockTags::##TAG.getString()] = arr; \ - } while (false) - DUMP(Acacia); - DUMP(Birch); - DUMP(Crop); - DUMP(DarkOak); - DUMP(DiamondDiggable); - DUMP(Dirt); - DUMP(FertilizeArea); - DUMP(GoldDiggable); - DUMP(Grass); - DUMP(Gravel); - DUMP(IronDiggable); - DUMP(Jungle); - DUMP(Log); - DUMP(Metal); - DUMP(MobSpawner); - DUMP(NotFeatureReplaceable); - DUMP(Oak); - DUMP(Plant); - DUMP(Pumpkin); - DUMP(Rail); - DUMP(Sand); - DUMP(Snow); - DUMP(Spruce); - DUMP(Stone); - DUMP(StoneDiggable); - DUMP(TextSign); - DUMP(Water); - DUMP(Wood); - DUMP(WoodDiggable); + writeNlohmannJSON("data/item_tags.json", res); +} + +void dumpBlockTags(const ll::Logger& logger) { + logger.info("Extracting block tags..."); + nlohmann::json res = nlohmann::json::object(); +#define DUMP(TAG) \ + do { \ + auto arr = nlohmann::json::array(); \ + BlockTypeRegistry::forEachBlock([&arr](const BlockLegacy& b) { \ + if (b.hasTag(VanillaBlockTags::##TAG)) { \ + arr.push_back(b.getRawNameId()); \ + } \ + return true; \ + }); \ + res[VanillaBlockTags::##TAG.getString()] = arr; \ + logger.info(VanillaBlockTags::##TAG.getString()); \ + } while (false) + DUMP(Acacia); + DUMP(Birch); + DUMP(Crop); + DUMP(DarkOak); + DUMP(DiamondDiggable); + DUMP(Dirt); + DUMP(FertilizeArea); + DUMP(GoldDiggable); + DUMP(Grass); + DUMP(Gravel); + DUMP(IronDiggable); + DUMP(Jungle); + DUMP(Log); + DUMP(Metal); + DUMP(MobSpawner); + DUMP(NotFeatureReplaceable); + DUMP(Oak); + DUMP(Plant); + DUMP(Pumpkin); + DUMP(Rail); + DUMP(Sand); + DUMP(Snow); + DUMP(Spruce); + DUMP(Stone); + DUMP(StoneDiggable); + DUMP(TextSign); + DUMP(Water); + DUMP(Wood); + DUMP(WoodDiggable); #undef DUMP - writeJSON("data/block_tags.json", res); -} \ No newline at end of file + writeNlohmannJSON("data/block_tags.json", res); +} diff --git a/src/DataExtractor.h b/src/DataExtractor.h index 5492a6ace..84b44eeb5 100644 --- a/src/DataExtractor.h +++ b/src/DataExtractor.h @@ -1,180 +1,90 @@ -#include -#include -#include -#include -#include -#include -#include "zlib.h" +// Basic #include "magic_enum.hpp" +#include "zlib.h" #include #include +#include +#include -//ll header +// LL #include "ll/memory/Hook.h" #include "ll/memory/Memory.h" +#include + +#include -//mc header +// MC header +#include "mc/ActorDefinitionIdentifier.h" +#include "mc/CreativeItemRegistry.h" #include "mc/Minecraft.h" -#include "mc/MinecraftCommands.h" -#include "mc/IDataOutput.h" +#include "mc/commands/CommandRegistry.h" +#include "mc/commands/MinecraftCommands.h" #include "mc/common/HashedString.h" -#include "mc/world/Dimension.h" +#include "mc/enums/Brightness.h" #include "mc/math/AABB.h" +#include "mc/math/BlockPos.h" #include "mc/math/Vec3.h" -#include "mc/network/CraftingDataPacket.h" +#include "mc/nbt/CompoundTag.h" +#include "mc/nbt/NbtIo.h" +#include "mc/network/AvailableCommandsPacket.h" #include "mc/network/BinaryStream.h" +#include "mc/network/CraftingDataPacket.h" #include "mc/network/ReadOnlyBinaryStream.h" -#include "mc/nbt/NbtIo.h" -#include "mc/CreativeItemRegistry.h" -#include "mc/item/ItemInstance.h" -#include "mc/item/ItemStack.h" -#include "mc/item/Item.h" -#include "mc/item/ItemRegistryManager.h" -#include "mc/item/ItemRegistryRef.h" -#include "mc/nbt/CompoundTag.h" #include "mc/util/ItemColorUtil.h" -#include "mc/world/Level.h" -#include "mc/world/BlockPalette.h" -#include "mc/world/BlockLegacy.h" -#include "mc/world/Block.h" -#include "mc/world/Experiments.h" -#include "mc/world/LevelData.h" +#include "mc/util/Spawner.h" +#include "mc/util/json/Value.h" #include "mc/world/ActorFactory.h" -#include "mc/ActorDefinitionIdentifier.h" -#include "mc/world/BiomeRegistry.h" #include "mc/world/Biome.h" -#include "mc/world/ItemTag.h" -#include "mc/world/VanillaItemTags.h" -#include "mc/world/VanillaBlockTags.h" -#include "mc/world/BlockTypeRegistry.h" +#include "mc/world/BiomeRegistry.h" +#include "mc/world/BlockPalette.h" #include "mc/world/BlockSource.h" -#include "mc/world/Mob.h" +#include "mc/world/BlockTypeRegistry.h" +#include "mc/world/Dimension.h" +#include "mc/world/Experiments.h" +#include "mc/world/Level.h" +#include "mc/world/LevelData.h" #include "mc/world/Material.h" -#include "mc/util/Spawner.h" -#include "mc/common/Brightness.h" -#include "mc/math/BlockPos.h" -#include "mc/util/json/Value.h" +#include "mc/world/Mob.h" +#include "mc/world/VanillaBlockTags.h" +#include "mc/world/VanillaItemTags.h" +#include "mc/world/block/Block.h" +#include "mc/world/block/BlockLegacy.h" +#include "mc/world/item/Item.h" +#include "mc/world/item/ItemDescriptor.h" +#include "mc/world/item/ItemInstance.h" +#include "mc/world/item/ItemRegistryManager.h" +#include "mc/world/item/ItemRegistryRef.h" +#include "mc/world/item/ItemStack.h" +#include "mc/world/item/ItemTag.h" class ServerNetworkHandler { public: - // symbol: ?handle@ServerNetworkHandler@@UEAAXAEBVNetworkIdentifier@@AEBVTextPacket@@@Z - // ֻǰΪҪ - MCVAPI void handle(class NetworkIdentifier const&, class TextPacket const&); + // symbol: ?handle@ServerNetworkHandler@@UEAAXAEBVNetworkIdentifier@@AEBVTextPacket@@@Z + // 只是前向声明这两个类作为参数,不需要导入它们 + MCVAPI void handle(class NetworkIdentifier const&, class TextPacket const&); }; struct BiomeTagIDType; struct BiomeTagSetIDType; class GetCollisionShapeInterface { public: - // prevent constructor by default - GetCollisionShapeInterface& operator=(GetCollisionShapeInterface const&); - GetCollisionShapeInterface(GetCollisionShapeInterface const&); - GetCollisionShapeInterface(); -}; - -class BigEndianStringByteOutput { - void writeBigEndianBytes(std::byte* bytes, size_t count) { - auto right = bytes + count - 1; - if (right >= bytes) { - auto left = bytes; - do { - auto tmp = *left; - *left = *right; - *right-- = tmp; - } while (left++ < right); - } - writeBytes(bytes, count); - } - -public: - virtual ~BigEndianStringByteOutput() = default; - ; - virtual void* writeString(std::string_view string_span) { - void* (*rv)(void*, std::string_view); - *((void**)&rv) = LL_RESOLVE_SYMBOL("?writeString@BytesDataOutput@@UEAAXV?$basic_string_view@DU?$char_traits@D@std@@@std@@@Z"); - return (*rv)((void*)this, std::move(string_span)); - } - - virtual void* writeLongString(std::string_view string_span) { - void* (*rv)(void*, std::string_view); - *((void**)&rv) = LL_RESOLVE_SYMBOL("?writeLongString@BytesDataOutput@@UEAAXV?$basic_string_view@DU?$char_traits@D@std@@@std@@@Z"); - return (*rv)((void*)this, std::move(string_span)); - } - virtual void writeFloat(float data) { - writeBigEndianBytes((std::byte*)&data, 4); - } - virtual void writeDouble(double data) { - writeBigEndianBytes((std::byte*)&data, 8); - } - virtual void writeByte(std::byte data) { - writeBytes(&data, 1); - } - virtual void writeShort(short data) { - writeBigEndianBytes((std::byte*)&data, 2); - } - virtual void writeInt(int data) { - writeBigEndianBytes((std::byte*)&data, 4); - } - virtual void writeLongLong(long long data) { - writeBigEndianBytes((std::byte*)&data, 8); - } - virtual void* writeBytes(std::byte* bytes, size_t count) { - void* (*rv)(void*, std::byte*, size_t); - *((void**)&rv) = LL_RESOLVE_SYMBOL("?writeBytes@StringByteOutput@@UEAAXPEBX_K@Z"); - return (*rv)((void*)this, bytes, count); - } + // prevent constructor by default + GetCollisionShapeInterface& operator=(GetCollisionShapeInterface const&); + GetCollisionShapeInterface(GetCollisionShapeInterface const&); + GetCollisionShapeInterface(); }; -class Logger { -public: - void error(const std::string& error) { - std::cout << "\033[0;1;31m" << error << "\033[0m" << std::endl; - } - - void warn(const std::string& warn) { - std::cout << "\033[0;1;33m" << warn << "\033[0m" << std::endl; - } - - void info(const std::string& info) { - std::cout << "\033[0;1;32m" << info << "\033[0m" << std::endl; - } - - void text(const std::string& info) { - std::cout << "\033[0;1;37m" << info << "\033[0m" << std::endl; - } -}; -void extractData(); - -void dumpBlockAttributesData(); - -void dumpItemData(); - -void dumpEntityData(); - -void dumpCreativeItemData(); - -void dumpPalette(); - -void dumpBlockIdToItemIdMap(); - -void dumpBiomeData(); - -void dumpCommandArgData(); - -void dumpAvailableCommand(); - -void dumpItemTags(); - -void dumpBlockTags(); - -void dumpEntityAABB(const Level* level, const std::pair& pair, - nlohmann::basic_json>& obj); - -void dumpPropertyTypeData(); - -static void writeJSON(const std::string& fileName, const Json::Value& json); - -static void writeJSON(const std::string& fileName, const nlohmann::json& json); - -static bool folderExists(std::string folderName); - -static void createFolder(std::string folderName); \ No newline at end of file +void dumpCreativeItemData(const ll::Logger& logger); +void dumpCommandNameSymbol(const ll::Logger& logger); +void dumpCommonCommandArgData(const ll::Logger& logger); +void dumpFullCommandArgData(const ll::Logger& logger); +void dumpCommandmConstrainedValues(const ll::Logger& logger); +void dumpBiomeData(const ll::Logger& logger); +void dumpBlockAttributesData(const ll::Logger& logger); +void dumpItemData(const ll::Logger& logger); +void dumpPalette(const ll::Logger& logger); +void dumpBlockTags(const ll::Logger& logger); +void dumpItemTags(const ll::Logger& logger); +void dumpPropertyTypeData(const ll::Logger& logger); + +void extractBlock(ListTag& dest, const Block& block, const ll::Logger& logger); +void extractData(); \ No newline at end of file diff --git a/src/ll/base/Concepts.h b/src/ll/base/Concepts.h index 449d792fe..1122cbb83 100644 --- a/src/ll/base/Concepts.h +++ b/src/ll/base/Concepts.h @@ -4,41 +4,52 @@ #include #include #include +#include + +#include "ll/base/Macro.h" +#include "ll/base/StdInt.h" namespace ll::concepts { -template +template static constexpr bool is_one_of_v = (std::is_same_v || ...); -template +template struct is_one_of : std::bool_constant> {}; -template +template concept IsOneOf = is_one_of_v; -template +template static constexpr bool is_all_same_v = (std::is_same_v && ...); -template +template struct is_all_same : std::bool_constant> {}; -template +template concept IsAllSame = is_all_same_v; -template -static constexpr bool is_string_v = std::convertible_to; +template +static constexpr bool is_string_v = std::is_constructible_v; + +template +constexpr bool is_non_char_integral_v = + is_one_of_v, bool, schar, uchar, short, ushort, int, uint, long, ulong, int64, uint64>; + +template +concept IsNonCharIntegral = is_non_char_integral_v; template concept IsString = is_string_v; -template class Z> -concept ConceptFor = Z::value; +template class Z> +concept Require = Z::value; -template +template concept Formattable = requires(T const& v, std::format_context ctx) { std::formatter>().format(v, ctx); }; -template +template concept IsExpected = requires(T e) { typename std::remove_cvref_t::value_type; typename std::remove_cvref_t::error_type; @@ -48,7 +59,7 @@ concept IsExpected = requires(T e) { requires std::is_same_v::value_type> || requires(T e) { e.value(); }; }; -template +template concept IsOptional = !IsExpected && requires(T o) { o.value(); o.has_value(); @@ -56,45 +67,74 @@ concept IsOptional = !IsExpected && requires(T o) { typename std::remove_cvref_t::value_type; }; -template +template concept Rangeable = requires(T t) { { t.begin() } -> std::same_as::iterator>; { t.end() } -> std::same_as::iterator>; }; -template +template concept Associative = Rangeable && requires { typename std::remove_cvref_t::key_type; typename std::remove_cvref_t::mapped_type; }; +template +concept IsDispatcher = requires(T t) { + typename std::remove_cvref_t::storage_type; + typename std::remove_cvref_t::listener_type; + t.storage; + t.call(); +}; + +struct LL_EBO VectorBaseTag {}; + template +concept IsVectorBase = std::is_base_of_v; + +template concept TupleLike = !Rangeable && requires(T t) { std::tuple_size>::value; std::get<0>(t); }; -template +template concept ArrayLike = Rangeable && !requires { typename std::remove_cvref_t::mapped_type; }; -template class Z> +template class Z> inline constexpr bool is_specialization_of_v = false; -template