Hello, this is Youngho Lee
In this unit, we will learn firing and reloading
Similar to take pistol and release pistol
we will use RPC
and we'll see how what the server performs
and what client performs is divided
Fire using RPC
First is fire
Fire on network
similar to take pistol and release pistol that we did
uses RPC communication
The logic is like this
Here, there's a client
and the client receives a fire input
It gets this input
and the client, with this input
requests the server
that it wants to fire
with RPC, a server RPC
to the server
Then the server receives this server RPC
and performs fire logic
Like line trace and fire
It performs fire logic and the result
is sent to the client
like 'hey there's this piece flying off'
'so update the UI', these requests are made
That will be the client or NetMulticast RPC
In this format, the request is sent to clients
Then, the client or the clients of Multicast
will perform according to this RPC request
Fire happens in this flow
Now let's make this
Go to Visual Studio
and to NetTPSCharacter header file
Let's make the fire part here on the very bottom
When user inputs fire
we're going to add a server RPC function
UFunction, server as it's a server RPC
and reliable
Then Void ServerRPC_Fire
This means requesting fire to the server
Let's implement this function
ServerRPC Fire Implementation function's implementation
will be move to under the fire function
to make it easier to work with
Then, there needs a part where
client or NetMulticast RPC is called within here
Like I mentioned using the diagram
the part where the clients receives input
and where it requests server RPC
must be divided
So when Fire function is called
that's when the user presses on the fire button
When that happens, if it's not holding a pistol
or if there's no bullet left
or if it's reloading
Unless these cases, the below is performed
If it's holding a pistol, the following will be performed
Does this fire part happen on the client side?
No. It will happen in the server
Let's use server RPC to do that
Call ServerRPC Fire
and where will these that are the actual pistol firing go
They should move to the client side
Let's first move it to the ServerRPC part
When fire button is pressed, this happens
and then it requests the server to perform fire
Then, fire is performed using server RPC
The fire logic is performed in the server like this
But showing the shot particles is related to rendering
It's a visual aspect
This part isn't done in the server, where does it happen?
On the client side
Then the UI update
This part will also be done on the client side
and animation will also be there
So these need to be worked on separately
To work on this fire action
separately from server and client
let's make the part that the client will do
using NetMulticast RPC
Go to header file
To NetTPSCharacter's header file
Here, to use a NetMulticast RPC
u Function NetMulticast, then you can say reliable
but I'll put unreliable here
The reason of putting unreliable is
This part here
The core logic of fire
will all happen in the server
Right? The demage process
and HP decrement will happen here
But particle effects and such
will have to happen in the client
But is particle effect necessary when a shot is fired?
It isn't
It won't matter if this doesn't happen once or twice
Even if it's omitted, the data itself isn't being deleted
so the user's data like HP
will be processed in the server so it will be maintained
but the effect might not happen once in a while
depending on network circumstances
But important parts like HP
will be done in the server so it doesn't matter
So the visual effects
of fire for the client
doesn't matter too much to be considered absolutely necessary
so I'll put unreliable
void Multicast RPC_Fire
And for the parameter
we might need information about the collision point and whether it did collide or not
Why? Because only when it did, on the spot it did
the particle effect must show
So on the parameter
we'll put bool, bHit
and then const fHitResult
Then hitinfo with annotation
Then if it did collide, if true value was input
that point will have particle effect
and this will be performed
Let's add implementation on Multicast RPC Fire
I added implementation on NetTPSCharacter.cpp
What do we want to do when it collided?
We want particles on the collision point
When bHit is true, this part needs to be performed
I'll take this part and put it here
So if bHit value is true
particles will show
Next, for bulletCount that removes bullets
the data is changed in the server
so the client doesn't need to care about this
But this part is needed
Updating the mainUI is needed
So we'll take this part
and put it here
I just cut it out
On the server RPC
does it need this part where it shows the particle?
The server doesn't, it just need to make the logic
It just needs to check if it did or didn't collide
and set the data by proving the logic when it did
That's the server's role
Then the effect of showing something on the screen
and UI update, these need to be done in the client
Before we take the animation part
the main UI also had a problem
before when we did take and release pistol
Other characters
that is, clients without player controller
do not make mainUI
In that case, mainUI is null
So only when there is a mainUI
this must be performed
if mainUI, for it to be performed only when
there is a mainUI
Lastly, on Multicast RPC fire
this is called on clients
So animation
must also be called on the client and not the server
Let's cut that out and bring it down here
Then the server simply checks the fire logic
and makes data
It removes bullets
Then its job is done
so it sends visualization request to the
client side
Then this Multicast RPC fire could be called from the server
From server RPC, Multicast RPC_fire
Let's call it
Here, bHit information needs to be included
and hitinfo as well
so that the data is sent on network
and the value delivered by parameter is used
to visualize these things
Great. When a shot is fire, the mainUI
does PopBullet and updates the number of bullets left of bulletCount
That's this part here
I'll build here
Let's see how it looks
Play, and I'll open server
and a client
Let's fire a shot
Let me do it from the client window
Take the pistol
I'll shoot to the wall
Pew pew
Can you spot the problem?
The animation is working both on the client
and on the server
Let me shoot to the ground
The effect is also working well on both sides
But one problem
The UI isn't being upated
Here, the bullet isn't being updated
on neither windows
Let's try on the server window
Server takes the pistol
Pew pew
On the server, the UI is updated
But it isn't on the client's window
It's because of this part
Let's go back to the logic
Looking at the fire logic of ours
the server performed the fire logic and changed the data
The client updated the screen with that data
and rendered for visualization
Then when there is a mainUI
it is set to pop bullet to match the current bulletCount when updating the UI
The bulletCount was decreased
and the data was sent to the client
using RPC
But the bulletCount wasn't properly applied
so bullets weren't popped
Then why did it work on the server
It sent a server RPC
Then the server RPC will do this
Then it sends a client
But how is the server RPC?
It's a server and a client
So from its point of view, I decreased it
on the server window
so even if its own RPC is called, it properly has the decreased count
But on the other client's screen
even if it was decreased on the server it wasn't sent to the client
Let's get back to the screen and shoot on the server
You can see that the server is being updated
This part own here is being updated
But on the client window it isn't
Why? Because this is using a server RPC
and this guy is a server and a client at the same time
So it decreased its own bulletCount
then with NetMulticast RPC
it was sent to call clients. Then what happens?
The server will send it to this one an also to the other window
The message will be set to here as well since it's a Multicast RPC
Then let's see
From here, the bulletCount decreased
because this bulletCount was sent back to me
I know this bulletCount data
That's why it decreased properly
On the other hand, the updated data was sent to this guy here
but this one isn't being updated
That means the bulletCount data wasn't sent properly
It was sent here but not here
Let's look at the bulletCount on our code
We're at the declaration of the bulletCount
We're at NetTPSCharacter.h's declaration
It isn't being synced at all on network
We didn't put such option in
So this needs property replication
That way, when value is changed on network
the server can automatically sync it
So here, on the number of bullets left
I'll put UPROPERTY.replicated
I just declared that I'll sync on network
Is this enough?
No
Go to cpp file
and on the GetLifetimeReplicatedProps function on the very bottom
we need to define it
We need to add implementation
Which one?
Sync the bulletCount
You need to add this implementation
That way the header can tell if it's subject to network syncing
and then on GetLifetimeReplicatedProps
the variable's property synchronization code will be performed
Let's build
Great. It's working fine on the server
Take the pistol and shoot
and you can see the bullet decreasing in the server
Now, on the client window
Just now the UI didn't update
Now, shooting from the client window
it's decreasing properly
But if we didn't work on this part here
If on GetLifetimeReplicatedProps
I didn't make it sync, what would happen?
Will the bulletCount be synced on network?
No, because it's only declared
I annotated the sync structure
Now looking at the screen
The server, it's its own data so the UI will be updated
There's no meaning in data syncing
because it's me changing my data
Because I'm the server and the client
But on for the client
it requests to the server with RPC
and that server RPC is decreasing the bulletCount
There's no way for the client to receive that data for now
Is it being updated?
It's not
Why? Because it's not activated
But if I activate this again
Play
On the server, the UI is properly updating
It didn't work on the client just now
Let's try on the client window
Now, we added the implementation
to make it sync
so now, you can see that the UI is being updated properly
The action taking place in this screen
is the server performing the RPC
and then on the client
the bulletCount was set to be synced
so the UI is updated
Look at the screen
On fire, it's not only RPC communication that happens
What else was there?
Property replication also happened
Property replication
So from that
The client is now requesting a server RPC
Since I wrote server RPC it looks like that's being performed here
but here it's just requesting
to the server
Then the server's logic performs the server RPC
Through the server RPC request, server code is performed
Then what happens here
It line traces
and on the collision point, bHit
With the information about the collision point, damage process is run
Damage process
Then after all this is done, to the client
what does it do?
It sends
Send to who?
To call clients, it sends with Multicast RPC
Then here, Multicast RPC
is called
and the Multicast RPC function is performed here
Here, particle effect
animation
and UI and such are being updated
But when trying to update this UI
the variable bulletCount
isn't being properly updated
The reason is because it only worked with RPC
So how did we fix this bulletCount?
We used property replication
We used UPROPERTY replicated
and then we registered bulletCount by putting DoRepLifetime
Then the bulletCount value was automatically
decreased in the server
So decreasing it by 1
synced it automatically and updated it
Then there's one thing to think about here
Does this have to be done with property replication?
It may not be
I'll annotate this instead of having it like this
Let's say we also turn this UPROPERTY replicate option
Then
will there be no way to sync?
No, there is a way
Here on MulticastRPC
I'll say const int32 and newBulletCount
So we're adding this part on MulticastRPC
on cpp
Then, on MulticastRPC Fire
we're handing this factor over, bulletCount
Then this bulletCount
will be delivered as a parameter factor on network
Right
Then what should we do with this value
We assign newBulletCount
on bulletCount
Good?
If we work this way
the updated value will be sent
Even this,
we can also make it update only when there's a mainUI
because it will be needed only in that case
I'll build here and see
Now the replicated part is gone
I deleted the property replication
Let's see
The server is updating properly
and the client as well
The UI is being updated properly
You can see it down here
So this part doesn't need to be
done with property replication only
You can use RPC
to make this work as well
But the reason why I told you this
is to tell you that you can use RPC
and also property replication
as well to make this work
Here, I'll change it back to how it was
so that both RPC and
property replication is used
Here, except for this part
I'll do ctrl z
Great
On get lifetime as well
we'll take it back to the original code
and on bulletCount, we'll put UPROPERTY, replicated back to its shape
This means I'll just keep the property replication and use that
We learned two ways to make fire work
Up until now was fire
I showed you that
on fire, you can use property replication and RPC
and that you don't have to
use RPC only or property replication only
but that both work
through that example
This was fire
Reload using RPC
Next is reload
It will use RPC
RPC, again, the clients
receives a certain input from the server
and requests to the server
Then the server
performs a logic according to that request
Here, when requesting to the server, what type of RPC is it?
Server RPC
It uses server RPC to request to the server
Then the server performs the logic
and the result is sent back to the client
Once that sent the visualization on reload is performed
How will that request work here
It was Multicast until now
but for reload
we'll use client RPC
We'll try using client RPC to do that
Why?
For reload
we'll say that only that client
needs to receive the result
Of course we can make every client see the reload animation
but reload itself might not
matter greatly to other users, the animation itself
But for the user reloading, the animation is very important
Why? Because the code that updates the UI once reload is done
is in the client
So here
client requests communication using server RPC to the server
then the server performs core logic
and sends client RPC to the client
Then client, again receives the visualization message
and does the rendering itself
That's how it'll work
Come to Visual Studio
and to NetTPSCharacter header file
On the very bottom, public
We're going to add a Multiplayer on reload
UFUNCTION, and we're going to use server RPC so put server and reliable
When there's an input in the server
this request must happen
It can't be omitted since it's an important input from a client
So we put reliable
but visualization
doesn't matter as greatly
The visualization
can be seen or not to the user
Those can work with unreliable as well
But reload animation for the client is very important
Why?
Because there is a code that updates the UI
once the reload animation is over
So those parts
need to have reliable
when sending a client RPC and the data
I'll mention that again later on
So we'll put void serverRPC
ServerRPC_Reload
We have ServerRPC_Reload on reload
and in addition to that
let's make the client RPC as well
This time, not server
and instead client
This one too, I'll put reliable
The reason is, as I keep telling you, the animation needs to be performed to update the UI
so it's done as reliable
I'll say void ClientRPC_Reload
Let's add implementation for the two functions
Added one on NetTPSCharacter cpp and the other one as well
I'll add implementation
I'll move these two, server RPC and client RPC
to under ReloadPistol, like this
Let's keep going
First, from the client side, ReleasePistol
Oh sorry ReloadPistol, then what happens?
This part needs to be checked by the client
Animation, this part is sent with Multicast
and isReloading will work
These are done on the client side
But let's move this part to where?
To the client RPC
We have to take these to the client
but there's a problem here
If a user inputs reload
the animation will first be shown
It doesn't really have to ask the server about it
here
The animation is shown
and once that's done, init Ammo ui
function is called
On NetPlayerAnim instance
when this AnimNotify OnReloadFinish event function is called
InitAmmoUI function on player is called
That way the UI is updated
Then the animation needs to be called properly
and this InitAmmoUI on player also has to be called
This InitAmmoUI happens on the client side
What's important here?
This part. Here it's changing the data
This part that changes the data
isn't what the client should do but what the server should do
Visualization is done where?
By the client
but this data changing part is on the server
So we'll have to separate them
So once animation is done
InitAmmoUI will request a server RPC
From where? I'll explain it once again
ReloadPistol input comes in and animation plays
and when that happens, event function is called
Notify even is called
when the animation is about to be over
Then InitAmmoUI is called
Data is updated at that moment
and this isn't on the client
but telling the server 'update the data
since my animation is over'
So InitAmmoUI's this part
is what we have to work with server RPC
Here, call ServerRPC Reload
then where do all these go?
These will go to server RPC
and the part that updates the UI must go where?
To client RPC
From server RPC, this bulletCount only goes there
and everything else will all have to go to client RPC
Again, a user clicks on reload
and server RPC is requested when the animation is done
then server RPC updates data
and to the client
it says 'hey your animation is done
so update the UI
and effects'
Here the client RPC is called
Then, using RPC communication, client first receives input
then with that input, animation is performed
Then what do we do?
When this animation ends, InitAmmoUI is updated
and here it requests to the server
Right here
to the server
Then the server receives this as a server RPC
and what does it do?
It updates bulletCount, makes data for bulletCount
and then again to the client
it sends to the client saying 'the bulletCount is updated
so update the UI with this data'
Then this will be performed to update the screen
Then from the client RPC it sent it to the client
then here the mainUI parts
must be performed only when there is a mainUI
That's what we did so far
So here as well, if
mainUI, when there is a main UI
The parts about mainUI will be perfromed when there is a mainUI
Reload will be done when the client RPC is called from the server
and everything is updated
Let's build
Good
Then let's go to Unreal editor and open a server window
and a client window
First I'll take a pistol from the server
and shoot, the UI is updating
Let me press R
Then it updates
I can fire again
Again, the UI is updated, and I can fire more
On the client as well
I'll use all the bullets
I can't fire anymore
Update by pressing R
Is the screen updated? It isn't
It isn't being updated on the client window
Pew pew pew pew
It worked on the server but on the client, it isn't working
Why does this happen?
We'll learn that while making a log
First, bulletCount is updated on server RPC
Then how does the client use this bulletCount
It adds bullets using this updated bulletCount
Then let's see if this data is being updated properly
First here, UE_LOG
LogTemp Warning, TEXT
bulletCount of server RPC
We're going to take this bulletCount here
bulletCount on %d
Then on client RPC
Before calling the client RPC, this was done
and coming back here let's see
Before working on the bullet UI settings
we'll input the bulletCount first
Great, how does it work?
It was sent to the server and the server updated bulletCount data
and using client RPC, with that updated data
the screen is updated
But the reason this doesn't work properly
The reason the screen isn't updating
There must be a problem
I put this bulletCount
to find what the problem is
Let's see
First, on window
there is Output Log window under message log
Let's see there
Good
Then on filter, I'll see Warning only
Like this
Then I'll play, client as well
Take and fire pistol
The bulletCount is obviously 0
Let me press on reload here
It reloads
There's something on the screen
Let's see
On the output log, on the server, what happened?
It says ServerRPC bulletCount is 10
Right here
ServerRPC bulletCount is 10
and client RPC is 0
Isn't that odd?
On the server, the data was updated to bulletCount 10
but the client that received it
still has it at 0, the data wasn't updated
The reason is
Did we have bulletCount be replicated? No
Go to header
where this bulletCount is declared, it is replicated
And on the very bottom
we also added implementation for that
It must be done automatically
but why isn't it being updated?
Let's see another thing on tick
From tick function
let's add something for this
UE_LOG, LogTemp
It's kind of inconvenient when we try to work with the console
For this part, later on, we'll use
macro to make it better to work with
Warning, text, tick bulletCount
We'll see how this bulletCount is called
And this one only needs to be left on client
so I'll add one thing
NetMode
When NetMode is at client
GetNetMode
sends over these NetModes
With this, we can know where this is
whether it is running on the client window or the server window
Here, I'll put NM_Client on NetMode
Running on client
and this will be output on the screen
only when there is mainUI
So that it works selectively
Good
Come back and click on clear
Play
On the server, there's nothing on the output log
When I play the client
The bulletCount is 10
Right?
Now I'll take and fire the pistol on the client window
Then the bulletCount is at 0
Pressing R
it showed 0 just now
Now the animation is done and look
The count has changed to 10
The reason why the bulletCount is at 10
is here
Zooming in here
The server RPC changed the bulletCount to 10
Then the client RPC log says 0
Tick also says 0
but then after that it's 10
Here, we can know
that RPC called the moment we call it
but what about property replication?
It isn't being synced right away
It has its own update cycle
On that cycle, the data is matched
There was this variable that we worked with
which is Net Update Frequency
on actor, do you remember?
We had BP NetActor
Selecting this,
there's this variable Net Update Frequency
Here's Net Update Frequency
and what does this mean?
It says 199
which is the cycle of the server and client being updated
It's set at 100 so it will be called 100 times a second
But it would be maintained or not depending on network circumstances
So this Net Update Frequency
The cycle
Depending on the cycle
the bulletCount property replication happens
As you saw on the screen
Here, RPC says this
Right after calling, client communication happens
and property replication
just follows its cycle
so the timing the two are updated don't match
So even though the server said 10
it's 0 on the client
so here the client RPC updates
to update the UI
but what's the bulletCount? 0
So it doesn't have anything to update
So, the moment we're trying to update on NetTPSCharacter
Right here
What's the bulletCount here?
0
As soon as this changed this part had to be performed but it didn't
That's why this problem occurred
Then what should we do? It's very simple
We need to sync property replication and RPC
There will be several ways but we'll use the parameter
and update bulletCount here
Syncing with that value
We learned this also on fire
Next
The bulletCount is being updated on 100%, MaxBulletCount
So we can change this bulletCount
to MaxBulletCount which changes the data
and then it will
reload
Why? Tick follows right up
to put MaxBulletCount on bulletCount
Handing over the bulletCount means
sending it over to parameter
and then
put update bulletCount
which will be used to update bulletCount
This part will also have to go in the implementation, of course
Then as a ClientRPC Reload factor
when this is called on the server RPC, bulletCount data is cleared
and to this RPC function, update bulletCount, bulletCount data comes in
then the value is updated to this value
Then the data will be synced
Another is
bulletCount will be updated to MaxBulletCount anyways
so when client RPC is called
it can just fill it up to MaxBulletCount instead of just any other bulletCount
This is the same
Then with this, let's see if it works
I'll first erase this part with UE_LOG
because it might show on the screen
On tick as well
I'll erase this part where it called
Build
The part that we worked on
The Reload part will work
We made it work properly on the client side
Right
What did it do on client RPC reload
It kept taking it to MaxBullet
It's done building so let's check
Play
This data on output log isn't being printed anymore
We don't need this
On the server, taking and firing the pistol
the UI is updating
and pressing on Reload
it also updates
Now on the client, take the pistol over there
and I'll fire
The bulletCount must be 0, and it is
Press on Reload, the animation shows
and the bulletCount is updated
What's the reason it shows up properly on the screen?
The timing of bulletCount and RPC being updated are different
They aren't the same
But on RPC, data is updated to MaxBulletCount anyways
so the UI was added by MaxBulletCount
It can also be done by using parameter
or if that's a waste of packet
without having to do that
since here, it just has to fill the UI with this data
it was set to just make it MaxBulletCount
This was reload
Let's summarize what we've learned in this unit
Fire using RPC Declare ServerRPCFire() function
Go to NetTPSCharacter.h Add an RPC function ServerRPCFire() which will be performed in the server to fire
Implementation of ServerRPCFire() function Go to NetTPSCharacter.cpp
Add ServerRPCFire() implementation Move everything on fire of Fire() function to ServerRPCFire()
Declare MulticastRPCFire()
Fire logic is performed in the server but effect and UI are performed in the client Go to NetTPSCharacter.h
Add MulticastRPCFire() declaration on NetMulticast RPC option With parameter, receive collision result
MulticastRPCFire() function implementation Go to NetTPSCharacter.cpp
Add MulticastRPCFire() implementation Take effect, mainUI call, animation from ServerRPCFire()
ServerRPCFire() function revision When bHit is true, SpawnEmitterAtLocation() function call is moved to MulticastRPCFire()
Code removing bullets and controlling mainUI and animation is move to MulticastRPCFire()
Call MulticastRPCFire() function at the last part BulletCount replication
Go to NetTPSCharacter.h to sync the remaining bullets Set Replicated option for bulletCount variable
Go to NetTPSCharacter.cpp Add bulletCount replication to GetLifetimeReplicatedProps() function
Reload using RPC Add Server, Client RPCReload
Declare ServerRPCReload() to NetTPSCharacter.h Add ClientRPCReload() function which uses client RPC option
Go to NetTPSCharacter.cpp
When reload animation is done AnimNotify_OnReloadFinish() event happens in NetPlayerAnimInstance.cpp
It calls InitAmmoUI() of NetTPSCharacter.cpp InitAmmoUI() calls ServerRPCReload()
ServerRPCReload() resets bulletCount and calls ClientRPCReload()
ClientRPCReload() works on mainUI and finishes reload
The End