Birds fly. Sun shines. And brother? Brutes shoot people.

[Netcode] Trying to replicate simple things is driving me insane

For questions and discussion about UnrealEd, UnrealScript, and other aspects of Unreal Engine design.

Moderators: Semfry, ividyon

gopostal
Skaarj Lord Skaarj Lord
Posts: 152
Joined: 01 Aug 2008, 06:35

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 15:24

You can grab health on a pawn any time you want since it's a default property of the class and will always be readable. I would shy away from using any sort of timer when you don't have to, instead use events to your advantage to update PRI. For example I just added a bit of code to my coop server last night that checks monster health and if it is larger than a set value it is adjusted down:

Code: Select all

function MutateReduceDamage(out int Damage, name Type, pawn Injured, pawn InstigatedBy)
{
   if (Injured != None && InstigatedBy != None)
   {
      // This will limit the max health of any pawn in case it is too high
      if(Injured.IsA('ScriptedPawn'))
         if(Injured.Health > MaxMonsterHealth)
            Injured.Health = MaxMonsterHealth;
      

My max is set to 500 on the server so if you damage any monster and it has a health >500 it will instantly adjust it down. Why go this route? A couple of reasons honestly. First if you use a timer to check monster health then you are adding stress to the server regularly. Second, if you try to address this in a fast check in PreBeginPlay then you can miss factory generated monsters that may spawn after the map is underway. By adding the check into this function it's only run when damage is dealt, making it very quick. One could also add to this function and adjust the player's health if it starts to get too low, thereby making all the 999 health settings/health drip/mega health pickups pretty much moot in a single swipe.

I outlined the above because all along in there you can add any of this stuff to the player's PRI in your own defined setting but it's best to use events to make the change rather than timed checks.

User avatar Buff Skeleton
>:E >:E
Posts: 4173
Joined: 15 Dec 2007, 00:46

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 16:06

Good call. I guess if I want to report a player's dead/alive state I could have a simple bool, bAlive, which is false by default and only becomes true during PostLogin, and gets set back to false during Killed, and just flip the switch in the PRI in each case. Sound like a better solution?

[Edit] By the way gopostal, I just now realized I completely missed your first post in this thread earlier, durrr. My bad!
Image

User avatar Buff Skeleton
>:E >:E
Posts: 4173
Joined: 15 Dec 2007, 00:46

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 16:42

Now I'm running into this bullshit compile error I don't understand at all:

Code: Select all

Error: ..\EXU2BI\Classes\EXU2CoopGame.uc(317) : Error, Unrecognized member 'bCurrentlyAlive' in class 'EXUPlayerReplicationInfo'


Which is completely stupid because it IS defined in the class:

Code: Select all

class EXUPlayerReplicationInfo extends PlayerReplicationInfo;

var bool bCurrentlyAlive;
var int KillCount;
var int TeamKillCount;
var int DeathCount;
var int SuicideCount;

replication
{
   reliable if( Role==ROLE_Authority )
      bCurrentlyAlive, KillCount, TeamKillCount, DeathCount, SuicideCount;
}


And all I'm doing is casting to that class so I can access it the way you would cast to any other class to access its class-specific variables:

Code: Select all

   if( PlayerPawn(Other)!=None && EXUPlayerReplicationInfo(PlayerPawn(Other).PlayerReplicationInfo)!=None )
   {
      EXUPlayerReplicationInfo(PlayerPawn(Other).PlayerReplicationInfo).bCurrentlyAlive = False;
      log(Other$" Killed - bCurrentlyAlive: "$EXUPlayerReplicationInfo(PlayerPawn(Other).PlayerReplicationInfo).bCurrentlyAlive);
   }


Am I missing something here? I can't figure out what is wrong with the syntax to throw this kind of error.


Haha nevermind, I have two EXUPlayerReplicationInfo classes because one of them is used for ScriptedPawns in EXU.u. Derrrrp. Gonna have to make an EXU2PlayerReplicationInfo for EXU2BI I guess

[Edit2] This seems to be working so far! The next test is to be sure values actually update properly regardless of whether or not a player is visible, but it should do that now since it's all within a PRI instead of some hacked-together clusterfuck inventory item! Thanks so much gopostal!
Image

gopostal
Skaarj Lord Skaarj Lord
Posts: 152
Joined: 01 Aug 2008, 06:35

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 18:59

Glad to help. I spent the better part of a summer working through all this stuff on my own. OFC I read the 'replication deobfuscation' document over and over, even printing it out and taking it with me on my route to read on lunches. FeraliDragon was a huge help too, pointing me back when I would get lost. In the end though it was code>compile>test online about 70 billion cycles. Trust me, if I sound a little glib or flippant when I say "Just do this" Don't read much into that. I got there the hard way, no sense in anyone else having to reinvent the wheel if you can take my model and make it better.

One thing I would love if you get the time is for you to keep tabs on the Unreal changes you needed to make. Eventually I'm going to code up a stats system for my coop server (top players, best scores, etc) as well as a spending system for extra inventory items that I'm going to craft. The scanner was a server freebie but the rest of the goodies I have planned will cost ya some time on server ;) Knowing ahead of time where I'll need to change things would be a big help.

User avatar Buff Skeleton
>:E >:E
Posts: 4173
Joined: 15 Dec 2007, 00:46

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 19:03

You mean the differences between implementing this on UT instead of Unreal? I hardly made any changes to your basic methodology, honestly; it worked just fine in UT with the same stuff. I could have almost copy-pasted it. If you're interested, I can post all the relevant code I used to get this to work.
Image

gopostal
Skaarj Lord Skaarj Lord
Posts: 152
Joined: 01 Aug 2008, 06:35

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 19:18

I'm thrilled it worked with so little effort! That's great news :) As a way of closing this out so future searchers can learn from it you might briefly lay out what you did. So little good information exists on PRI applications you can bet this will be seen high on the google searches once it gets indexed. You'd be doing a favor for other coders (and myself).

User avatar Buff Skeleton
>:E >:E
Posts: 4173
Joined: 15 Dec 2007, 00:46

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 19:42

OK, here's the process I used, per your advice:

1. Create a custom PRI

Code: Select all

class EXU2BIPRI extends PlayerReplicationInfo;

var bool bCurrentlyAlive;
var int KillCount;
var int TeamKillCount;
var int DeathCount;
var int SuicideCount;

replication
{
   reliable if( Role==ROLE_Authority )
      bCurrentlyAlive, KillCount, TeamKillCount, DeathCount, SuicideCount;
}


2. Implement custom PRI in GameInfo's Basemutator

Code: Select all

class EXU2CoopSettings extends EXU2GlobalSettings; // EXU2GlobalSettings is the standard BaseMutator for EXU2Game (primary GameInfo), of which EXU2CoopGame is a subclass

// Basemutator for EXU2 Coop games. Added the PRI switcheroo here; thanks gopostal for the advice!

simulated function bool AlwaysKeep( actor Other )
{
   if( PlayerPawn(Other)!=None )
   {
      PlayerPawn(Other).PlayerReplicationInfoClass = class'EXU2BIPRI';
      return True;
   }

   if( NextMutator!=None )
      return NextMutator.AlwaysKeep(Other);

   return False;
}


3. Implement checks in the GameInfo. In EXU2CoopGame, for example, I have a check in Login to mark new players as alive:

This is within the if( NewPlayer!=None ) block AND in the RestartPlayer() if( foundStart ) block

Code: Select all

      if( EXU2BIPRI(NewPlayer.PlayerReplicationInfo)!=None )
         EXU2BIPRI(NewPlayer.PlayerReplicationInfo).bCurrentlyAlive = True; // This defaults to false and thus must be actively set to True when a player is guaranteed to be alive (i.e. at initial login or at player restart) to ensure correct status on scoreboard


This is in Killed(), just after the call to Super.Killed

Code: Select all

   if( PlayerPawn(Other)!=None && EXU2BIPRI(PlayerPawn(Other).PlayerReplicationInfo)!=None )
   {
      EXU2BIPRI(PlayerPawn(Other).PlayerReplicationInfo).bCurrentlyAlive = False;
      EXU2BIPRI(PlayerPawn(Other).PlayerReplicationInfo).DeathCount++;
      
      if( Killer==PlayerPawn(Other) || Killer==None )
         EXU2BIPRI(PlayerPawn(Other).PlayerReplicationInfo).SuicideCount++;
   }


And this is in ScoreKill() since I calculate TeamKill point devaluation there already

Code: Select all

      if( PlayerPawn(Other)!=None )
      {
         PointValue = -2500;   // PAY THE IRON PRICE

         if( EXU2BIPRI(PlayerPawn(Killer).PlayerReplicationInfo)!=None )
            EXU2BIPRI(PlayerPawn(Killer).PlayerReplicationInfo).TeamKillCount++;
      }


And a bit below that, the kill count

Code: Select all

      if( Other.IsA('EXUScriptedPawn') && class'EXUStaticFuncs'.static.bHasPawnTag(EXUScriptedPawn(Other), 'DontScore') )
         PointValue = 0;
      else
      {
         if( EXU2BIPRI(PlayerPawn(Killer).PlayerReplicationInfo)!=None )
            EXU2BIPRI(PlayerPawn(Killer).PlayerReplicationInfo).KillCount++;   // This IS replicated and useful

         Killer.KillCount++;   // This apparently is not even useful since it isn't replicated from what I can tell
      }


4. Implement display of values on Scoreboard

You have your variables (among others): var Deaths[16], Suicides[16], Kills[16], TeamKills[16];

Your scoreboard loop for each player (this is actually probably really poorly optimized; I copied it almost verbatim from Unreal's coop scoreboard as a base because I was too lazy / inexperienced to write one from scratch):

Code: Select all

   foreach AllActors( class'PlayerReplicationInfo', PRI )
   {
      if( !PRI.bIsSpectator )
      {
         PlayerNames[PlayerCount] = PRI.PlayerName;
         TeamNames[PlayerCount] = PRI.TeamName;
         Scores[PlayerCount] = PRI.Score;
         Teams[PlayerCount] = PRI.Team;
         Pings[PlayerCount] = PRI.Ping;
         
         if( EXU2BIPRI(PRI)!=None )
         {
            Deaths[PlayerCount] = EXU2BIPRI(PRI).DeathCount;
            Suicides[PlayerCount] = EXU2BIPRI(PRI).SuicideCount;
            Kills[PlayerCount] = EXU2BIPRI(PRI).KillCount;
            TeamKills[PlayerCount] = EXU2BIPRI(PRI).TeamKillCount;
         }

         if( EXU2BIPRI(PRI)!=None && !EXU2BIPRI(PRI).bCurrentlyAlive )
            L = "A Corpse and/or Corpse Pieces";
         else if( PRI.PlayerLocation!=None )
            L = PRI.PlayerLocation.LocationName;
         else if( PRI.PlayerZone!=None )
            L = PRI.PlayerZone.ZoneName;
         else
            L = "Wandering the Hellscape";

         PlayerLocations[PlayerCount] = L;

         PlayerCount++;
      }
   }


And that's about it. Everything else that uses those variables is handled in the scoreboard in ways you'd expect (i.e. ways you can see by example or come up with on your own). Having a custom PRI is way more handy than I expected!
Image

gopostal
Skaarj Lord Skaarj Lord
Posts: 152
Joined: 01 Aug 2008, 06:35

Subject: Re: [Netcode] Trying to replicate simple things is driving me insane

Post Posted: 01 Jul 2013, 20:02

You da man!

Image

Previous

Who is online

Users browsing this forum: No registered users and 24 guests

Copyright © 2001-2024 UnrealSP.org

Powered by phpBB® Forum Software © phpBB Limited