Announcement

Collapse

The Infinity Blade Forums Have Moved

We've launched brand new Infinity Blade forums with improved features and revamped layout. We've also included a complete archive of the previous posts. Come check out the new Infinity Blade forums.
See more
See less

TUTORIAL: Replicating a flashlight's state

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

    TUTORIAL: Replicating a flashlight's state

    I've been trying to understand replication so based on a question on the UDK forums I decided to implement a flash light whose on/off state can be replicated.

    First, create a subclass of a SpotLightMovable which will act as the flash light.
    Code:
    class MyFlashLight extends SpotLightMovable
        notplaceable;
    
    defaultproperties
    {
        Begin Object name=SpotLightComponent0
            LightColor=(R=255,G=0,B=0)
        End Object
        bNoDelete=FALSE
    }

    Next, we will modify our custom pawn by adding the flashlight as a variable.

    Code:
    var MyFlashLight FlashLight;
    We also need a variable that we will replicate the flashlight's on/off state.

    Code:
    var repnotify bool bIsFlashlightOn; /// whether the flashlight is on or not
    Then in the pawn's PostBeginPlay, we will attach the flash light to the pawn.

    Code:
    simulated function PostBeginPlay()
    {
        FlashLight = Spawn(class'MyFlashLight', self);
        FlashLight.SetBase(self);
        FlashLight.LightComponent.SetEnabled(self.default.bIsFlashlightOn);
        super.PostBeginPlay();
    }
    And set the variable's default value in the pawn's default properties.

    Code:
    defaultproperties
    {
        ...
        bIsFlashlightOn=true
    }
    Now we need a way to switch the flashlight on and off. We will set this up via an exec function that will be called when the "R" key is pressed. I added my key bind to the DefaultInput.ini (You might need to make the file writable as its read-only by default).

    Add this line at the end of the section marked as Primary default bindings

    Code:
    .Bindings=(Name="R",Command="ToggleFlashlight")
    This says that when the R key is pressed the exec function ToggleFlashlight will be called. We will define the function in our cutsom PlayerController subclass.

    Code:
    exec function ToggleFlashlight()
    {
        MyPawn(Pawn).ToggleFlashlight();
    }
    This calls the PlayerController's Pawn's ToggleFlashlight function (a mouth-full I know). Now this is where the magic happens. Since we essentially have all the information we need to determine whether the flash light can be turned on or not (without consulting the server) we can do what is nessecary to switch on the flashlight. To do this, we need to mark the funtion with the simulated keyword.

    Code:
    simulated function ToggleFlashlight()
    {
        bIsFlashlightOn = !bIsFlashlightOn;
        FlashLightToggled();
        // if we are a remote client, make sure the Server toggles the flashlight
        if( Role < Role_Authority )
        {
             ServerToggleFlashlight();
        }
    }
    We start by changing the value of our variable that keeps track of the flashlight's state.

    Next we check whether we are a client - in which case we need to tell the server what we have done by calling a server function. The server function essentially does the same thing as the client version, but on the server.

    Code:
    reliable server function ServerToggleFlashlight()
    {
        bIsFlashlightOn = !bIsFlashlightOn;
        `log("ServerToggleFlashlight: " $ bIsFlashlightOn);
        FlashLightToggled();
    }
    You'll notice that both functions call the FlashLightToggled function. This does the actual state switch.

    Code:
    simulated function FlashLightToggled()
    {
        if(bIsFlashlightOn)
        {
            FlashLight.LightComponent.SetEnabled(true);
        }
        else
        {
            FlashLight.LightComponent.SetEnabled(false);
        }
    }
    This has taken care of the client that switched the flashlight on/off and the server, but what about the other clients. If you look at the definition of the bIsFlashlightOn variable, its defined as repnotify. What this does is whenever the variable changes, a special function ReplicatedEvent is called.

    Code:
    simulated event ReplicatedEvent(name VarName)
    {
        if (VarName == 'bIsFlashlightOn')
        {
    	FlashLightToggled();
        }
        else
        {
    	Super.ReplicatedEvent(VarName);
        }
    }
    This function will be called on all the clients including the client that initiated the whole thing.

    We also need a way to tell the server when to send the variable to its clients, this is done through a replication condition in our pawn class like this.

    Code:
    replication
    {
    	// replicated properties
    	if ( bNetDirty )
    		bIsFlashlightOn;
    }
    That about covers it. Here are the full sources for each of the 3 classes we have touched on.

    MyFlashlight.uc

    Code:
    class MyFlashLight extends SpotLightMovable
        notplaceable;
    
    
    defaultproperties
    {
        Begin Object name=SpotLightComponent0
    	LightColor=(R=255,G=0,B=0) /// red so we can see the change
        End Object
        bNoDelete=FALSE
    }
    MyPawn.uc

    Code:
    class MyPawn extends UTPawn
    	config(Game)
    	notplaceable;
    
    var MyFlashLight FlashLight;
    var repnotify bool bIsFlashlightOn; /// whether the flashlight is on or not
    
    replication
    {
    	// replicated properties
    	if ( bNetDirty )
    		bIsFlashlightOn;
    }
    
    simulated function PostBeginPlay()
    {
        FlashLight = Spawn(class'MyFlashLight', self);
        FlashLight.SetBase(self);
        FlashLight.LightComponent.SetEnabled(self.default.bIsFlashlightOn);
        super.PostBeginPlay();
    }
    
    /**
     * Check on various replicated data and act accordingly.
     */
    simulated event ReplicatedEvent(name VarName)
    {
        `log(VarName @ "replicated");
        if (VarName == 'bIsFlashlightOn')
        {
        	FlashLightToggled();
        	`log("bIsFlashlightOn replicated");
        }
        else
        {
        	Super.ReplicatedEvent(VarName);
        }
    }
    
    simulated function ToggleFlashlight()
    {
        bIsFlashlightOn = !bIsFlashlightOn;
        `log("ToggleFlashlight: " $ bIsFlashlightOn);
        FlashLightToggled();
        // if we are a remote client, make sure the Server Set's toggles the flashlight
        `log("Role:" @ Role);
    	if( Role < Role_Authority )
    	{
    		ServerToggleFlashlight();
    	}
    }
    
    reliable server function ServerToggleFlashlight()
    {
        bIsFlashlightOn = !bIsFlashlightOn;
        `log("ServerToggleFlashlight: " $ bIsFlashlightOn);
        FlashLightToggled();
    }
    
    simulated function FlashLightToggled()
    {
        if(bIsFlashlightOn)
        {
            FlashLight.LightComponent.SetEnabled(true);
        }
        else
        {
            FlashLight.LightComponent.SetEnabled(false);
        }
    }
    
    defaultproperties
    {
        bIsFlashlightOn=true
    }
    MyPlayerController.uc

    Code:
    class MyPlayerController extends UTPlayerController;
    
    exec function ToggleFlashlight()
    {
        MyPawn(Pawn).ToggleFlashlight();
    }
    
    state Dead
    {
      function EndState(name NextStateName)
      {
        SetBehindView(default.bBehindView);
      }
    }
    
    defaultproperties
    {
        bBehindView = true
    }

    #2
    FlashLight.LightComponent.SetEnabled(bIsFlashlight On) would be a little more efficient than the if .. else

    Comment


      #3
      boom! here it is!
      will be trying that as soon as im home

      Comment


        #4
        Originally posted by Blade[UG] View Post
        FlashLight.LightComponent.SetEnabled(bIsFlashlight On) would be a little more efficient than the if .. else
        Makes sense, thanks.

        Comment


          #5
          Thanks thelaw. This was my problem, as you might have known. So, I got that working, however, when you SetBase(self), you can't move the flashlight up and down. So here's what I did:

          Code:
          class BSFlashLight extends SpotLightMovable;
          ...
          function Tick( float DeltaTime )
          {
             if (P != None)
                SetRotation(UTPlayerController(P.Controller).Rotation);
          }
          This works for the server, but not the clients. Do you know of a way to replicate the pitch of the flashlight?

          Comment


            #6
            Create a function that's simulated in order to do it?

            Comment


              #7
              Awesome, this is just what I have been looking for, thnx a lot thelaw, now i only need to get the flashlight to work on battery power that needs to be collected, and i'll have the basic gameplay setup for my game

              @Kyben what does P represent in your code?

              Comment


                #8
                Originally posted by Kyben View Post
                ...This works for the server, but not the clients. Do you know of a way to replicate the pitch of the flashlight?
                You don't need to replicate a pitch when there is already one replicated for you. Get it using the function Pawn.GetViewRotation.

                Comment


                  #9
                  Originally posted by NemesisX64 View Post
                  @Kyben what does P represent in your code?
                  It'll be a pawn. It's pseudocode though, so copy+paste won't work

                  Comment


                    #10
                    Originally posted by ambershee View Post
                    It'll be a pawn. It's pseudocode though, so copy+paste won't work
                    yeah i got that, was just trying to figure out how the code was supposed to work, wasn't sure what P was

                    EDIT: ok that pseudocode just baffles me, can anyone point me to what i should change in it, so that it works for me, I tried changing it around a bit, but it seams that my UnrealScript skill is not high enough to make it usable

                    Comment


                      #11
                      yeah getting the rotation to work would be nice...

                      is it possible to attach a particle effect to this?


                      maybe someone can figure out what to take from this code and implement in the above, to get the rotation to work

                      http://wiki.beyondunreal.com/Legacy:...FlashLight_2k3

                      Comment


                        #12
                        Originally posted by Mr Evil View Post
                        You don't need to replicate a pitch when there is already one replicated for you. Get it using the function Pawn.GetViewRotation.
                        if you have the light attached to a socket, you probably don't even need to do anything

                        Comment


                          #13
                          Sorry, P is the pawn it's attached to.

                          @ ambershee: Tried it. I think its because the rotation of the playercontroller isn't replicated?

                          @ Blade[UG]: Replicating attachments to a socket would be lovely. I've tried everything, but no dice. I feel like I'm jumping through 20 hoops to get around something that should be simple. I know its possible, but I can't figure it out.

                          Comment


                            #14
                            Code:
                            simulated function PostBeginPlay() {
                                super.PostBeginPlay();
                                SetBase(MyPawn, , MyPawn.Mesh, 'FlashlightSocket');
                            }

                            Comment


                              #15
                              Originally posted by Blade[UG] View Post
                              Code:
                              simulated function PostBeginPlay() {
                                  super.PostBeginPlay();
                                  SetBase(MyPawn, , MyPawn.Mesh, 'FlashlightSocket');
                              }
                              I got sth like

                              Code:
                              FlashLight.SetBase(self, , self.Mesh, 'FlashLightSocket');
                              And I have created a FlashLightSocket on the model. But for some reason this is still not working (The FlashLight still works but just like it did with SetBase(self); without the socket addition). Any ideas what I'm doing wrong?

                              Comment

                              Working...
                              X