A little bit extended mover

Discussions about Coding and Scripting
Post Reply
Haxer557
Novice
Posts: 10
Joined: Mon Jun 06, 2011 9:51 am
Personal rank: Thievery UT Player

A little bit extended mover

Post by Haxer557 »

Hello,

I map a level for a team game (Thievery UT), and I wish to create a boat, that would carry players of one team, but only if they are inside. To achieve it, I have coded a Trigger that I will call from now a controller. The controller checks every tick id there is a player of this particular team in boat, and how many of them, if boat is not interpolating it checks its keys, and modifies KeyPos and KeyRot values, as well as MoveSpeed - the more players are in boat, the faster it moves - then it triggers it. The boat is also coded, for by default KeyPos and KeyRot values do not replicate to client.

Code: Select all

var vector DesiredLocation;
var rotator DesiredRotationAdv;
var float NewMoveTime; 
var int DesiredKeyNum;
var() name AttachTag;

replication
{
	reliable if(Role==Role_Authority)
		DesiredLocation, DesiredRotationAdv, DesiredKeyNum, NewMoveTime;
}
A simulated Tick overrides KeyPos, KeyRot, and MoveTime variables, just like that:

Code: Select all

simulated function Tick(float DeltaTime)
{
	Super.Tick(DeltaTime);
	if(KeyPos[DesiredKeyNum]!=DesiredLocation)
		KeyPos[DesiredKeyNum]=DesiredLocation;
	if(KeyRot[DesiredKeyNum]!=DesiredRotationAdv)
	{
		KeyRot[DesiredKeyNum]=DesiredRotationAdv;
	}
	if(MoveTime!=NewMoveTime)
		MoveTime=NewMoveTime;
}
If I try to play it solo, everything works as I desired, however if I try it online, the moment boat turns left - and mover starts to rotate - mover starts shaking very fast, and player on the boat starts to spin around. Perhaps there is something more I should replicate to the client?

edit: in case it was helpful, here are source codes:

The controller:

Code: Select all

//=============================================================================
// ThHaxersBoatController.
//=============================================================================
class ThHaxersBoatController expands Triggers;

var vector       HaxersKeyPos[128];
var rotator      HaxersKeyRot[128];
var int 		 HaxersActualKeyNum;
var ThHaxersAdvancedBoat Boat;
var rotator SavedRotatorTest;

var() float Speedmps;
var float MoveTime;
var bool bInitialized;

function InitializeBoat()
{
	local int i;

	log("Boat is initializing");
	HaxersKeyPos[0].X=0;
	HaxersKeyPos[0].Y=0;
	HaxersKeyPos[0].Z=0;
	HaxersKeyRot[0]=Rotation-Rotation;

	for(i=1; i<28; i++)//first 28 keys boat moves straight forward
	{
	HaxersKeyPos[i].X=HaxersKeyPos[i-1].X;
	HaxersKeyPos[i].Y=HaxersKeyPos[i-1].Y+64;
	HaxersKeyPos[i].Z=HaxersKeyPos[i-1].Z;
	HaxersKeyRot[i]=Rotation-Rotation;
	}
	for(i=28; i<63; i++)//then it moves diagonally
	{
	HaxersKeyPos[i].X=HaxersKeyPos[i-1].X+46;
	HaxersKeyPos[i].Y=HaxersKeyPos[i-1].Y+46;
	HaxersKeyPos[i].Z=HaxersKeyPos[i-1].Z;
	HaxersKeyRot[i]=Rotation-Rotation;
	HaxersKeyRot[i].Yaw=HaxersKeyRot[i-1].Yaw - 468.114;
	}
	for(i=63; i<122; i++)//the last part of boats movement is almost perpendicular to the first part
	{
	HaxersKeyPos[i].X=HaxersKeyPos[i-1].X+64;
	HaxersKeyPos[i].Y=HaxersKeyPos[i-1].Y+4;
	HaxersKeyPos[i].Z=HaxersKeyPos[i-1].Z;
	HaxersKeyRot[i]=HaxersKeyRot[i-1];
	}

	foreach AllActors(class'ThHaxersAdvancedBoat', Boat, Event)
	{
		break;
	}

	MoveTime = 1/Speedmps;

	bInitialized=true;
}

function SetKeys()
{
	HaxersActualKeyNum++;
	if(Boat.KeyNum==0)
	{
		Boat.DesiredKeyNum=1;
	}
	if(Boat.KeyNum==1)
	{
		Boat.DesiredKeyNum=0;
	}
	Boat.DesiredLocation=HaxersKeyPos[HaxersActualKeyNum];
	Boat.DesiredRotationAdv=HaxersKeyRot[HaxersActualKeyNum];
}

function Tick(float DeltaTime)
{
	local int ThievesStanding;
	local Actor A;
	local Pawn P;
	local Pawn SavedPawn;

	//count thieves standing on a boat
	Super.Tick(DeltaTime);

	if(!bInitialized)
		return;

	if(HaxersActualKeyNum==120)
	{
	log("Boat Reached!");
		if(!binterpolating)
		{
			foreach AllActors(class 'Actor', A, 'BoatReached') {
				A.Trigger(None, None);}
			bInitialized=false;
		}
	return;
	}
	for (P=Level.PawnList; P!=None; P=P.nextPawn)
   	{
		if(ThieveryPPawn(P)!=None&&ThieveryPPawn(P).PlayerReplicationInfo!=None&&ThieveryPPawn(P).PlayerReplicationInfo.Team==0)
		{
			if(VSize(ThieveryPPawn(P).Location - Boat.Location)<140&&ThieveryPPawn(P).Location.Z>Boat.Location.Z)
			{
				SavedPawn=P;
				ThievesStanding++;
			}
		}
	}

	if(ThievesStanding>0)
	{
		// some taffer is sitting in a boat - let's set sail
		if(!Boat.bInterpolating)
		{
			SetKeys();
			Boat.NewMoveTime=MoveTime+(ThievesStanding-1)*MoveTime*0.5;
			Boat.Trigger(SavedPawn, SavedPawn);
		}
	}
}

And the boat:

Code: Select all

//=============================================================================
// ThHaxersAdvancedBoat.
//=============================================================================
class ThHaxersAdvancedBoat expands Mover;

var vector DesiredLocation;
var rotator DesiredRotationAdv;
var float NewMoveTime;
var int DesiredKeyNum;
var() name AttachTag;

replication
{
	reliable if(Role==Role_Authority)
		DesiredLocation, DesiredRotationAdv, DesiredKeyNum, NewMoveTime;
}

function PostBeginPlay()
{
	local Actor Act;
	local Mover Mov;

	Super.PostBeginPlay();

	// Initialize all slaves.
	if ( AttachTag != '' )
		foreach AllActors( class 'Actor', Act, AttachTag )
		{
			Mov = Mover(Act);
			if (Mov == None) {

				Act.SetBase( Self );
			}
			else if (Mov.bSlave) {
			
				Mov.GotoState('');
				Mov.SetBase( Self );
			}
		}
}

simulated function Tick(float DeltaTime)
{
	local Actor A;
	Super.Tick(DeltaTime);
	if(KeyPos[DesiredKeyNum]!=DesiredLocation)
		KeyPos[DesiredKeyNum]=DesiredLocation;
	if(KeyRot[DesiredKeyNum]!=DesiredRotationAdv)
	{
		KeyRot[DesiredKeyNum]=DesiredRotationAdv;
	}
	if(MoveTime!=NewMoveTime)
		MoveTime=NewMoveTime;
}
edit2:

To make it more clear, I recorded a video:
User avatar
Feralidragon
Godlike
Posts: 5498
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: A little bit extended mover

Post by Feralidragon »

Could you post your default properties as well.

Movers are a quite messed up part of the UEngine relative online play (they never worked right, take their rotating mover of example which doesn't even rotate at all online).
However in your case I think this may be fixed, but the default properties are important since they define certain things like the NetPriority, Roles, etc.
Haxer557
Novice
Posts: 10
Joined: Mon Jun 06, 2011 9:51 am
Personal rank: Thievery UT Player

Re: A little bit extended mover

Post by Haxer557 »

Most of the properties are just mover's defaults I guess. Sorry for the inconvenience, but since I use my mobile phone to access the Internet atm, I am unable to post a Sshot. Instead, I will write down some properties:
NetPriority - 2.7
NetUpdateFrequency - 100.0
RemoteRole - ROLE_SimulatedProxy
User avatar
Feralidragon
Godlike
Posts: 5498
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: A little bit extended mover

Post by Feralidragon »

Well, I will be honest with you: I never coded a mover in my life, therefore my "solution" may or may not work, but give it a try nonethless:
- It happens that to me that "shake" is simply 2 different rotation values "conflicting" with eachother, meaning that when the client updates to a value, the server sends its own value and is updated again, and the server value is different from the client.
I checked up your code and the Mover class code to see how it handled movement, and everything sugests that you're worrying about something you don't have to, therefore try this:
- Remove that replication block from the mover, it will be useless from this moment on;
- Turn that simulated tick into a non-simulated (remove the "simulated" word)

From that moment on, the keys will be only updated in the server, and the mover super class replication code should handle the rest.
Again, no guarantees it will work, and in case it really doesn't, at least we can observe perhaps another kind of behaviour to create a pattern and check how that can be fixed.

EDIT: Btw, remove those Rotation-Rotation parts of your code (replace them by rot(0,0,0) instead).
Haxer557
Novice
Posts: 10
Joined: Mon Jun 06, 2011 9:51 am
Personal rank: Thievery UT Player

Re: A little bit extended mover

Post by Haxer557 »

By the time you posted it, I had tried setting role to dumbproxy, and it works pretty fine. Still you helped me a lot by pointing to Networking properties.
Your solution is something similar to what I have once tried, but the parent class doesn't replicate KeyPos arrays, what would lead to a desynch in online game.
The very first parts of the code I wrote when I was just starting with Unreal Script, thats why there is Rotation-Rotation :P shame on me.
Thank you once again, for I wouldn't have touched those Networking properties if it wasn't you who mentioned it. If I create any readable item with credits, I will mention it, as well as the forums. :)
User avatar
Feralidragon
Godlike
Posts: 5498
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: A little bit extended mover

Post by Feralidragon »

No problem. However:
Haxer557 wrote: Your solution is something similar to what I have once tried, but the parent class doesn't replicate KeyPos arrays, what would lead to a desynch in online game.
The first thing you must understand about the Mover class (from what I checked in its code) is that you don't even need to replicate those values (the same happens to actors like the guided redeemer). Most of the values of the mover are server-side only, and the only values you replicate are stuff like "RealLocation" and "RealRotation" and so on, values that were updated in the server, and that must be updated in the client, exactly to avoid the sync problem between both ends.

But well, that "solution" is not perfect, but if it works well for you, that's ok (considering that replication of Movers and guided redeemers isn't exactly simple stuff) :thuup:
Post Reply