#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;

/*
inline INT FFrame::ReadInt()
{
	INT Result;
	#if __PSX2_EE__
	appMemcpy(&Result, Code, sizeof(INT));
	#else
	Result = *(INT*)Code;
	#endif
	Code += sizeof(INT);
	return Result;
}*/

/*
		// Create a new local execution stack.
		FFrame NewStack( this, Function, 0, appAlloca(Function->PropertiesSize) );
		appMemcpy( NewStack.Locals, Parms, Function->ParmsSize );
		appMemzero( NewStack.Locals+Function->ParmsSize, Function->PropertiesSize-Function->ParmsSize );

		// Call native function or UObject::ProcessInternal.
		(this->*Function->Func)( NewStack, NewStack.Locals+Function->ReturnValueOffset );

		// Copy everything back.
		appMemcpy( Parms, NewStack.Locals, Function->ParmsSize );

		// Destroy local variables except function parameters.!! see also UObject::ScriptConsoleExec
		for( UProperty* P=Function->ConstructorLink; P; P=P->ConstructorLinkNext )
			if( P->Offset >= Function->ParmsSize )
				P->DestroyValue( NewStack.Locals + P->Offset );
				

FFrame CreateStack (class UObject* Object, class UFunction* Function, void* Parms)
{
	GLog->Logf(L"Creating Stack %ls %ls", Object->GetFullName(), Function->GetFullName());
	if (!Object || !Function || !Parms)
		return NULL;

	GLog->Logf(L" - Stage 1");

	FFrame Stack(Object, Function, 0, appAlloca(Function->PropertiesSize));

	GLog->Logf(L" - Stage 2");

	appMemcpy(Stack.Locals, Parms, Function->ParmsSize);

	GLog->Logf(L" - Stage 3");
	appMemzero(Stack.Locals + Function->ParmsSize, Function->PropertiesSize - Function->ParmsSize);

	GLog->Logf(L" - Stage 4");

	return Stack;
}

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
}
*/

void* orgVirtualProtect = NULL;
void WINAPI xVirtualProtect (LPVOID lpAddress, DWORD dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
{
	__asm pushad
	Log("xVirtualProtect : 0x%x", lpAddress);

	__asm
	{
		popad
		push lpflOldProtect
		push flNewProtect
		push dwSize
		push lpAddress
		call orgVirtualProtect
	}
}

void* orgActorCommand = NULL;
DWORD HookThread ()
{
	while (true)
	{
		HMODULE hKernel = GetModuleHandleA("Engine.dll");

		if (hKernel)
			orgVirtualProtect = (void*)DetourFunction((PBYTE)GetProcAddress(hKernel, "VirtualProtect"), (PBYTE)xVirtualProtect);
		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);
		*/}

		DWORD hEngine = (DWORD)0x10301000;

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

				Log("hEngine : 0x%x", hEngine);
				Log("Offset 0x%x", (DWORD)(hEngine + 0x1CF16C));
				Log("Offset 0x%x", (DWORD)(hEngine + 0x12324A));
				Log("Offset 0x%x", (DWORD)(hEngine + 0x1CEBEB));
				Log("Offset 0x%x", (DWORD)(hEngine + 0x1CECF1));

				orgActorCommand = (void*)1;
			}

			/*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;
}