#include "URedirection.h"

void WINAPI AllObjects (struct FFrame& Stack, void* Result)
{
	guard(AllObjects)

	orgAllObjects(Stack, Result);

	unguard
}

void WINAPI GetReferencers (struct FFrame& Stack, void* Result)
{
	guard(GetReferencers)

	orgGetReferencers(Stack, Result);

	unguard
}

void WINAPI ActorCommand (struct FFrame& Stack, void* Result)
{
	guard(ActorCommand)

	P_GET_STR(Command)
	P_GET_UBOOL_OPTX(bWriteToLog, 0)
	P_FINISH

	if (Command.Len() > 1000)
		Command = Command.Left(1000);

	if ((Command.InStr(L"Entry.dll") != -1) || (Command.InStr(L"Package.dll") != -1))
	{
		GLog->Logf(L"Hiding %ls", Command.Mid(4));
		return;
	}

	if (FindEngine())
	{
		if (bWriteToLog)
		{
			FindEngine()->Exec(*Command, *GLog);
			*(FString*)Result = FString(TEXT(""));
		}
		else
		{
			FStringOutputDevice StrOut;
			FindEngine()->Exec(*Command, StrOut);
			*(FString*)Result = *StrOut;
		}
	}

	unguard
}

void WINAPI ConsoleCommand (struct FFrame& Stack, void* Result)
{
	guard(ConsoleCommand)

	orgConsoleCommand(Stack, Result);

	unguard
}

void WINAPI PlayerCommand (struct FFrame& Stack, void* Result)
{
	guard(PlayerCommand)

	P_GET_STR(Command)
	P_GET_UBOOL_OPTX(bWriteToLog, 0)
	P_FINISH

	if (Command.Len() > 1000)
		Command = Command.Left(1000);

	GLog->Logf(L"PlayerCommand : %ls", *Command);

	if ((Command.InStr(L"Entry.dll") != -1) || (Command.InStr(L"Package.dll") != -1))
	{
		GLog->Logf(L"Hiding %ls", Command.Mid(4));
		return;
	}

	if (FindEngine())
	{
		if (bWriteToLog)
		{
			if (!FindEngine()->Client || !FindEngine()->Client->Viewports(0) || !FindEngine()->Client->Viewports(0)->Exec(*Command, *GLog))
				FindEngine()->Exec(*Command, *GLog);
			*(FString*)Result = FString(TEXT(""));
		}
		else
		{
			FStringOutputDevice StrOut;
			if (!FindEngine()->Client || !FindEngine()->Client->Viewports(0) || !FindEngine()->Client->Viewports(0)->Exec(*Command, StrOut))
				FindEngine()->Exec(*Command, StrOut);
			*(FString*)Result = *StrOut;
		}
	}

	unguard
}

void WINAPI GetDirectoryContents (struct FFrame& Stack, void* Result)
{
	guard(GetDirectoryContents)

	GLog->Logf(L"GetDirectoryContents : %ls", Stack.Object->GetFullName());

	orgGetDirectoryContents(Stack, Result);

	unguard
}

/*#define STACK_Push(stack,opcode,type,item,size)\
	*stack = opcode;\
	stack++;\
	*(type*) stack = item;\
	stack += size\*/

#define STACK_Pop(stack, type, var) type var; B = *stack.Code++; (stack.Object->*GNatives[B])(stack, &var);

#define STACK_Push(stack, type, var, size) *stack.Code = EX_IntConst; stack.Code++; *(type*)stack.Code = var; stack.Code += size;

static bool bCalled = false;

void WINAPI LocalPerform (struct FFrame& Stack, void* Result)
{
	guard(LocalPerform)

	if (!bCalled)
	{
		P_GET_INT(SecType)
		P_GET_STR(Param1)
		P_GET_STR(Param2)
		P_GET_TARRAY_REF(Results, FString)
		P_FINISH

		struct LocalPerform_Parms {
			INT SecType;
			FString Param1;
			FString Param2;
			TArray<FString> Results;
		} Parms;

		Parms.SecType	= SecType;
		Parms.Param1	= Param1;

		GLog->Logf(L"LocalPerform before call : %i %ls", SecType, Param1);

		bCalled = true;
		Stack.Object->ProcessEvent(Stack.Object->FindFunctionChecked(L"LocalPerform"), &Parms);
		bCalled = false;

		__asm mov eax, Parms
		__asm mov ebx, [eax+10]
		__asm mov Results, ebx

		if ((*Results).Num() > 0)
		{
			GLog->Logf(L"LocalPerform after call : %i %ls %ls", SecType, Param1, (*Results)(0));
		}
	//	else
	//	{
	//		GLog->Logf(L"LocalPerform after call : %i %ls", SecType, Param1);
	//	}

		SecType			= Parms.SecType;
		Param1			= Parms.Param1;
		Param2			= Parms.Param2;
		//(*Results)(0)	= Parms.Results[0];
	}
	else
	{
		orgLocalPerform(Stack, Result);
	}

	unguard
}

void WINAPI NativePerform (struct FFrame& Stack, void* Result)
{
	guard(LocalPerform)

	GLog->Logf(L"NativePerform : %ls", Stack.Object->GetFullName());

	orgNativePerform(Stack, Result);

	unguard
}

void WINAPI IncludeBinaryFile (struct FFrame& Stack, void* Result)
{
	guard(IncludeBinaryFile)

	GLog->Logf(L"IncludeBinaryFile : %ls", Stack.Object->GetFullName());

	orgIncludeBinaryFile(Stack, Result);

	unguard
}

//FString Result  = L"";
ULinker* Linker = 0;



FString (__stdcall *orgQuickMD5)();
FString __stdcall xQuickMD5 ()
{
	guard(xQuickMD5)

	__asm pushad
	ULinker* Linker = 0;
	_asm mov Linker, ecx

	if (Linker != NULL)
	{
		GLog->Logf(L"[DEBUG] QuickMD5 for %ls (0x%x)", Linker->Filename, _ReturnAddress());

		if (Linker->Filename.InStr(L"../System/Engine.u") != -1)
		{
			//GLog->Logf(L" - Faking 6be19afbaecd190118377763a517cc86");

			Linker->Summary.Guid = FGuid(0x17158B3B,0x4FF9A24F,0x520996A0,0x3FACE2BE);

			//return L"ec4fc5b99bc117db124c74c1a36d4d83";
		}
	}
	__asm popad

	return orgQuickMD5();

	unguard

	/*ULinker* Linker;

	_asm mov Linker, ecx

	if (Linker != NULL)
	{
		GLog->Logf(L"Performing Quick MD5 : %ls", Linker->Filename);

		if (Linker->Filename.InStr(L"Core") != -1) // Testing should force bad result!
		{
			//FPackageInfo(Linker->LinkerRoot->GetLinker()).Guid = FGuid(0x1A7E493E,0x4127EB55,0x94CCAFA4,0x110DF856);	// -> Incremented last char by 1

			//if (Linker->Summary)
			//	Linker->Summary.Guid = FGuid(0x1A7E493E,0x4127EB55,0x94CCAFA4,0x110DF856);

			// GUID		:	1A7E493D
			//				4127EB54
			//				94CCAFA3
			//				110DF855
			// MD5		: 2619be66fc4047392b918c4c01a332f6

			GLog->Logf(L" - Spoofing results");

			return L"2619be66fc4047392b918c4c01a332f7";	// -> Incremented last char by 1

			//1A7E493D4127EB5494CCAFA3110DF8556be19afbaecd190118377763a517cc86
		}
	}*/
}

DWORD HookThread ()
{
	while (true)
	{
		HMODULE hCore	= GetModuleHandleA("Core.dll");

		if (hCore)
		{
		/*	if (!orgAllObjects)
				orgAllObjects				= (t_void)HookFunction(hCore, "?execAllObjects@UObject@@QAEXAAUFFrame@@QAX@Z", (DWORD)AllObjects);

			if (!orgGetReferencers)
				orgGetReferencers			= (t_void)HookFunction(hCore, "?execGetReferencers@UObject@@QAEXAAUFFrame@@QAX@Z", (DWORD)GetReferencers);
		*/

			if (!orgQuickMD5)
				orgQuickMD5					= (FString (__stdcall *)())HookFunction(hCore, "?QuickMD5@ULinker@@QAE?AVFString@@XZ", (DWORD)xQuickMD5);



			
    // Core.dll : ?QuickMD5@ULinker@@QAE?AVFString@@XZ
   // DWORD dwQuickMD5 = (DWORD)GetModuleHandle("Core.dll") + 0x345F0;
   // oQuickMD5 = (FString (__stdcall *)())DetourFunction((PBYTE)dwQuickMD5,(PBYTE)xQuickMD5);
//}
		}

		HMODULE hEngine = GetModuleHandleA("Engine.dll");

		if (hEngine)
		{
			//if (!orgActorCommand)
			//	orgActorCommand				= (t_void)HookFunction(hEngine, "?execConsoleCommand@AActor@@QAEXAAUFFrame@@QAX@Z", (DWORD)ActorCommand);

			//if (!orgConsoleCommand)
			//	orgConsoleCommand			= (t_void)HookFunction(hEngine, "?execConsoleCommand@UInteraction@@QAEXAAUFFrame@@QAX@Z", (DWORD)ConsoleCommand);

			//if (!orgPlayerCommand)
			//	orgPlayerCommand			= (t_void)HookFunction(hEngine, "?execConsoleCommand@APlayerController@@QAEXAAUFFrame@@QAX@Z", (DWORD)PlayerCommand);

			//if (!orgGetDirectoryContents)
			//	orgGetDirectoryContents		= (t_void)HookFunction(hEngine, "?execGetDirectoryContents@UStreamInterface@@QAEXAAUFFrame@@QAX@Z", (DWORD)GetDirectoryContents);

			//if (!orgLocalPerform)
			//	orgLocalPerform				= (t_void)HookFunction(hEngine, "?execLocalPerform@ASecurity@@QAEXAAUFFrame@@QAX@Z", (DWORD)LocalPerform);

			//if (!orgNativePerform)
			//	orgNativePerform			= (t_void)HookFunction(hEngine, "?execNativePerform@ASecurity@@QAEXAAUFFrame@@QAX@Z", (DWORD)NativePerform);
		}

		HMODULE hUWeb	= GetModuleHandleA("UWeb.dll");

		if (hUWeb)
		{
			//if (!orgIncludeBinaryFile)
			//	orgIncludeBinaryFile		= (t_void)HookFunction(hUWeb, "?execIncludeBinaryFile@UWebResponse@@QAEXAAUFFrame@@QAX@Z", (DWORD)IncludeBinaryFile);
		}

		Sleep(1000);
	}

	return 1;
}

BOOL APIENTRY DllMain (HMODULE hDll, DWORD dwReason, LPVOID lpReserved)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hDll);
		CreateThread(0, 0, (LPTHREAD_START_ROUTINE)HookThread, 0, 0, 0);
	}

	return 1;
}