UE1 - UT Replication, need some advice

  • Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

Rajada

Member
Jan 21, 2008
213
0
16
rajada.tumblr.com
I really hope modern games have outgrown the headache that is Unreal replication. This problem arises online:

I have a weapon that has a timer function in it. Every set amount of time (very short, ~ 0.1 seconds) TraceFire is called. It in turn calls ProcessTraceHit wich spawns an actor at the first colliding position. Functionally this is basically a laser sight. To keep things from getting too costly, one dot is spawned. If it is destroyed, another is spawned. As long as there is a dot, it should be moved (via SetLocation()) to the location I traced a few steps back. However, online, the first dot is created but never moved. It decays after a few seconds, and another is created. I store the dot in a variable: var LaserDot D;. My thought is that this variable is not being replicated, but it could be other things too.

So I'm looking for an expert opinion, and maybe a brief explanation of the replication involved here. Here is some code to help explain my work so far:

In the weapon:

Code:
var LaserDot LD;

simulated function Timer()
{
		TraceFire(0.0);	
}

function TraceFire( float Accuracy )
{
	local vector HitLocation, HitNormal, StartTrace, EndTrace, X,Y,Z;
	local actor Other;
	local Pawn PawnOwner;

	PawnOwner = Pawn(Owner);

	GetAxes(PawnOwner.ViewRotation,X,Y,Z);
	StartTrace = Owner.Location + CalcDrawOffset() + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z; 
	AdjustedAim = PawnOwner.AdjustAim(100000, StartTrace, 2.5*AimError, False, False);	
	EndTrace = StartTrace + Accuracy * (FRand() - 0.5 )* Y * 100
		+ Accuracy * (FRand() - 0.5 ) * Z * 100;
	X = vector(AdjustedAim);
	EndTrace += (10000 * X); 
	Other = PawnOwner.TraceShot(HitLocation,HitNormal,EndTrace,StartTrace);
	ProcessTraceHit(Other, HitLocation, HitNormal, X,Y,Z);
}
function ProcessTraceHit(Actor Other, Vector HitLocation, Vector HitNormal, Vector X, Vector Y, Vector Z)
{
	local LaserDot L;
	if((LD == none) && (Pawn(Owner).Health > 0))
	{
		L = Spawn(class'LaserDot',,, HitLocation+HitNormal*9, Rotator(HitNormal));
		L.RemoteRole = ROLE_SimulatedProxy;
		L.SetOwner(Owner);
		LD = L;
		LD.SetOwner(Owner);
		LD.RemoteRole = ROLE_SimulatedProxy;
	}
	else if(Pawn(Owner).Health < 0)
	LD.Destroy();
	else
	LD.SetLocation(HitLocation+HitNormal*9);
}

The laser dot itself has almost no code:

Code:
simulated function Tick(float DeltaTime)
{
	if(Owner == none)
	Destroy();
}
 
Last edited:

meowcat

take a chance
Jun 7, 2001
803
3
18
Its been a long time since I coded anything in UT, but it would appear to me that the "simulated function call chain" is broken. Since (simulated) Timer calls the trace function, Timer could run on the client, however neither TraceFire nor ProcessTraceHit are simulated, and I imagine Pawn.TraceShot is probably not simulated either. The other thing I can't remember is whether the weapon is replicated to non-owning clients (it probably is, but I just can't remember).

The fact that the laser dot shows up on clients means that the RemoteRole change is working but its not receiving any location updates. Check the replication block in actor.uc for the 'location' variable. I seem to remember having to lower the RemoteRole to ROLE_DumbProxy because ROLE_simlatedProxy assumes that you will also have some clientside movement code included. You may also need to adjust the NetPriority and NetUpdateFrequency variables too (maybe try to match the projectile class...)
 
Last edited:

Rajada

Member
Jan 21, 2008
213
0
16
rajada.tumblr.com
One thing I've never known for sure (despite reading several help articles on it) was when to simulate functions. I'm probably wrong, but my thought was when it needed to be executed clientside, you simulate it. No one has yet to explain it to me in a way that makes sense.

Anyway, the thing that I do get to a small extent is that certain variables are only replicated in certain remote roles. To me, that just seems like a completely stupid system. I understand the need to optimize network traffic, especially in 1999, but I hope this system hasn't stuck in modern games, or at least has been refined. I spend so much time guessing and checking in replication.

Oh, yes by the way, DumbProxy seems to have done it. I'm not exactly sure why, but also making timer not simulated helped.
 
Last edited:

meowcat

take a chance
Jun 7, 2001
803
3
18
Generally, yes. If a function needs to be able to be run clientside it must also be simulated, if a non-simulated function is called on the client, it will simply not actually execute (broken simulation chain). The function call chain must also be started on the client either by a replicated fucntion call from the server, or the local client. The exception to this rule (at least the one that I remember) is the PlayerPawn class, in which the owning client which can also run non-simulated functions (RemoteRole==ROLE_AutonomousProxy).

Even in modern games, you ALWAYS need to optimize data replication (after all the more compact/optimized the data, the more objects can be replicated ... to an extent, based on server loads/relevancy checks). UE's system actually ends up being pretty straightforward once you get the hang of it. Also being able to test the code in a network, or faking it on a single machine, helps a lot with troubleshooting! With UT and UT2k4 there are a ton of fantastic examples of replication that really cover a lot of weird/one-off situations.

The pages on the UDN here under "NetWorking" give about as good an overview as any, but the best way I learned was to work on a lot of varied code projects and scour the source scripts.
 
Last edited:

Gizzy

The Banhammer Cometh
May 30, 2009
195
0
0
United Kingdom
So.. is the basic aim of this code to have a laserdot that is constantly active and moves depending on where the player is looking? Might have some code in csweapons that could help :)
 

Rajada

Member
Jan 21, 2008
213
0
16
rajada.tumblr.com
Well, yes, but there was some additional stuff too, mainly, a fired projectile actually seeks the dot, kind of like the Half Life 2 rocket launcher.

One last question, I have a bool variable in the weapon itself, it stops you from putting the weapon away with 0 ammo if you are still guiding a missile. This is determined by if var Missile M != none. This works fine in single player, but in multiplayer it acts as if the missile is visually destroyed when it explodes, but the gun lingers for several more seconds, as if M isn't none. In my opinion, either the projectile is still existing on the server somehow or M isn't being updated properly because of replication. Any suggestions?
 

gopostal

Active Member
Jan 19, 2006
848
47
28
Grab the source from this (it's in the download): http://www.moddb.com/mods/redeemer-mania

There is some really awesome seeker code in it that you can use however you like. Set the target to be the processtracehit location in place of the locked-on opponent and it should set you up nicely. There is code adjustments to make the rocket more or less deadly and to set how much it can turn. Have at whatever is in there and do what you like with it.