Page 1 of 1

Projectile speed replication

PostPosted: Sat Mar 23, 2019 9:34 pm
by Barbie
Short description: a given value in server's INI file should be transferred to clients.

Long description: For some reasons I want to change the speed of a projectile by an INI file located at the server. For example for the RocketLauncher: I subclassed the default projectile ("SBRocketMk2"), added a new variable "ProjectileSpeed" that should be replicated and assign the value of "ProjectileSpeed" to the variable "Speed" in PostBeginPlay():
Code: Select all
class SBRocketMk2 expands RocketMk2 config(SBRocketMk2);

var config float ProjectileSpeed;

replication {
   reliable if (Role == ROLE_Authority)
      ProjectileSpeed;
}

simulated function logger(string msg) {
   Log(msg);
   broadcastmessage(msg);
}


simulated function PostNetBeginPlay() {
   Logger(self $ ".PostNetBeginPlay: Speed=" $ Speed);
   super.PostNetBeginPlay();
}


simulated function PostBeginPlay() {
   Logger(self $ ".PostBeginPlay starting with SmokeRate=" $ SmokeRate $ ", ProjectileSpeed=" $ ProjectileSpeed  $ ", Speed=" $ Speed);
   Speed = ProjectileSpeed;
   Super.PostBeginPlay();
   logger(self $ ".PostBeginPlay finished with SmokeRate=" $ SmokeRate $ ", ProjectileSpeed=" $ ProjectileSpeed  $ ", Speed=" $ Speed);
}


defaultproperties {
   ProjectileSpeed=20
}

Because the new projectile has to be used, I subclassed the weapon also ("SBEightball") and set the ProjectileClass there. (Unfortunately the default ProjectileClass ("Class'RocketMk2'") is also used in the code, so I have to substitute it there.)
SBEightball
Code: Select all
class SBEightball expands UT_Eightball;


state FireRockets {

   function BeginState() // complete copy of parent except line 87 where class'rocketmk2' is spawned
   {
      local vector FireLocation, StartLoc, X,Y,Z;
      local rotator FireRot, RandRot;
      local rocketmk2 r;
      local UT_SeekingRocket s;
      local ut_grenade g;
      local float Angle, RocketRad;
      local pawn BestTarget, PawnOwner;
      local PlayerPawn PlayerOwner;
      local int DupRockets;
      local bool bMultiRockets;

      PawnOwner = Pawn(Owner);
      if ( PawnOwner == None )
         return;
      PawnOwner.PlayRecoil(FiringSpeed);
      PlayerOwner = PlayerPawn(Owner);
      Angle = 0;
      DupRockets = RocketsLoaded - 1;
      if (DupRockets < 0) DupRockets = 0;
      if ( PlayerOwner == None )
         bTightWad = ( FRand() * 4 < PawnOwner.skill );

      GetAxes(PawnOwner.ViewRotation,X,Y,Z);
      StartLoc = Owner.Location + CalcDrawOffset() + FireOffset.X * X + FireOffset.Y * Y + FireOffset.Z * Z;

      if ( bFireLoad )
         AdjustedAim = PawnOwner.AdjustAim(ProjectileSpeed, StartLoc, AimError, True, bWarnTarget);
      else
         AdjustedAim = PawnOwner.AdjustToss(AltProjectileSpeed, StartLoc, AimError, True, bAltWarnTarget);

      if ( PlayerOwner != None )
         AdjustedAim = PawnOwner.ViewRotation;

      PlayRFiring(RocketsLoaded-1);
      Owner.MakeNoise(PawnOwner.SoundDampening);
      if ( !bFireLoad )
      {
         LockedTarget = None;
         bLockedOn = false;
      }
      else if ( LockedTarget != None )
      {
         BestTarget = Pawn(CheckTarget());
         if ( (LockedTarget!=None) && (LockedTarget != BestTarget) )
         {
            LockedTarget = None;
            bLockedOn=False;
         }
      }
      else
         BestTarget = None;
      bPendingLock = false;
      bPointing = true;
      FireRot = AdjustedAim;
      RocketRad = 4;
      if (bTightWad || !bFireLoad) RocketRad=7;
      bMultiRockets = ( RocketsLoaded > 1 );
      While ( RocketsLoaded > 0 )
      {
         if ( bMultiRockets )
            Firelocation = StartLoc - (Sin(Angle)*RocketRad - 7.5)*Y + (Cos(Angle)*RocketRad - 7)*Z - X * 4 * FRand();
         else
            FireLocation = StartLoc;
         if (bFireLoad)
         {
            if ( Angle > 0 )
            {
               if ( Angle < 3 && !bTightWad)
                  FireRot.Yaw = AdjustedAim.Yaw - Angle * 600;
               else if ( Angle > 3.5 && !bTightWad)
                  FireRot.Yaw = AdjustedAim.Yaw + (Angle - 3)  * 600;
               else
                  FireRot.Yaw = AdjustedAim.Yaw;
            }
            if ( LockedTarget != None )
            {
               s = Spawn( class 'ut_SeekingRocket',, '', FireLocation,FireRot);
               s.Seeking = LockedTarget;
               s.NumExtraRockets = DupRockets;
               if ( Angle > 0 )
                  s.Velocity *= (0.9 + 0.2 * FRand());
            }
            else
            {
               //r = Spawn( class'rocketmk2',, '', FireLocation,FireRot);
               r = RocketMK2(Spawn(ProjectileClass,, '', FireLocation,FireRot));

               r.NumExtraRockets = DupRockets;
               if (RocketsLoaded>4 && bTightWad) r.bRing=True;
               if ( Angle > 0 )
                  r.Velocity *= (0.9 + 0.2 * FRand());
            }
         }
         else
         {
            g = Spawn( class 'ut_Grenade',, '', FireLocation,AdjustedAim);
            g.NumExtraGrenades = DupRockets;
            if ( DupRockets > 0 )
            {
               RandRot.Pitch = FRand() * 1500 - 750;
               RandRot.Yaw = FRand() * 1500 - 750;
               RandRot.Roll = FRand() * 1500 - 750;
               g.Velocity = g.Velocity >> RandRot;
            }
         }

         Angle += 1.0484; //2*3.1415/6;
         RocketsLoaded--;
      }
      bTightWad=False;
      bRotated = false;
   }

   function AnimEnd()
   {
      if ( !bRotated && (AmmoType.AmmoAmount > 0) )
      {
         PlayLoading(1.5,0);
         RocketsLoaded = 1;
         bRotated = true;
         return;
      }
      LockedTarget = None;
      Finish();
   }


}


defaultproperties {
   ItemName="Enhanced Rocket Launcher"
   PickupMessage="You got the Enhanced Rocket Launcher."
   ProjectileClass=class'SBRocketMk2'
}


For testing I set the ProjectileSpeed quite high:
SBRocketMk2.ini wrote:[SBEightballV1.SBRocketMk2]
ProjectileSpeed=5000.000000


Running the testmap locally all things work, but playing with client/server and INI file on server only, the client logs
UnrealTournament.ini wrote:ScriptLog: TestProjectileSpeed.SBRocketMk0.PostBeginPlay starting with SmokeRate=0.000000, ProjectileSpeed=20.000000, Speed=900.000000
ScriptLog: TestProjectileSpeed.SBRocketMk0.PostBeginPlay finished with SmokeRate=10.000000, ProjectileSpeed=20.000000, Speed=20.000000
ScriptLog: TestProjectileSpeed.SBRocketMk0.PostNetBeginPlay: Speed=20.000000
Warning: New actor channel received non-open packet: 0/1/1
So "ProjectileSpeed" is not replicated?

Re: Projectile speed replication

PostPosted: Sat Mar 23, 2019 10:38 pm
by sektor2111
You lost me here. If this projectile has a "defaultproperty" with your desired value, client should know a "defaultproperty" of a certain class if package is being sent to client as it knows other stock things. If that property is changed/changeable via INI... umm... nwm, I'm not going to roam client again - ACE won't love what I do...

Re: Projectile speed replication

PostPosted: Sun Mar 24, 2019 11:23 am
by Feralidragon
It's been a looooong while since I looked at anything concerning projectiles, but I am pretty sure that by the time you call PostBeginPlay, you still don't have any initial values replicated/processed from the server, and that's why you have PostNetBeginPlay, which is only called after the first batch of replicated properties, and that's where you should set the speed in order for it to work online.

In later engine iterations, namely UE3, Epic realized how stupid it was to have 2 different events like this, so they just moved PostBeginPlay to be called later, at PostNetBeginPlay time, and removed the latter.

Re: Projectile speed replication

PostPosted: Sun Mar 24, 2019 1:14 pm
by TheDane
You can set it dynamicly through the game with a mutator doing a:

Code: Select all
var config float ConfigurableVariable;

function bool AlwaysKeep(Actor Other)
{
   if (Other.IsA('SBRocketMk2'))
        {
      SBRocketMk2(Other).ProjectileSpeed = ConfigurableVariable;
      return true;
      }
   
   if ( NextMutator != None )
      return ( NextMutator.AlwaysKeep(Other) );
   return false;
}


You can build the above script into any mutator you have running, or ofcause make it as stand-alone. If you use it as stand-alone be sure not to break the chain in the functions (call super and such).

Re: Projectile speed replication

PostPosted: Sun Mar 24, 2019 4:22 pm
by Higor
PostBeginPlay your replicated vars haven't been set.

PostNetBeginPlay projectile physics has already been initialized by PostBeginPlay.

Solution?
Reinitialize projectile physics in PostNetBeginPlay.