/*-----------------------------------------------------------------------------
	UuPackageMap - UPackageMapLevel hook for v451b net compatibility
-----------------------------------------------------------------------------*/
class UuPackageMap : public UPackageMap
{
	DECLARE_CLASS(UuPackageMap,UPackageMap,CLASS_Transient,udemo);

	UNetConnection* Connection;
	
	UChannel***	Channels;	// Ptr to UChannel* UNetConnection::Channels[]
	TMap<AActor*,UActorChannel*>* ActorChannels; // Ptr to TMap<AActor*,UActorChannel*> UNetConnection::ActorChannels

	UBOOL CanSerializeObject( UObject* Obj );
	UBOOL SerializeObject( FArchive& Ar, UClass* Class, UObject*& Obj );

	UObject* UuIndexToObject( INT Index, UBOOL Load );

	UuPackageMap()
	{}
	UuPackageMap( UNetConnection* InConnection )
	: Connection( InConnection )
	{		
		FString	Ver = UTexture::__Client->Viewports(0)->Actor->Level->EngineVersion;		

		// Must be UTPG patch...
		if (Ver != TEXT("436") && Ver != TEXT("432"))
		{
			GLog->Logf(TEXT("Using UTPG Channel Layout"));
			Channels		= (UChannel***)						( (DWORD)InConnection + 0x0E4C );
			ActorChannels	= (TMap<AActor*,UActorChannel*>*)	( (DWORD)InConnection + 0x3E98 );
		}
		// Standard v432 structures
		else
		{
			GLog->Logf(TEXT("Using Epic Channel Layout"));
			Channels		= (UChannel***)						( (DWORD)InConnection + 0x0E60 );
			ActorChannels	= (TMap<AActor*,UActorChannel*>*)	( (DWORD)InConnection + 0x3E84 );
		}
	}
};

/*-----------------------------------------------------------------------------
	UuPackageMap::CanSerializeObject - Net compatible with v451b
-----------------------------------------------------------------------------*/
UBOOL UuPackageMap::CanSerializeObject(UObject* Obj)
{
	guard(UuPackageMap::CanSerializeObject);
	//return Original->CanSerializeObject(Obj);
	GLog->Logf(TEXT("CanSerializeObject: %s"), Obj->GetFullName());
	AActor* Actor = Cast<AActor>(Obj);
	if( Actor && !Actor->bStatic && !Actor->bNoDelete )
	{
		UActorChannel* Ch = ActorChannels->FindRef(Actor);
		return Ch!=NULL;
	}
	else return 1;
	unguard;
}

UObject* UuPackageMap::UuIndexToObject( INT Index, UBOOL Load )
{
	if( Index>=0 )
	{
		for( INT i=0; i<List.Num(); i++ )
		{
			FPackageInfo& Info = List(i);
			GLog->Logf(TEXT("--- PackageInfo[%d] -> %s %d"), i, *Info.Linker->Filename, Info.ObjectCount);
			if( Index < Info.ObjectCount )
			{
				UObject* Result = Info.Linker->ExportMap(Index)._Object;
				/*if( !Result && Load )
				{
					UObject::BeginLoad();
					Result = Info.Linker->CreateExport(Index);
					UObject::EndLoad();
				}*/
				return Result;
			}
			Index -= Info.ObjectCount;
		}
	}
	return NULL;
}

/*-----------------------------------------------------------------------------
	UuPackageMap::SerializeObject - Net compatible with v451b

	FInBunch << Object
	bit - dynamic/static
	int - actor channel idx or object idx
-----------------------------------------------------------------------------*/
UBOOL UuPackageMap::SerializeObject( FArchive& Ar, UClass* Class, UObject*& Object )
{
	guard(UuPackageMap::SerializeObject);

	GLog->Logf(TEXT("UuPackageMap::SerializeObject"));

	FInBunch& Bunch = (FInBunch&)Ar;
	GLog->Logf(TEXT("InBunch Size: %d - %d"), Bunch.GetPosBits(), Bunch.GetNumBits());


	DWORD Index = 0;
	if (Ar.IsLoading())					// ArIsLoading: 0x10
	{
		GLog->Logf(TEXT(">>> InBunch is loading"));

		BYTE B = 0;						// Byte size allocation on stack (BYTE PTR [EBP+B])
		Ar.SerializeBits(&B, 1);		// VFunc 0x8		
		
		if (B)
		{
			GLog->Logf(TEXT(">>> Object is dynamic"));

			// B == 1 => Dynamic
			// Get actor channel index
			Ar.SerializeInt(Index, UNetConnection::MAX_CHANNELS);	// MAX_CHANNELS = 0x3FF - VFunc 0xC

			GLog->Logf(TEXT(">>> Channel index: %d - 0x%03X"), Index, Index);
			
			if (Index == 0)
			{
				Object = NULL;
			}
			else
			{
				if (!Ar.IsError()									// ArIsError: 0x2C
					&& Index < UNetConnection::MAX_CHANNELS			// JNB 0x3FF
					&& (*Channels)[Index]							// 0xE60 + EAX*4
					&& (*Channels)[Index]->ChType == CHTYPE_Actor	// 0x44
					&& !(*Channels)[Index]->Closing)				// 0x30
				{
					Object = ((UActorChannel*)(*Channels)[Index])->GetActor();		// AActor* Actor; //	-- 0x64
				}
			}	

			GLog->Logf(TEXT(">>> Mapped to object: 0x%08X - %s"), Object, (Object ? Object->GetFullName() : TEXT("NONE")));
		}
		else
		{
			GLog->Logf(TEXT(">>> Object is static"));

			// 0x68 = second to last var in UPackageMap = MaxObjectIndex
			Ar.SerializeInt(Index, MaxObjectIndex);

			GLog->Logf(TEXT(">>> Object index: %d - 0x%03X"), Index, Index);

			if (!Ar.IsError())		// 0x2C
				Object = UuIndexToObject(Index, 1);		// VFUNC 0x64

			GLog->Logf(TEXT(">>> Mapped to object: 0x%08X - %s"), Object, (Object ? Object->GetFullName() : TEXT("NONE")));
		}
		if( Object && !Object->IsA(Class) )
		{
			debugf(TEXT("Forged object: got %s, expecting %s"),*Object->GetFullName(),*Class->GetFullName());
			Object = NULL;
		}		
		return 1;
	}
	else
	{
		GError->Logf(TEXT("UDEMO ERROR: Attempt to serialize to loaded FArchive: 0x%08X - %s"), Object, (Object ? Object->GetFullName() : TEXT("NONE")));
		return 0;
	}
	
	unguard;
}

/*UPackageMapLevel* OldMap = (UPackageMapLevel*)PackageMap;
	PackageMap = new(this) UuPackageMap(this);
	PackageMap->Copy(OldMap);
	PackageMap->CopyLinkers(OldMap);*/