// Critical extended data for players
// To be used to fix mods and expand a player's replication properties
// BaseEyeHeight should fix ZeroPing and SiegeInstagibRifles

class sgPlayerData expands ReplicationInfo;

struct PreciseVector
{
	var() config float X;
	var() config float Y;
	var() config float Z;
};

var Pawn POwner;
var float BaseEyeHeight;
var int OwnerID;
var sgPRI OwnerPRI;
var int RealHealth;
var vector LastRepLoc;
var float LastRepLocTime;
var bool bReplicateLoc;
var bool bReplicateHealth;
var bool bHudEnforceHealth;


replication
{
	unreliable if ( !bNetOwner && Role==ROLE_Authority )
		BaseEyeHeight;
	unreliable if ( !bNetOwner && bReplicateHealth && Role==ROLE_Authority )
		RealHealth;
	reliable if ( Role==ROLE_Authority )
		OwnerID;

	unreliable if ( Role==ROLE_Authority )
		AdjustPlayerLocation;
}

event PostBeginPlay()
{
	POwner = Pawn(Owner);
	if ( Owner.IsA('bbPlayer') )
		bReplicateHealth = true;
	OwnerPRI = sgPRI(POwner.PlayerReplicationInfo);
	bReplicateLoc = true;
}

simulated event SetInitialState()
{
	bScriptInitialized = true;
	if ( Level.NetMode != NM_Client )
		GotoState('Server','InitID');
}

simulated event PostNetBeginPlay()
{
	GotoState('Client');
}


state Server
{
InitID:
	Sleep(0.0);
	OwnerID = POwner.PlayerReplicationInfo.PlayerID;
	RemoteRole = ROLE_SimulatedProxy; //Init replication
Begin:
	if ( POwner == none || POwner.bDeleteMe )
	{
		Destroy();
		Stop;
	}
	BaseEyeHeight = POwner.BaseEyeHeight;
	if ( POwner.bHidden )	NetUpdateFrequency = 1.5;
	else					NetUpdateFrequency = POwner.NetUpdateFrequency * 0.5;
	if ( ShouldReplicateLoc() )
		ReplicateLoc();
	if ( bReplicateHealth )
		RealHealth = POwner.Health;
	Sleep(0.0);
	Goto('Begin');
}

simulated state Client
{
Begin:
	//Find PRI
	if ( !FindPRI() )
	{
		Sleep(0.3);
		Goto('Begin');
	}
FindPawn:
	POwner = Pawn(OwnerPRI.Owner);
	if ( POwner != none )
		SetOwner( POwner);
	if ( (PlayerPawn(POwner) != none) && ViewPort(PlayerPawn(POwner).Player) != none )
		Goto('OwnerClient');
SetProps:
	if ( POwner == none || POwner.bDeleteMe )
	{
		Sleep(0.0);
		Goto('FindPawn');
	}
	POwner.BaseEyeHeight = BaseEyeHeight;
	POwner.EyeHeight = BaseEyeHeight;
	Sleep(0.0);
	Goto('SetProps');
OwnerClient:
	Sleep(5);
	if ( POwner.IsA('bbPlayer') && sgHUD(PlayerPawn(POwner).myHud) != none )
		sgHUD(PlayerPawn(POwner).myHud).bEnforceHealth = true;
	Stop;
}

simulated function SetHealth()
{
	if ( (POwner != none) && (RealHealth != -1337) )
		POwner.Health = RealHealth;
}

simulated function bool FindPRI()
{
	local sgPRI PRI;

	ForEach AllActors (class'sgPRI', PRI)
		if ( PRI.PlayerID == OwnerID )
		{
			if ( PRI.bAdmin && PRI.bIsSpectator ) //This is most likely a playerless bot
				continue;
			OwnerPRI = PRI;
			return true;
		}
	//No return equals False
}

function bool ShouldReplicateLoc()
{
	if ( bReplicateLoc && !SiegeGI(Level.Game).bDisableIDropFix && (POwner.Acceleration == vect(0,0,0)) && (POwner.Base != none) && (POwner.Velocity == vect(0,0,0)) && (POwner.Base.Velocity == vect(0,0,0)) )
	{
		if ( (LastRepLocTime < (Level.TimeSeconds - 1 * Level.TimeDilation)) || (POwner.Location != LastRepLoc) )
			return POwner.FastTrace( POwner.Location - vect(0,0,1.2) * POwner.CollisionHeight);
	}
}

function ReplicateLoc()
{
	local sgPlayerData sgP;
	LastRepLoc = POwner.Location;
	LastRepLocTime = Level.TimeSeconds;
	ForEach AllActors (class'sgPlayerData', sgP)
		if ( sgP != self )
			sgP.AdjustPlayerLocation( POwner, POwner.Location.X, POwner.Location.Y, POwner.Location.Z);
}

simulated function AdjustPlayerLocation( Pawn Other, float LX, float LY, float LZ)
{
	local vector aVec;
	local bool bOldCol;

	if ( Other == none ) //Pawn not yet replicated?
		return;
	aVec.X = LX; aVec.Y = LY; aVec.Z = LZ;
	bOldCol = Other.bCollideWorld;
	Other.bCollideWorld = false;
	Other.bCollideWhenPlacing = false;
	Other.SetLocation( aVec);
	Other.bCollideWorld = bOldCol;
	Other.bCollideWhenPlacing = true;
}


static final function vector ToVector( PreciseVector A)
{
	local vector V;
	V.X = A.X;
	V.Y = A.Y;
	V.Z = A.Z;
	return V;
}
static final function bool IsZero( PreciseVector A)
{
	return (A.X == 0) && (A.Y == 0) && (A.Z == 0);
}


defaultproperties
{
	RemoteRole=ROLE_None
	OwnerID=-1
	RealHealth=-1337
}