 #define COMMAND_REGISTRY_EXTRA
 #include <MC/CommandRegistry.hpp>
 #include <MC/CommandParameterData.hpp>
 #include <MC/AvailableCommandsPacket.hpp>
 #include <vector>
 #include <RegCommandAPI.h>
 #include <LoggerAPI.h>
 static_assert(offsetof(CommandParameterData, options) == 73);
 static_assert(offsetof(CommandParameterData, name) == 16);
 static_assert(offsetof(CommandParameterData, unk56) == 56);
 static_assert(offsetof(CommandRegistry::Overload, versionOffset) == 40);
 static_assert(sizeof(CommandRegistry::Overload) == 48);
 static_assert(offsetof(CommandRegistry::Signature, alt_symbol) == 96);
 static_assert(sizeof(CommandRegistry::Signature) == 120);
 /*
 void CommandRegistry::registerOverload(std::string const& name, Overload::FactoryFn factory, std::vector<CommandParameterData>&& args)
 {
     Signature* signature = const_cast<Signature*>(findCommand(name));
     auto& overload = signature->overloads.emplace_back(CommandVersion{}, factory, std::move(args));
     registerOverloadInternal(*signature, overload);
 }*/

 extern Logger logger;

 CommandRegistry::Overload::Overload(CommandVersion version,
                                     FactoryFn factory,
                                     std::vector<CommandParameterData>&& args)
 : version(version)
 , factory(factory)
 , params(std::forward<std::vector<CommandParameterData>>(args))
 , versionOffset(255){};

 CommandRegistry::Overload::~Overload(){};

 std::vector<std::string> CommandRegistry::getEnumNames() {
     if (!Global<CommandRegistry>)
         return {};
     std::vector<std::string> results;
     for (auto& e : Global<CommandRegistry>->mEnums)
         results.push_back(e.name);
     return results;

     auto packet = Global<CommandRegistry>->serializeAvailableCommands();
     return packet.getEnumNames();
 }
 std::vector<std::string> CommandRegistry::getSoftEnumNames() {
     if (!Global<CommandRegistry>)
         return {};
     std::vector<std::string> results;
     for (auto& e : Global<CommandRegistry>->mSoftEnums)
         results.push_back(e.name);
     return results;

     auto packet = Global<CommandRegistry>->serializeAvailableCommands();
     return packet.getEnumNames();
 }
 std::vector<std::string> CommandRegistry::getEnumValues(std::string const& name) {
     if (!Global<CommandRegistry>)
         return {};
     std::vector<std::string> results;
     auto& enums = Global<CommandRegistry>->mEnums;
     auto iter = std::find_if(enums.begin(), enums.end(), [&](CommandRegistry::Enum const& r) { return r.name == name; });
     if (iter == enums.end())
         return results;
     for (auto& i : iter->values)
         results.push_back(Global<CommandRegistry>->mEnumValues.at(std::get<3>(i)));
     return results;

     auto packet = Global<CommandRegistry>->serializeAvailableCommands();
     return packet.getEnumValues(name);
 }
 std::vector<std::string> CommandRegistry::getSoftEnumValues(std::string const& name) {
     if (!Global<CommandRegistry>)
         return {};
     std::vector<std::string> results;
     auto& enums = Global<CommandRegistry>->mSoftEnums;
     auto iter = std::find_if(enums.begin(), enums.end(), [&](CommandRegistry::SoftEnum const& r) { return r.name == name; });
     if (iter != enums.end())
         return iter->list;
     return {};

     auto packet = Global<CommandRegistry>->serializeAvailableCommands();
     return packet.getEnumValues(name);
 }
 std::string CommandRegistry::getCommandFullName(std::string const& name) {
     if (!Global<CommandRegistry>)
         return "";
     auto sig = Global<CommandRegistry>->findCommand(name);
     if (sig)
         return sig->name;
     return "";
 }

 #include <Main/Config.h>
 bool CommandRegistry::unregisterCommand(std::string const& name) {
     if (!LL::globalConfig.debugMode) {
         logger.error("unregister command is only enabled in debug mode");
         return false;
     }
     logger.warn("Unregister Command \"{}\"!", name);
     try {
         auto command = getCommandFullName(name);
         if (command.empty())
             return false;
         auto alias = getAliases(name);
         auto aliasKey = command + "CommandAliases";
         static size_t removeIndex = 0;
         auto iter = std::find_if(mEnums.begin(), mEnums.end(), [](Enum const& e) { return e.name == "CommandName"; });
         for (auto i = iter->values.begin(); i != iter->values.end();) {
             auto& enumValue = mEnumValues.at(std::get<3>(*i));
             if (enumValue == command || std::find(alias.begin(), alias.end(), enumValue) != alias.end()) {
                 mEnumValueLookup.erase(enumValue);
                 i = iter->values.erase(i);
                 enumValue = fmt::format("removed_{}", removeIndex++);
             } else {
                 ++i;
             }
         }
         auto aliasIter = std::find_if(mEnums.begin(), mEnums.end(), [&aliasKey](Enum const& e) { return e.name == aliasKey; });
         if (aliasIter != mEnums.end()) {
             aliasIter->values.clear();
             mEnumLookup.erase(aliasIter->name);
             aliasIter->name = fmt::format("removed_{}", removeIndex++);
         }
         auto sig = mSignatures.find(command);
         if (sig == mSignatures.end())
             return false;
         {
             auto iter = std::remove_if(mCommandSymbols.begin(), mCommandSymbols.end(),
                                        [&](Symbol const& r) { return r == sig->second.main_symbol || r == sig->second.alt_symbol; });
             if (iter != mCommandSymbols.end())
                 mCommandSymbols.erase(iter, mCommandSymbols.end());
         }
         //{
         //    auto iter = std::remove_if(mRules.begin(), mRules.end(),
         //                               [&](ParseRule const& r) { return r.sym == sig->second.main_symbol || r.sym == sig->second.alt_symbol; });
         //    if (iter == mRules.end())
         //        mRules.erase(iter, mRules.end());
         //};
         {
             auto iter = std::remove_if(mFactorizations.begin(), mFactorizations.end(),
                                        [&](Factorization const& r) { return r.sym == sig->second.main_symbol || r.sym == sig->second.alt_symbol; });
             if (iter != mFactorizations.end())
                 mFactorizations.erase(iter, mFactorizations.end());
         };

         mSignatures.erase(sig);
         mAliases.erase(command);
         return true;
     } catch (...) {
         logger.error("Error in CommandRegistry::unregisterCommand");
     }
     return false;
 }

 inline void CommandRegistry::printAll() const {
     logger.error("mRules");
     for (auto& rule : mRules) {
         logger.warn("{}", rule.toDebugString());
     }
     logger.error("mParseTableMap");
     for (auto& [key, table] : mParseTableMap) {
         logger.warn("{}: {}", key, table.toDebugString());
     }
     logger.error("mOptionals");
     for (auto& optional : mOptionals) {
         logger.warn("{}", optional.toDebugString());
     }
     logger.error("mEnums");
     for (auto& en : mEnums) {
         logger.warn("{}", en.toDebugString());
     }
     logger.error("mFactorizations");
     for (auto& i : mFactorizations) {
         logger.warn("{}", i.toDebugString());
     }
     logger.error("mCommandSymbols");
     for (auto& i : mCommandSymbols) {
         logger.warn("{}", i.toDebugString());
     }
     logger.error("mSignatures");
     for (auto& [k, v] : mSignatures) {
         logger.warn("{}: {}", k, v.toDebugString());
     }
     logger.error("mConstrainedValues");
     for (auto& i : mConstrainedValues) {
         logger.warn("{}", i.toDebugString());
     }
 }
 inline void CommandRegistry::printSize() const {
     static auto log = std::unordered_map<std::string, std::string>{
         {"mRules                   ", ""},
         {"mParseTableMap           ", ""},
         {"mOptionals               ", ""},
         {"mEnumValues              ", ""},
         {"mEnums                   ", ""},
         {"mFactorizations          ", ""},
         {"mPostfixes               ", ""},
         {"mEnumLookup              ", ""},
         {"mEnumValueLookup         ", ""},
         {"mCommandSymbols          ", ""},
         {"mSignatures              ", ""},
         {"mTypeLookup              ", ""},
         {"unk376                   ", ""},
         {"mAliases                 ", ""},
         {"mSemanticConstraints     ", ""},
         {"mSemanticConstraintLookup", ""},
         {"mConstrainedValues       ", ""},
         {"mConstrainedValueLookup  ", ""},
         {"mSoftEnums               ", ""},
         {"mSoftEnumLookup          ", ""},
         {"mStateStack              ", ""},
         {"mEnumsValues             ", ""},
         {"mConstrainedValuesValues ", ""},
     };
     auto mEnumsValuesSize = ([&]() -> size_t {
         size_t size = 0;
         for (auto& i : mEnums) {
             size += i.values.size();
         }
         return size;
     })();
     auto mConstrainedValuesSize = ([&]() -> size_t {
         size_t size = 0;
         for (auto& i : mConstrainedValues) {
             size += i.mConstraints.size();
         }
         return size;
     })();
     log["mRules                   "].append(fmt::format(", {:4}", mRules.size()));
     log["mParseTableMap           "].append(fmt::format(", {:4}", mParseTableMap.size()));
     log["mOptionals               "].append(fmt::format(", {:4}", mOptionals.size()));
     log["mEnumValues              "].append(fmt::format(", {:4}", mEnumValues.size()));
     log["mEnums                   "].append(fmt::format(", {:4}", mEnums.size()));
     log["mFactorizations          "].append(fmt::format(", {:4}", mFactorizations.size()));
     log["mPostfixes               "].append(fmt::format(", {:4}", mPostfixes.size()));
     log["mEnumLookup              "].append(fmt::format(", {:4}", mEnumLookup.size()));
     log["mEnumValueLookup         "].append(fmt::format(", {:4}", mEnumValueLookup.size()));
     log["mCommandSymbols          "].append(fmt::format(", {:4}", mCommandSymbols.size()));
     log["mSignatures              "].append(fmt::format(", {:4}", mSignatures.size()));
     log["mTypeLookup              "].append(fmt::format(", {:4}", mTypeLookup.size()));
     log["unk376                   "].append(fmt::format(", {:4}", unk376.size()));
     log["mAliases                 "].append(fmt::format(", {:4}", mAliases.size()));
     log["mSemanticConstraints     "].append(fmt::format(", {:4}", mSemanticConstraints.size()));
     log["mSemanticConstraintLookup"].append(fmt::format(", {:4}", mSemanticConstraintLookup.size()));
     log["mConstrainedValues       "].append(fmt::format(", {:4}", mConstrainedValues.size()));
     log["mConstrainedValueLookup  "].append(fmt::format(", {:4}", mConstrainedValueLookup.size()));
     log["mSoftEnums               "].append(fmt::format(", {:4}", mSoftEnums.size()));
     log["mSoftEnumLookup          "].append(fmt::format(", {:4}", mSoftEnumLookup.size()));
     log["mStateStack              "].append(fmt::format(", {:4}", mStateStack.size()));
     log["mEnumsValues             "].append(fmt::format(", {:4}", mEnumsValuesSize));
     log["mConstrainedValuesValues "].append(fmt::format(", {:4}", mConstrainedValuesSize));
     for (auto& [k, v] : log) {
         logger.warn("{}{}", k, v);
     }
 }