Announcement

Collapse
No announcement yet.

Replication from the Mutator Class? How?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Replication from the Mutator Class? How?

    So, now that we have a bit of a handle on things that Epic no longer replicates for us, I have been taking a look at some mutators out there to get a better feel for how people are replicating their mutators. There are still some confusing issues that I am still not understanding.

    I see many people subclassing the Info class to add their replication there. They are spawning a version of their Info subclass from their Mutator class and running the code in there and that is getting replicated.

    But I usually see people using Tick for their function. Some functions don't need to be called at every Tick I wouldn't think.

    - Is Tick replicated Clientside?

    - Assuming that it is can Tick be put into the Mutator class without being in an Info subclass?

    - Since modifyPlayer isn't replicated, what would be the purpose of using modifyplayer? Is there another function that would be more useful for modifying player values instead of Tick? Perhaps PostBeginPlay or something?

    - How can we tell which functions are replicated and which ones aren't?

    How would you make something like a groundspeed modifier mutator using only the Mutator subclass, but making sure it is replicated to all clients? I've heard it can be done without using the info subclass

    #2
    No functions are replicated except those marked with client or server.

    What you really mean are which functions are called by code or the engine both server side and client side.

    Tick() is called by the engine for actors with role simulated proxies and above. It can be better to set up a looped timer instead though, depending on you requirements. PostBeginPlay() is also called client side, but you I believe you can't rely on all of the actor's variables being replicated at that point.

    Comment


      #3
      Originally posted by KewlAzMe View Post
      So, now that we have a bit of a handle on things that Epic no longer replicates for us, I have been taking a look at some mutators out there to get a better feel for how people are replicating their mutators. There are still some confusing issues that I am still not understanding.

      I see many people subclassing the Info class to add their replication there. They are spawning a version of their Info subclass from their Mutator class and running the code in there and that is getting replicated.

      But I usually see people using Tick for their function. Some functions don't need to be called at every Tick I wouldn't think.

      - Is Tick replicated Clientside?

      - Assuming that it is can Tick be put into the Mutator class without being in an Info subclass?

      - Since modifyPlayer isn't replicated, what would be the purpose of using modifyplayer? Is there another function that would be more useful for modifying player values instead of Tick? Perhaps PostBeginPlay or something?

      - How can we tell which functions are replicated and which ones aren't?

      How would you make something like a groundspeed modifier mutator using only the Mutator subclass, but making sure it is replicated to all clients? I've heard it can be done without using the info subclass
      ModifyPlayer() in the mutator class is all you would need to create a groundspeed modifier mutator.

      an example would be:
      Code:
      simulated function ModifyPlayer(Pawn Other)
      {
      	local UTPawn P;
      
      	if (UTPawn(Other) != None)
      	{
      		P = UTPawn(Other);
      		P.GroundSpeed = P.default.GroundSpeed * 2;
      	}
      
      	Super.ModifyPlayer(Other);
      }
      The above code would double the GroundSpeed for all pawns. I am sure that will work on a server/client game. I am using ModifyPlayer() for modifications to the player's pawn in my Configurable UT3 mutator and seems to work just fine.

      Comment


        #4
        Originally posted by warlord57 View Post
        I am using ModifyPlayer() for modifications to the player's pawn in my Configurable UT3 mutator and seems to work just fine.
        Well it doesn't .... hence the purpose of this post. ModifyPlayer certainly does not work online. Tho I'm not sure if putting "simulated" in front of it works, tho I am pretty sure i've tried that too without success

        Comment


          #5
          Originally posted by KewlAzMe View Post
          Well it doesn't .... hence the purpose of this post. ModifyPlayer certainly does not work online. Tho I'm not sure if putting "simulated" in front of it works, tho I am pretty sure i've tried that too without success
          ModifyPlayer should work fine, as long as what you're modifying is itself replicated (and GroundSpeed is). Could you post your code? There may be something else going on.

          Making it simulated will do nothing because a) mutators don't exist on clients, and b) even if they did, nothing ever calls ModifyPlayer on clients, so it would never be executed.

          Comment


            #6
            Ok Perhaps Groundspeed was a bad example.

            Code:
            function ModifyPlayer(Pawn Other)
            {
            	local UTPawn P;
            
            	if (UTPawn(Other) != None)
            	{
            		P = UTPawn(Other);
            		P.MultiJumpRemaining = 4;
            	}
            
            	Super.ModifyPlayer(Other);
            }
            This is the actual setting in question. The MultiJumpRemaining variable is not replicated, and modifyplayer isn't run on a client. So how could I replicate this on clients using only the Mutator subclass and no other files?

            Comment


              #7
              Is there a particular reason why you have to use only a mutator? It could be done, but it would be horribly inefficient. If I were doing it, I would give everyone an Inventory item in ModifyPlayer and use ClientGivenTo to set whatever needs to be done clientside for that pawn.

              Comment


                #8
                Originally posted by Mr Evil View Post
                Is there a particular reason why you have to use only a mutator? It could be done, but it would be horribly inefficient. If I were doing it, I would give everyone an Inventory item in ModifyPlayer and use ClientGivenTo to set whatever needs to be done clientside for that pawn.
                Well I guess I'm trying to find out the most efficient way. Someone told me that a jump mutator should be simple and have no need to use any other classes but the mutator class. So I assume that IS the most efficient way.

                But can you explain a bit more about what you are saying. Are you would subclass the Inventory class and run ModifyPlayer from there and inside that run ClientGivenTo?

                I'm so close to grasping the concept but as soon as I think I've figured it out, I lose it.

                Comment


                  #9
                  Looking at UTPawn.uc, I see that MultiJumpRemaining is initialized from MaxMultiJump, so setting that instead should have the desired effect. Now, MaxMultiJump isn't in the replication statement either, but it was replicated in UT2004, and UTPawn says nativereplication at the top, so it might still be replicated invisibly. Try it and see what happens.

                  If you do end up needing to do it the inventory way, override ClientGivenTo in your inventory class and modify the pawn in there. That function is called when the inventory is given to a player and automatically replicated to the client (it is only executed on the client, so you need to modify the pawn on the server somewhere too). Then use CreateInventory in the mutator to give every pawn your inventory item when they spawn.

                  Don't worry about it; replication confuses everyone.

                  Comment


                    #10
                    Why does that number need to be replicated, anyway? Shouldn't it be something that happens on the server? Why would the client need to know about it?

                    Comment


                      #11
                      Items that are natively replicated still have to appear in the replication block, IIRC.

                      Comment


                        #12
                        MaxMultiJump needs to be set on the client's machine or else the client won't let them keep jumping, even though the server would.

                        Simple but overkill method (I wrote this out of my head just now, so it may or may not compile/actually work):

                        Code:
                        class UTMutator_Multijump extends UTMutator config(UTMutator_Multijump);
                        
                        var() config int NewMaxJump;
                        
                        replication {
                           if (Role == ROLE_Authority)
                               NewMaxJump;
                        }
                        
                        function ModifyPlayer(Pawn Other)
                        {
                        	local UTPawn P;
                        
                        	if (UTPawn(Other) != None)
                        	{
                        		P = UTPawn(Other);
                        		P.MaxMultiJump = NewMaxJump;
                        	}
                        
                        	Super.ModifyPlayer(Other);
                        }
                        
                        simulated function tick(float delta) {
                            local UTPawn pawn;
                        
                            foreach worldInfo.AllPawns(class'UTPawn', pawn) {
                                pawn.MaxMultiJump = NewMaxJump;
                            }
                        }
                        
                        defaultproperties {
                           bAlwaysRelevent=true
                           RemoteRole=ROLE_SimulatedProxy
                        }
                        Something like that anyway. The tick is overkill, it could be replaced by a looped timer with a reasonable time increment, and there could be a check to just not do it unless worldinfo.netmode == NM_Client, because ModifyPlayer works otherwise.

                        Comment


                          #13
                          Originally posted by immortius View Post
                          Simple but overkill method (I wrote this out of my head just now, so it may or may not compile/actually work):...
                          I wasn't going to post that method because it's horrible. Using an inventory item is more complicated, but it's a "proper" way to do it.

                          Comment


                            #14
                            Originally posted by Mr Evil View Post
                            I wasn't going to post that method because it's horrible. Using an inventory item is more complicated, but it's a "proper" way to do it.
                            True enough, that would avoid the need for wasted ticks/timers because it can set the value client side when the pawn receives it.

                            Comment


                              #15
                              So is the idea to find a relevant function that executes on the client, and override it to add your stuff?

                              I see ClientGivenTo is used for JumpBoots and other power pickups like Berserk. So I would treat the Multijumps as a bonus that was given at spawn? Add something like

                              Code:
                              Class MultiJumpInv Extends UTInventory;
                              
                              replication
                              {
                              	if (Role == ROLE_Authority) {
                                          iMaxNumJumps;
                              	}
                              }
                              
                              reliable client function ClientGivenTo(Pawn NewOwner, bool bDoNotActivate)
                              {
                              	local UTPawn P;
                              	
                              	P = UTPawn(NewOwner);
                              
                              	Super.ClientGivenTo(NewOwner, bDoNotActivate);
                              	if (Role < ROLE_Authority) {
                              		if (P != None) {
                              			P.MaxMultiJump = MultiJumpMut.iMaxNumJumps;
                              		}
                              	}
                              }
                              
                              defaultproperties {
                                 bAlwaysRelevent=true
                                 RemoteRole=ROLE_SimulatedProxy
                              }
                              And then in the Mutator class I would have:

                              Code:
                              Class MultiJumpMut extends UTMutator Config(MultiJump);
                              
                              var() config int iMaxNumJumps;
                              
                              function ModifyPlayer(Pawn Other)
                              {
                              	local UTPawn P;
                              
                                      P = UTPawn(Other)
                              	if (P != None)
                              	{
                              		P.CreateInventory(class'MultiJump.MultiJumpInv');
                              	}
                              
                              	Super.ModifyPlayer(Other);
                              }
                              
                              defaultproperties
                              {
                                 iMaxNumJumps=4
                                 Begin Object Name=Sprite ObjName=Sprite Archetype=SpriteComponent'UTGame.Default__UTMutator:Sprite'
                                    ObjectArchetype=SpriteComponent'UTGame.Default__UTMutator:Sprite'
                                 End Object
                                 Components(0)=Sprite
                                 RemoteRole=ROLE_SimulatedProxy
                                 bAlwaysRelevant=True
                                 Name="Default__UTMutator_MultiJump"
                                 ObjectArchetype=UTMutator'UTGame.Default__UTMutator'
                              }
                              Am I at least on the right track?

                              Comment

                              Working...
                              X