#include "ClientInstance.h"
#include "Utils/MemoryUtils.h"
#include "Utils/FileUtils.h"

auto ClientInstance::getLocalPlayer() -> Player* {
	if (Utils::File::getVersion() == _("1.21.80"))
		return (reinterpret_cast<Player * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[32]))(this);
	else if (Utils::File::getVersion() == _("1.21.73"))
		return (reinterpret_cast<Player * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[30]))(this);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return (reinterpret_cast<Player * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[30]))(this);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return (reinterpret_cast<Player * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[30]))(this);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return (reinterpret_cast<Player * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[30]))(this);
	else
		return (reinterpret_cast<Player * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[30]))(this);
}

auto ClientInstance::getBlockSource() -> BlockSource* {
	if (Utils::File::getVersion() == _("1.21.80"))
		return (reinterpret_cast<BlockSource * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[31]))(this);
	else if (Utils::File::getVersion() == _("1.21.73"))
		return (reinterpret_cast<BlockSource * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[29]))(this);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return (reinterpret_cast<BlockSource * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[29]))(this);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return (reinterpret_cast<BlockSource * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[29]))(this);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return (reinterpret_cast<BlockSource * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[29]))(this);
	else
		return (reinterpret_cast<BlockSource * (__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[29]))(this);
}

auto ClientInstance::releaseMouse() -> void {
	if (Utils::File::getVersion() == _("1.21.80"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[346])(this);
	else if (Utils::File::getVersion() == _("1.21.73"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[344])(this);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[344])(this);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[344])(this);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[344])(this);
	else
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[341])(this);
}

auto ClientInstance::grabMouse() -> void {
	if (Utils::File::getVersion() == _("1.21.80"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[345])(this);
	else if (Utils::File::getVersion() == _("1.21.73"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[343])(this);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[343])(this);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[343])(this);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[343])(this);
	else
		return reinterpret_cast<void(__thiscall*)(void*)>((*reinterpret_cast<void***>(this))[340])(this);
}

auto ClientInstance::playUI(std::string str, float a1, float a2) -> void {
	if (Utils::File::getVersion() == _("1.21.80"))
		return reinterpret_cast<void(__thiscall*)(void*, std::string32, float, float)>((*reinterpret_cast<void***>(this))[353])(this, std::string32(str), a1, a2);
	else if (Utils::File::getVersion() == _("1.21.73"))
		return reinterpret_cast<void(__thiscall*)(void*, std::string32, float, float)>((*reinterpret_cast<void***>(this))[351])(this, std::string32(str), a1, a2);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return reinterpret_cast<void(__thiscall*)(void*, std::string32, float, float)>((*reinterpret_cast<void***>(this))[351])(this, std::string32(str), a1, a2);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return reinterpret_cast<void(__thiscall*)(void*, std::string32, float, float)>((*reinterpret_cast<void***>(this))[351])(this, std::string32(str), a1, a2);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return reinterpret_cast<void(__thiscall*)(void*, std::string32, float, float)>((*reinterpret_cast<void***>(this))[351])(this, std::string32(str), a1, a2);
	else
		return reinterpret_cast<void(__thiscall*)(void*, std::string32, float, float)>((*reinterpret_cast<void***>(this))[348])(this, std::string32(str), a1, a2);
}

auto ClientInstance::getMinecraftGame() -> MinecraftGame* {
	return *reinterpret_cast<MinecraftGame**>((uintptr_t)this + 0xD0);
}

auto ClientInstance::getMinecraft() -> Minecraft* {
	//return *reinterpret_cast<Minecraft**>((uintptr_t)this + 0xD8);
	return *reinterpret_cast<Minecraft**>((uintptr_t)this + 0xD8);
}

auto ClientInstance::getLevelRender() -> LevelRender* {
	return *reinterpret_cast<LevelRender**>((uintptr_t)this + 0xE8);
}

auto ClientInstance::getLoopbackPacketSender() -> LoopbackPacketSender* {
	return *reinterpret_cast<LoopbackPacketSender**>((uintptr_t)this + 0xF8);
}

auto ClientInstance::getCamera() -> mce::Camera& {
	return *reinterpret_cast<mce::Camera*>((uintptr_t)this + 0x2C8);
}

auto ClientInstance::getMatrix() -> GLMatrix {
	if (Utils::File::getVersion() == _("1.21.73"))
		return *reinterpret_cast<GLMatrix*>((uintptr_t)this + 0x388);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return *reinterpret_cast<GLMatrix*>((uintptr_t)this + 0x388);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return *reinterpret_cast<GLMatrix*>((uintptr_t)this + 0x388);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return *reinterpret_cast<GLMatrix*>((uintptr_t)this + 0x388);
	else
		return *reinterpret_cast<GLMatrix*>((uintptr_t)this + 0x368);
}

auto ClientInstance::getGuiData() -> GuiData* {
	if (Utils::File::getVersion() == _("1.21.80"))
		return *reinterpret_cast<GuiData**>((uintptr_t)this + 0x5B8);
	else if (Utils::File::getVersion() == _("1.21.73"))
		return *reinterpret_cast<GuiData**>((uintptr_t)this + 0x5B0);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return *reinterpret_cast<GuiData**>((uintptr_t)this + 0x5B0);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return *reinterpret_cast<GuiData**>((uintptr_t)this + 0x5B0);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return *reinterpret_cast<GuiData**>((uintptr_t)this + 0x5B0);
	else
		return *reinterpret_cast<GuiData**>((uintptr_t)this + 0x590);
}

auto ClientInstance::getFovX() -> float {
	if (Utils::File::getVersion() == _("1.21.73"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x748);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x748);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x748);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x748);
	else
		return *reinterpret_cast<float*>((uintptr_t)this + 0x728);
}

auto ClientInstance::getFovY() -> float {
	if (Utils::File::getVersion() == _("1.21.73"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x75C);
	else if (Utils::File::getVersion() == _("1.21.72"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x75C);
	else if (Utils::File::getVersion() == _("1.21.71"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x75C);
	else if (Utils::File::getVersion() == _("1.21.70"))
		return *reinterpret_cast<float*>((uintptr_t)this + 0x75C);
	else
		return *reinterpret_cast<float*>((uintptr_t)this + 0x73C);
}

auto ClientInstance::getScreenName() -> std::string {
	static void* sig;
	if (!sig) {
		if (Utils::File::getVersion() == _("1.21.80"))
			sig = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B EA 48 8B 01 48 8D 54 24 28 48 8B 80 58 08 00 00 FF 15 CC"));
		else if (Utils::File::getVersion() == _("1.21.73"))
			sig = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B EA 48 8B 01 48 8D 54 24 28 48 8B 80 48 08 00 00 FF 15 D4"));
		else if (Utils::File::getVersion() == _("1.21.72"))
			sig = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B EA 48 8B 01 48 8D 54 24 28 48 8B 80 48 08 00 00 FF 15 34"));
		else if (Utils::File::getVersion() == _("1.21.71"))
			sig = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B EA 48 8B 01 48 8D 54 24 28 48 8B 80 48 08 00 00 FF 15 14"));
		else if (Utils::File::getVersion() == _("1.21.70"))
			sig = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B EA 48 8B 01 48 8D 54 24 28 48 8B 80 48 08 00 00 FF 15 24"));
		else if (Utils::File::getVersion() == _("1.21.62"))
			sig = Utils::Memory::FindPattern(_("48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 60 48 8B EA 48 8B 01 48 8D 54 24 28 48 8B 80 30 08 00 00 FF 15 24"));
	}

	std::string32 name = std::string32(_(""));

	static auto function = reinterpret_cast<std::string32 & (__thiscall*)(ClientInstance*, std::string32&)>(sig);
	name = function(this, name);
	return name.c_str();
}
