#include "Client.h"

#pragma region Mods
#include "Mod/Velocity.h"
#include "Mod/KillAura.h"
#include "Mod/AntiBot.h"
#include "Mod/Regen.h"
#include "Mod/AutoPot.h"
#include "Mod/TargetStrafe.h"
#include "Mod/Teams.h"
#include "Mod/AntiRegen.h"
#include "Mod/TeleportAura.h"

#include "Mod/Watermark.h"
#include "Mod/ArrayList.h"
#include "Mod/ClickGui.h"
#include "Mod/SessionInfo.h"
#include "Mod/Keystrokes.h"
#include "Mod/Interface.h"
#include "Mod/Animations.h"
#include "Mod/ServerRotations.h"
#include "Mod/Ambience.h"
#include "Mod/NameTags.h"
#include "Mod/Trail.h"
#include "Mod/TargetInfo.h"
#include "Mod/HealthAlert.h"
#include "Mod/ESP.h"
#include "Mod/Zoom.h"
#include "Mod/NoRender.h"
#include "Mod/PlayerList.h"
#include "Mod/HurtColor.h"
#include "Mod/ItemPhysics.h"
#include "Mod/BlockESP.h"
#include "Mod/FreeLook.h"
#include "Mod/Tracers.h"
#include "Mod/Chat.h"
#include "Mod/HitEffects.h"
#include "Mod/KillEffects.h"

#include "Mod/Fly.h"
#include "Mod/Speed.h"
#include "Mod/FastStop.h"
#include "Mod/Sprint.h"
#include "Mod/Jesus.h"
#include "Mod/NoSlow.h"
#include "Mod/Step.h"
#include "Mod/Spider.h"
#include "Mod/NoFall.h"
#include "Mod/LongJump.h"
#include "Mod/InventoryMove.h"

#include "Mod/Scaffold.h"
#include "Mod/ChestStealer.h"
#include "Mod/InventoryManager.h"
#include "Mod/Timer.h"
#include "Mod/AutoTool.h"
#include "Mod/FreeCam.h"
#include "Mod/FastUse.h"
#include "Mod/InventorySync.h"

#include "Mod/Disabler.h"
#include "Mod/StaffDetector.h"


#include "Mod/AutoClicker.h"
#include "Mod/HitBoxes.h"
#include "Mod/Reach.h"
#include "Mod/SafeWalk.h"
#include "Mod/WTap.h"

#include "Mod/Test.h"
#include "Mod/ToggleSounds.h"
#include "Mod/Insults.h"
#include "Mod/MCP.h"
#include "Mod/JavaInventory.h"
#include "Mod/IRC.h"
#include "Mod/NetSkip.h"
#include "Mod/MCF.h"
#include "Mod/Sounds.h"
#include "Mod/ClientSpoofer.h"
#include "Mod/Breaker.h"
#include "Mod/FastBreak.h"
#include "Mod/DeviceSpoofer.h"
#include "Mod/SecurityFeatures.h"
#include "Mod/CheatDetector.h"
#include "Mod/AutoGG.h"
#include "Mod/RichPresence.h"
#pragma endregion

#pragma region Commands
#include "Command/HelpCommand.h"
#include "Command/ToggleCommand.h"
#include "Command/ConfigCommand.h"
#include "Command/BindsCommand.h"
#include "Command/NameCommand.h"
#include "Command/ClientNameCommand.h"
#include "Command/BottomCommand.h"
#include "Command/AdminCommand.h"
#pragma endregion

#pragma region Utils
#include "Utils/FileUtils.h"
#include "Utils/AudioUtils.h"
#include "Utils/ChatUtils.h"
#include "Utils/ConfigUtils.h"
#include "Utils/DeviceUtils.h"
#include "Utils/AuthUtils.h"
#include "Utils/SecurityUtils.h"
#include "Utils/TimeUtils.h"
#pragma endregion

#pragma region Hooks
#include "Hook/Swapchain.h"
#include "Hook/Keyboard.h"
#include "Hook/Mouse.h"
#include "Hook/ScreenViews.h"
#include "Hook/Players.h"
#include "Hook/BobHurt.h"
#include "Hook/Mobs.h"
#include "Hook/Packets.h"
#include "Hook/Actors.h"
#include "Hook/Options.h"
#include "Hook/ContainerScreenControllers.h"
#include "Hook/Dimensions.h"
#include "Hook/ClientInstances.h"
#include "Hook/GameModes.h"
#include "Hook/RenderControllers.h"
#include "Hook/TextureGroups.h"
#include "Hook/MinecraftUIRenderContexts.h"
#include "Hook/RakPeers.h"
#include "Hook/ItemRenderers.h"
#include "Hook/CameraComponents.h"
#include "Hook/UIControls.h"
#include "Hook/ConnectionRequests.h"
#pragma endregion

#pragma region Datas
#include "Datas/UserDatas.h"
#include "Datas/DeviceDatas.h"
#include "Datas/PointerDatas.h"
#include "Datas/ProgressDatas.h"
#pragma endregion

#pragma region Client Threads
void CalcTime(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            Client::playtime++;

            Sleep(1000);
        }
        }).detach();

    ExitThread(1);
}

void GetOptions(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            static int checkdelay = 0;
            if (checkdelay > 10000) {
                try {
                    std::string regkey = _("keyboard_type_") + Utils::File::getOption(_("ctrl_fullkeyboardgameplay")) + _("_key");

                    Client::optleft = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".left"))));
                    Client::optright = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".right"))));
                    Client::optback = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".back"))));
                    Client::optforward = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".forward"))));
                    Client::optjump = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".jump"))));
                    Client::optsneak = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".sneak"))));

                    Client::opthotbar1 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar1"))));
                    Client::opthotbar2 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar2"))));
                    Client::opthotbar3 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar3"))));
                    Client::opthotbar4 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar4"))));
                    Client::opthotbar5 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar5"))));
                    Client::opthotbar6 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar6"))));
                    Client::opthotbar7 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar7"))));
                    Client::opthotbar8 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar8"))));
                    Client::opthotbar9 = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".hotbar9"))));

                    Client::optinventory = static_cast<char>(std::stoi(Utils::File::getOption(regkey + _(".inventory"))));

                }
                catch (...) {}

                checkdelay = 0;
            }
            else {
                checkdelay++;
            }

            Sleep(0);
        }
        }).detach();

    ExitThread(1);
}

void ClientTick(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            if (Client::insertedMods) {
                for (Mod* mod : Client::modlist) {
                    if (Client::clientinstance)
                        mod->onClient();
                }
            }

            Sleep(0);
        }
        }).detach();
    std::thread([] {
        while (Client::running) {
            if (Client::insertedMods) {
                for (Mod* mod : Client::modlist) {
                    if (Client::clientinstance)
                        mod->onClient2();
                }
            }

            Sleep(0);
        }
        }).detach();
    std::thread([] {
        while (Client::running) {
            if (Client::insertedMods) {
                for (Mod* mod : Client::modlist) {
                    if (Client::clientinstance)
                        mod->onClient3();
                }
            }

            Sleep(0);
        }
        }).detach();
    std::thread([] {
        while (Client::running) {
            if (Client::insertedMods) {
                for (Mod* mod : Client::modlist) {
                    if (Client::clientinstance)
                        mod->onClient4();
                }
            }

            Sleep(0);
        }
        }).detach();

    ExitThread(1);
}

void GetPatchs(void* arg_1) {
    std::thread([] {
        void* iteminhandrenderer_renderitem_;
        if (Utils::File::getVersion() == _("1.21.80"))
            iteminhandrenderer_renderitem_ = Utils::Memory::FindPattern(_("8B 52 10 48 8B 01 48 8B 40 38 FF 15 34"));
        else if (Utils::File::getVersion() == _("1.21.73"))
            iteminhandrenderer_renderitem_ = Utils::Memory::FindPattern(_("8B 52 10 48 8B 01 48 8B 40 38 FF 15 50"));
        else if (Utils::File::getVersion() == _("1.21.72"))
            iteminhandrenderer_renderitem_ = Utils::Memory::FindPattern(_("8B 52 10 48 8B 01 48 8B 40 38 FF 15 80 76"));
        else if (Utils::File::getVersion() == _("1.21.71"))
            iteminhandrenderer_renderitem_ = Utils::Memory::FindPattern(_("8B 52 10 48 8B 01 48 8B 40 38 FF 15 F0"));
        else if (Utils::File::getVersion() == _("1.21.70"))
            iteminhandrenderer_renderitem_ = Utils::Memory::FindPattern(_("8B 52 10 48 8B 01 48 8B 40 38 FF 15 00"));
        else
            iteminhandrenderer_renderitem_ = Utils::Memory::FindPattern(_("8B 52 10 48 8B 01 48 8B 40 38 FF 15 20"));

        iteminhandrenderer_renderitem_ = (void*)((uintptr_t)iteminhandrenderer_renderitem_ + 2);
        std::vector<unsigned char> gBpBytes = { 0x1C };
        std::vector<unsigned char> ogBytes = { gBpBytes };

        DWORD oldProtect;
        bool patched = false;
        while (Client::running) {
            if (Client::clientinstance && Client::clientinstance->getLocalPlayer()) {
                if (!patched) {
                    std::vector<unsigned char> buffer(gBpBytes.size());
                    VirtualProtect(iteminhandrenderer_renderitem_, gBpBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
                    memcpy(buffer.data(), iteminhandrenderer_renderitem_, gBpBytes.size());
                    VirtualProtect(iteminhandrenderer_renderitem_, gBpBytes.size(), oldProtect, &oldProtect);
                    ogBytes = buffer;

                    VirtualProtect(iteminhandrenderer_renderitem_, gBpBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
                    memcpy(iteminhandrenderer_renderitem_, gBpBytes.data(), gBpBytes.size());
                    VirtualProtect(iteminhandrenderer_renderitem_, gBpBytes.size(), oldProtect, &oldProtect);

                    patched = true;
                }
            }
            else {
                if (patched) {
                    VirtualProtect(iteminhandrenderer_renderitem_, ogBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
                    memcpy(iteminhandrenderer_renderitem_, ogBytes.data(), ogBytes.size());
                    VirtualProtect(iteminhandrenderer_renderitem_, ogBytes.size(), oldProtect, &oldProtect);

                    patched = false;
                }
            }
            if (!Client::running) break;

            Sleep(0);
        }
        if (patched) {
            VirtualProtect(iteminhandrenderer_renderitem_, ogBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
            memcpy(iteminhandrenderer_renderitem_, ogBytes.data(), ogBytes.size());
            VirtualProtect(iteminhandrenderer_renderitem_, ogBytes.size(), oldProtect, &oldProtect);

            patched = false;
        }
        }).detach();

    std::thread([] {
        void* iteminhandrenderer_renderbp_;
        if (Utils::File::getVersion() == _("1.21.73"))
            iteminhandrenderer_renderbp_ = Utils::Memory::FindPattern(_("F3 0F 10 05 1F FB"));
        else if (Utils::File::getVersion() == _("1.21.72"))
            iteminhandrenderer_renderbp_ = Utils::Memory::FindPattern(_("F3 0F 10 05 4F FA"));
        else if (Utils::File::getVersion() == _("1.21.71"))
            iteminhandrenderer_renderbp_ = Utils::Memory::FindPattern(_("F3 0F 10 05 47 3D"));
        else if (Utils::File::getVersion() == _("1.21.70"))
            iteminhandrenderer_renderbp_ = Utils::Memory::FindPattern(_("F3 0F 10 05 47 3D"));
        else
            iteminhandrenderer_renderbp_ = Utils::Memory::FindPattern(_("F3 0F 10 05 54 45"));

        std::vector<unsigned char> gBpBytes = { 0x0F, 0x57, 0xC0, 0x90, 0x90, 0x90, 0x90, 0x90 };
        std::vector<unsigned char> ogBytes = { gBpBytes };

        DWORD oldProtect;
        bool patched = false;
        while (Client::running) {
            if (Client::disableSwitchAnim) {
                if (!patched) {
                    std::vector<unsigned char> buffer(gBpBytes.size());
                    VirtualProtect(iteminhandrenderer_renderbp_, gBpBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
                    memcpy(buffer.data(), iteminhandrenderer_renderbp_, gBpBytes.size());
                    VirtualProtect(iteminhandrenderer_renderbp_, gBpBytes.size(), oldProtect, &oldProtect);
                    ogBytes = buffer;

                    VirtualProtect(iteminhandrenderer_renderbp_, gBpBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
                    memcpy(iteminhandrenderer_renderbp_, gBpBytes.data(), gBpBytes.size());
                    VirtualProtect(iteminhandrenderer_renderbp_, gBpBytes.size(), oldProtect, &oldProtect);

                    patched = true;
                }
            }
            else {
                if (patched) {
                    VirtualProtect(iteminhandrenderer_renderbp_, ogBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
                    memcpy(iteminhandrenderer_renderbp_, ogBytes.data(), ogBytes.size());
                    VirtualProtect(iteminhandrenderer_renderbp_, ogBytes.size(), oldProtect, &oldProtect);

                    patched = false;
                }
            }
            if (!Client::running) break;

            Sleep(0);
        }
        if (patched) {
            VirtualProtect(iteminhandrenderer_renderbp_, ogBytes.size(), PAGE_EXECUTE_READWRITE, &oldProtect);
            memcpy(iteminhandrenderer_renderbp_, ogBytes.data(), ogBytes.size());
            VirtualProtect(iteminhandrenderer_renderbp_, ogBytes.size(), oldProtect, &oldProtect);

            patched = false;
        }

        }).detach();

    ExitThread(1);
}

void GetPointers(void* arg_1) {
    std::thread([] {
        Datas::Pointer::itemstack_getenchantvalue = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 74 24 10 57 48 81 EC 80 00 00 00 48 8B F2"));
        }).detach();

    std::thread([] {
        Datas::Pointer::itemstack_getcustomname = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 74 24 20 48 89 54 24 10 57 48 83 EC 30 48 8B DA 48 8B F1"));
        }).detach();

    std::thread([] {
        Datas::Pointer::inventory_dropslot = Utils::Memory::FindPattern(_("85 D2 0F 88 23"));
        }).detach();

    std::thread([] {
        if (Utils::File::getVersion() == _("1.21.80"))
            Datas::Pointer::containerscreencontroller_handletakeall = Utils::Memory::FindPattern(_("E8 D1 8F FE"));
        else if (Utils::File::getVersion() == _("1.21.73"))
            Datas::Pointer::containerscreencontroller_handletakeall = Utils::Memory::FindPattern(_("E8 C1 1A FD FF"));
        else if (Utils::File::getVersion() == _("1.21.72"))
            Datas::Pointer::containerscreencontroller_handletakeall = Utils::Memory::FindPattern(_("E8 C1 1A FD"));
        else if (Utils::File::getVersion() == _("1.21.71"))
            Datas::Pointer::containerscreencontroller_handletakeall = Utils::Memory::FindPattern(_("E8 C1 1A FD"));
        else if (Utils::File::getVersion() == _("1.21.70"))
            Datas::Pointer::containerscreencontroller_handletakeall = Utils::Memory::FindPattern(_("E8 C1 1A FD"));
        else
            Datas::Pointer::containerscreencontroller_handletakeall = Utils::Memory::FindPattern(_("E8 D1 72 FC FF 49"));

        uintptr_t out = (uintptr_t)Datas::Pointer::containerscreencontroller_handletakeall;
        out += 5 + *reinterpret_cast<int*>(out + 1);
        Datas::Pointer::containerscreencontroller_handletakeall = (void*)out;
        }).detach();

    std::thread([] {
		if (Utils::File::getVersion() == _("1.21.80"))
			Datas::Pointer::gamemode_baseuseitem = Utils::Memory::FindPattern(_("48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 90 48 81 EC 70 01 00 00 48 8B 05 BF DB"));
		else if (Utils::File::getVersion() == _("1.21.73"))
			Datas::Pointer::gamemode_baseuseitem = Utils::Memory::FindPattern(_("48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 90 48 81 EC 70 01 00 00 48 8B 05 BF"));
		else if (Utils::File::getVersion() == _("1.21.72"))
			Datas::Pointer::gamemode_baseuseitem = Utils::Memory::FindPattern(_("48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 90 48 81 EC 70 01 00 00 48 8B 05 DF"));
		else if (Utils::File::getVersion() == _("1.21.71"))
            Datas::Pointer::gamemode_baseuseitem = Utils::Memory::FindPattern(_("48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 90 48 81 EC 70 01 00 00 48 8B 05 3F"));
		else if (Utils::File::getVersion() == _("1.21.70"))
            Datas::Pointer::gamemode_baseuseitem = Utils::Memory::FindPattern(_("48 89 5C 24 10 48 89 74 24 18 55 57 41 56 48 8D 6C 24 90 48 81 EC 70 01 00 00 48 8B 05 7F"));
		else {
            Datas::Pointer::gamemode_baseuseitem = Utils::Memory::FindPattern(_("E8 52 5F FA"));

			uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_baseuseitem;
			out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_baseuseitem = (void*)out;
		}
        }).detach();

    std::thread([] {
        if (Utils::File::getVersion() == _("1.21.80")) {
            Datas::Pointer::gamemode_getdestroyrate = Utils::Memory::FindPattern(_("E8 65 52 00 00 0F"));

            uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_getdestroyrate;
            out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_getdestroyrate = (void*)out;
        }
        else if (Utils::File::getVersion() == _("1.21.73")) {
            Datas::Pointer::gamemode_getdestroyrate = Utils::Memory::FindPattern(_("E8 75 52 00"));

            uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_getdestroyrate;
            out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_getdestroyrate = (void*)out;
        }
        else if (Utils::File::getVersion() == _("1.21.72")) {
            Datas::Pointer::gamemode_getdestroyrate = Utils::Memory::FindPattern(_("E8 75 52 00"));

            uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_getdestroyrate;
            out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_getdestroyrate = (void*)out;
        }
        else if (Utils::File::getVersion() == _("1.21.71")) {
            Datas::Pointer::gamemode_getdestroyrate = Utils::Memory::FindPattern(_("E8 75 52 00"));

            uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_getdestroyrate;
            out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_getdestroyrate = (void*)out;
        }
        else if (Utils::File::getVersion() == _("1.21.70")) {
            Datas::Pointer::gamemode_getdestroyrate = Utils::Memory::FindPattern(_("E8 75 52 00"));

            uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_getdestroyrate;
            out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_getdestroyrate = (void*)out;
        }
        else {
            Datas::Pointer::gamemode_getdestroyrate = Utils::Memory::FindPattern(_("E8 F1 53 00 00 0F"));

            uintptr_t out = (uintptr_t)Datas::Pointer::gamemode_getdestroyrate;
            out += 1 + sizeof(float) + *reinterpret_cast<int*>(out + 1);
            Datas::Pointer::gamemode_getdestroyrate = (void*)out;
        }
        }).detach();

    ExitThread(1);
}

void AutoSave(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            Sleep(500);
            if (Client::running)
                Utils::Config::SaveConfig(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs\\") + Client::configName + _(".txt"), Client::configName, false);
            Sleep(500);
        }
        }).detach();

    ExitThread(1);
}

void CrashSeen(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            if (Client::crash) {
                Sleep(50);
                std::abort();
            }

            Sleep(0);
        }
        }).detach();

    ExitThread(1);
}

void CheckStatus(void* arg_1) {
    std::thread([] {
        char buffer[1024];
        while (Client::running) {
            int data = recv(Utils::Security::clientsocket, buffer, sizeof(buffer) - 1, 0);
            if (data <= 0) continue;

            buffer[data] = '\0';
            std::string message(buffer);

            try {
                nlohmann::json j = nlohmann::json::parse(message);
                if (j.contains(_("Status"))) {
                    if (j[_("Status")] == _("Success")) {
                        if (Client::lastadmincommandline1 == _("crash")) {
                            Utils::Chat::display(_("Crashed ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }

                        else if (Client::lastadmincommandline1 == _("eject")) {
                            Utils::Chat::display(_("Ejected ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }

                        else if (Client::lastadmincommandline1 == _("freeze")) {
                            Utils::Chat::display(_("Froze ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }
                        else if (Client::lastadmincommandline1 == _("unfreeze")) {
                            Utils::Chat::display(_("Unfroze ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }

                        else if (Client::lastadmincommandline1 == _("dropfps")) {
                            Utils::Chat::display(_("Dropped Fps ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }
                        else if (Client::lastadmincommandline1 == _("undropfps")) {
                            Utils::Chat::display(_("Undropped Fps ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }


                        else if (Client::lastadmincommandline1 == _("fling")) {
                            Utils::Chat::display(_("Flong ") + Client::lastadmincommandline2, Utils::Chat::Type::GREEN);
                        }

                        else if (Client::lastadmincommandline1 == _("joinirc")) {
                            Utils::Chat::display(_("Joined ") + Client::lastadmincommandline2 + _(" to IRC Chat"), Utils::Chat::Type::GREEN);
                        }
                        else if (Client::lastadmincommandline1 == _("kickirc")) {
                            Utils::Chat::display(_("Kicked ") + Client::lastadmincommandline2 + _(" from IRC Chat"), Utils::Chat::Type::GREEN);
                        }
                    }
                    if (j[_("Status")] == _("Faild")) {
                        Utils::Chat::display(_("Cloudn't find user: ") + Client::lastadmincommandline2, Utils::Chat::Type::RED);
                    }
                }

                if (j.contains(_("Message"))) {
                    if (j[_("Message")] == _("CRASH")) {
                        Utils::Chat::display(_("Crashed by admin"), Utils::Chat::Type::RED);
                        Client::crash = true;
                    }

                    else if (j[_("Message")] == _("EJECT")) {
                        Utils::Chat::display(_("Ejected by admin"), Utils::Chat::Type::RED);
                        Client::running = false;
                    }

                    else if (j[_("Message")] == _("FREEZE")) {
                        Utils::Chat::display(_("Freezed by admin"), Utils::Chat::Type::RED);
                        Client::forceCancelinputs = true;
                    }
                    else if (j[_("Message")] == _("UNFREEZE")) {
                        Utils::Chat::display(_("Unfreezed by admin"), Utils::Chat::Type::GREEN);
                        Client::forceCancelinputs = false;
                    }

                    else if (j[_("Message")] == _("DROPFPS")) {
                        Utils::Chat::display(_("Fps dopped by admin"), Utils::Chat::Type::RED);
                        Client::dropfps = true;
                    }
                    else if (j[_("Message")] == _("UNDROPFPS")) {
                        Utils::Chat::display(_("Undropped fps by admin"), Utils::Chat::Type::GREEN);
                        Client::dropfps = false;
                    }


                    else if (j[_("Message")] == _("FLING")) {
                        Utils::Chat::display(_("Flung by admin"), Utils::Chat::Type::GREEN);
                        Client::fling = true;
                    }

                    else if (j[_("Message")] == _("JOINIRC")) {
                        Utils::Chat::display(_("Joined to irc by admin"), Utils::Chat::Type::GREEN);

                        Client::joinirc = true;
                    }

                    else if (j[_("Message")] == _("KICKIRC")) {
                        Utils::Chat::display(_("Kicked from irc by admin"), Utils::Chat::Type::RED);

                        Client::kickirc = true;
                    }
                }

                if (j.is_array()) {
                    std::vector<Client::UserData> users;
                    
                    for (const auto& item : j) {
                        if (item.contains(_("username")) && item.contains(_("mcid"))) {
                            if (item[_("mcid")].empty())
                                continue;

                            Client::UserData data;
                            data.username = item[_("username")];
                            data.mcid = item[_("mcid")];
                            users.push_back(data);
                        }
                    }
                    Client::users = users;
                }

            }
            catch (const std::exception& e) {
                //std::cout << _("Shit ") << e.what();
            }
            Sleep(1000);
        }
        }).detach();

    ExitThread(1);
}

void CheckUsers(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            // send mcid
            {
                static std::string lastmcid = "";
                if (Client::clientinstance && Client::clientinstance->getLocalPlayer() && Client::screenName != _("start_screen")) {
                    std::string name = Client::clientinstance->getLocalPlayer()->getLocalNameTag();
                    if (lastmcid != name) {
                        if (Client::running) 
                            Utils::Security::sendcommand(_("SETMCID ") + name);
                        lastmcid = name;
                    }
                }
            }

            Sleep(250);

            if (Client::running) {
                Utils::Security::sendcommand(_("GET_USER_LIST"));

                Sleep(250);
            }
        }
        }).detach();
    ExitThread(1);
}

void CheckServer(void* arg_1) {
    std::thread([] {
        while (Client::running) {
            fd_set readset;
            FD_ZERO(&readset);
            FD_SET(Utils::Security::clientsocket, &readset);
            timeval timeout;
            timeout.tv_sec = static_cast<long>(0.0001);
            timeout.tv_usec = static_cast<long>(0.0001);

            if (select(static_cast<int>(Utils::Security::clientsocket) + 1, &readset, 0, 0, &timeout) > 0) {
                if (FD_ISSET(Utils::Security::clientsocket, &readset)) {
                    char buf[1];
                    int data = recv(Utils::Security::clientsocket, buf, sizeof(buf), MSG_PEEK);
                    
                    long long now = Utils::Time::getMs();
                    static long long start = now;
                    static bool queue = false;
                    if (data == 0 || data == -1) {
                        if (!queue)
                            Client::notifications.push_back({ Datas::Language::get().notifications.information, Datas::Language::get().notifications.notification_disconnectwillbe1minutes, 10.f, 200.f});

                        queue = true;
                        
                        if (queue) {
                            if (!Utils::Security::start())
                                Utils::Security::end();
                            else
                                continue;
                        }

                        if (now - start >= 60000.f) {
                            Utils::Chat::display(Datas::Language::get().messages.disconnected, Utils::Chat::Type::RED, Utils::Chat::PrefixType::VALKYRIE);
                            Client::running = false;
                        }
                    }
                    else {
                        if (queue) {
                            Utils::Security::setup();
                            Client::notifications.push_back({ Datas::Language::get().notifications.information, Datas::Language::get().notifications.notification_connected, 10.f });
                            queue = false;
                        }
                        start = now;
                    }
                }
            }

            Sleep(1000);
        }
        }).detach();
    ExitThread(1);
}
#pragma endregion

void Shutdown(void* arg_1) {
    while (Client::running) {
        Sleep(0);
    }

    //Utils::Auth::end();
    Utils::Security::end();

    kiero::shutdown();

    MH_DisableHook(MH_ALL_HOOKS);
    MH_RemoveHook(MH_ALL_HOOKS);

    ShowWindow(GetConsoleWindow(), SW_HIDE);

    auto zoomMod = Client::findMod<Zoom>(_("Zoom"));
    if (zoomMod)
        zoomMod->enabled = false;

    auto playerlistMod = Client::findMod<PlayerList>(_("Player List"));
    if (playerlistMod)
        playerlistMod->enabled = false;

    //Utils::Config::SaveConfig(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs\\") + Client::configName + _(".txt"), Client::configName);

    for (Mod* mod : Client::modlist) {
        if (mod->enabled) {
            mod->enabled = false;
            mod->onDisabled();
        }
    }

    Utils::Audio::playmc(_("beacon.deactivate"), 1.f, 1.f);
    //Utils::Chat::display(_("Ejected."), Utils::Chat::Type::RED);

    {
        auto clientinstance = Client::clientinstance;
        if (clientinstance) {
            auto localplayer = clientinstance->getLocalPlayer();
            if (localplayer) {
                auto actorwalkanimationcomponent = localplayer->getActorWalkAnimationComponent();
                if (actorwalkanimationcomponent)
                    actorwalkanimationcomponent->mWalkAnimSpeedMultiplier = 1.f;
            }
        }
    }

    Sleep(1000);

    FreeLibraryAndExitThread(reinterpret_cast<HMODULE>(arg_1), 1);
}


void Run(void* arg_1) {
#ifdef _DEBUG
    if (!GetConsoleWindow()) {
        AllocConsole();
        freopen_s((FILE**)stdout, _("conout$"), _("w"), stdout);
    }
    else {
        std::cout << _("==============\n");
        ShowWindow(GetConsoleWindow(), SW_SHOW);
    }
#endif

    if (MH_Initialize() != MH_OK) {
        MessageBoxA(0, _("The program was terminated due to an error.\nError code: 0-0"), _("Valkyrie"), MB_ICONERROR);

        Client::running = false;
        ExitThread(1);
    }

    CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(Shutdown), reinterpret_cast<HMODULE>(arg_1), 0, 0);

    if (/*Utils::File::getVersion() != _("1.21.80") &&*/
        Utils::File::getVersion() != _("1.21.73") &&
        Utils::File::getVersion() != _("1.21.72") &&
        Utils::File::getVersion() != _("1.21.71") &&
        Utils::File::getVersion() != _("1.21.70") &&
        Utils::File::getVersion() != _("1.21.62")) {
        MessageBoxA(0, _("Your version is not supported."), _("Error"), MB_ICONERROR);

        Client::running = false;
        ExitThread(1);
    }

    Hooks::Swapchain::Init();
    Hooks::ScreenViews::Init();
    Hooks::Keyboard::Init();
    Hooks::Mouse::Init();

    while (Hooks::Swapchain::state == -1 ||
        Hooks::ScreenViews::state == -1 ||
        Hooks::Keyboard::state == -1 ||
        Hooks::Mouse::state == -1
        )
    {
        Sleep(0);
    }

    if (Hooks::Swapchain::state == 0 ||
        Hooks::ScreenViews::state == 0 ||
        Hooks::Keyboard::state == 0 ||
        Hooks::Mouse::state == 0
        )
    {
        Client::running = false;
        return;
    }

    /*
    while (Client::selectedClient == -1) {
        if (!Client::running) break;
        Sleep(0);
    }
    if (!Client::running) ExitThread(1);
    */

    
    {
        if (!std::filesystem::exists(Utils::File::getRoamingState() + _("\\Valkyrie")))
            std::filesystem::create_directory(Utils::File::getRoamingState() + _("\\Valkyrie"));
    }

    if (false)
    {
        {
            Datas::Device::id = Utils::Device::getUserSid();
            Utils::Auth::readfile(Utils::File::getRoamingState() + _("\\Valkyrie\\Credentials.txt"));
        }

        {
            {
                Datas::Progress::start = true;
            }

            if (!Utils::Auth::start()) {
                Utils::Chat::display(_("Server is down."), Utils::Chat::Type::RED);

                Client::running = false;
                ExitThread(1);
            }



            if (Utils::Auth::login(Datas::Device::id, Datas::User::FileInfo::u_key, Datas::User::FileInfo::u_name)) {
                Utils::Auth::end();
                if (!Utils::Auth::local)
                    Sleep(2000);
                Datas::User::logged = true;
            }
            else {
                if (Utils::Auth::create(Datas::Device::id, Datas::User::FileInfo::u_key, Datas::User::FileInfo::u_name)) {
                    Utils::Auth::end();
                    Utils::Auth::start();
                    if (Utils::Auth::login(Datas::Device::id, Datas::User::FileInfo::u_key, Datas::User::FileInfo::u_name)) {
                        Utils::Auth::end();
                        if (!Utils::Auth::local)
                            Sleep(2000);
                        Datas::User::logged = true;
                    }
                }
                else {
                    if (Utils::Auth::laststatus == 1)
                        Utils::Chat::display(_("Your username cannot use."), Utils::Chat::Type::RED);
                    else
                        Utils::Chat::display(_("Your Credentials Information not found."), Utils::Chat::Type::RED);

                    Client::running = false;
                    ExitThread(1);
                }
            }
        }
    }
    else {
        Sleep(1000);
        Datas::User::name = "Guest";
        Datas::User::role = Datas::User::Role::Member;
        Datas::User::logged = true;
    }

    if (false)
    {
        if (!Utils::Security::start()) {
            Utils::Chat::display(_("Second Server is down."), Utils::Chat::Type::RED);

            Client::running = false;
            ExitThread(1);
        }

        Utils::Security::setup();

        CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(CheckStatus), reinterpret_cast<HMODULE>(arg_1), 0, 0);
        CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(CheckUsers), reinterpret_cast<HMODULE>(arg_1), 0, 0);
        CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(CheckServer), reinterpret_cast<HMODULE>(arg_1), 0, 0);
        CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(CrashSeen), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    }

    CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(CalcTime), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(GetOptions), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(ClientTick), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(GetPatchs), reinterpret_cast<HMODULE>(arg_1), 0, 0);

    CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(GetPointers), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    

    {
        Client::modlist = {
            new Velocity(),
            new KillAura(),
            new AntiBot(),
            new Regen(),
            new AutoPot(),
            new TargetStrafe(),
            new Teams(),
            new AntiRegen(),
            new TeleportAura(),

            new Watermark(),
            new ArrayList(),
            new ClickGui(),
            new SessionInfo(),
            new Keystrokes(),
            new Interface(),
            new Animations(),
            new ServerRotations(),
            new Ambience(),
            new NameTags(),
            new Trail(),
            new TargetInfo(),
            new HealthAlert(),
            new ESP(),
            new Zoom(),
            new NoRender(),
            new PlayerList(),
            new HurtColor(),
            new ItemPhysics(),
            new BlockESP(),
            new FreeLook(),
            new Tracers(),
            new Chat(),
            new HitEffects(),
            new KillEffects(),

            new Fly(),
            new Speed(),
            new FastStop(),
            new Sprint(),
            new Jesus(),
            new NoSlow(),
            new Step(),
            new Spider(),
            new NoFall(),
            new LongJump(),
            new InventoryMove(),

            new Scaffold(),
            new ChestStealer(),
            new InventoryManager(),
            new Timer(),
            new AutoTool(),
            new FreeCam(),
            new FastUse(),
            new InventorySync(),

            new Disabler(),
            new StaffDetector(),

            new AutoClicker(),
            new HitBoxes(),
            new Reach(),
            new SafeWalk(),
            new WTap(),

            new ToggleSounds(),
            new Insults(),
            new MCP(),
            new JavaInventory(),
            //new IRC(),
            new NetSkip(),
            new MCF(),
            new Sounds(),
            new ClientSpoofer(),
            new Breaker(),
            new FastBreak(),
            new DeviceSpoofer(),
            new SecurityFeatures(),
            new CheatDetector(),
            new AutoGG(),
            new RichPresence()
        };

        if (Datas::User::role == Datas::User::Role::Developer) {
            Client::modlist.push_back(new Test());
        }

        Client::commandlist = {
            new HelpCommand(),
            new ToggleCommand(),
            new ConfigCommand(),
            new BindsCommand(),
            new NameCommand(),
            new BottomCommand()
        };

        if (Datas::User::role == Datas::User::Role::Developer) {
            Client::commandlist.push_back(new ClientNameCommand());
            Client::commandlist.push_back(new AdminCommand());
        }

        Client::insertedMods = true;
    }

    Hooks::Players::Init();
    Hooks::BobHurt::Init();
    Hooks::Mobs::Init();
    Hooks::Packets::Init();
    Hooks::Actors::Init();
    Hooks::Options::Init();
    Hooks::ContainerScreenControllers::Init();
    Hooks::Dimensions::Init();
    Hooks::ClientInstances::Init();
    Hooks::GameModes::Init();
    Hooks::RenderControllers::Init();
    Hooks::TextureGroups::Init();
    //Hooks::MinecraftUIRenderContexts::Init();
    Hooks::RakPeers::Init();
    Hooks::ItemRenderers::Init();
    Hooks::CameraComponents::Init();
    Hooks::UIControls::Init();
    Hooks::ConnectionRequests::Init();

    Utils::Audio::playmc(_("beacon.activate"), 1.f, 1.f);

    //Utils::Chat::display(_("Injected!"), Utils::Chat::Type::GREEN);
    

    {
        if (!std::filesystem::exists(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs")))
            std::filesystem::create_directory(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs"));

        if (!Utils::Config::LoadConfig(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs\\Default.txt"), _("Default"), false)) {
            Utils::Config::SaveConfig(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs\\Default.txt"), _("Default"), false);
            Utils::Config::LoadConfig(Utils::File::getRoamingState() + _("\\Valkyrie\\Configs\\Default.txt"), _("Default"), false);
        }
    }

    //CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(AutoSave), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    
    //Client::notifications.push_back({ _("Information"), _("Injected!"), 3.f });

    ExitThread(1);
}

int __stdcall DllMain(void* arg_1, unsigned long arg_2, void* arg_3) {
    if (arg_2 == 1) {
        DisableThreadLibraryCalls(reinterpret_cast<HMODULE>(arg_1));


        CreateThread(0, 0, reinterpret_cast<LPTHREAD_START_ROUTINE>(Run), reinterpret_cast<HMODULE>(arg_1), 0, 0);
    }

    return 1;
}

