-
-
Notifications
You must be signed in to change notification settings - Fork 305
Decoupling Netcoding (Events)
When an RPC is called on a networkObject, it is obvious that the code inside the RPC of the networkObject will be called.
However, if you want to scale the game, or make your project more readable and clean, the logic should not be contained in the networkObject.
For example, if you want to shoot a gun, you invoke SendRpc(RPC_Shoot, Receivers.All)
//RPC for Shooting
public override void Shoot(RpcArgs args)
{
// Shoot Logic here...
// Which means that for every RPC,
// networkObject won't really have a single responsibility
// and end up bloated over time, with an ugly amount of code.
}
However, using the Observer Pattern, we can simply notify other components/scripts, to do the logic instead!
Hence, the project will be scale-able, since the code is properly divided.
And single-responsibility pattern applies, which is always a part of clean code.
Look at it in practice!
public System.Action ShootEvent;
//RPC for Shooting
public override void Shoot(RpcArgs args)
{
// The subscriber(s) to shootEvent, are notified
// to do the actual logic.
if (ShootEvent != null)
ShootEvent();
}
So, assuming you have a reference to the networkObject (by the Inspector usually), then all you have to do is subscribe!
Let's see a fully fleshed out example!
using System;
public class ExampleNetworkObject: ExampleNetworkObjectBehavior
{
public Action ShootEvent;
// RPC for Shooting
public override void Shoot(RpcArgs args)
{
// The subscriber to shootEvent, does the actual logic.
if (ShootEvent != null)
ShootEvent();
}
}
public class ShootLogic : MonoBehaviour
{
// This is by default referenced, via the Inspector
public ExampleNetworkObject networkObject;
public void Start()
{
// When networkObject fires off the ShootEvent
// it will trigger OnShoot automatically
networkObject.ShootEvent += OnShoot;
}
public void OnShoot()
{
// Shoot Logic here...
}
}
So, whenever we invoke SendRPC(RPC_SHOOT, Receivers.All);
, it will always and succesfully call OnShoot()
, and the logic is decoupled clearly. It is also extremely readable for everyone, and in this way, networkObject will never get bloated, since the single-responsibility pattern applies.
If you want to pass RpcArgs, instead of just notifying the RPC function happened, with a few small tweaks on the above, it should all work smoothly.
using System;
public class ExampleNetworkObject: ExampleNetworkObjectBehavior
{
// Note that we have 1 parameter instead of none ;)
public Action<RpcArgs> ShootEvent;
// RPC for Shooting
public override void Shoot(RpcArgs args)
{
// The subscriber to shootEvent, does the actual logic.
// Note that we pass `args` inside the event parameter.
if (ShootEvent != null)
ShootEvent(args);
}
}
public class ShootLogic : MonoBehaviour
{
// This is by default referenced, via the Inspector.
public ExampleNetworkObject networkObject;
public void Start()
{
// When networkObject fires off the ShootEvent
// it will trigger OnShoot automatically
networkObject.ShootEvent += OnShoot;
}
public void OnShoot(RpcArgs args)
{
// Shoot Logic here...
}
}
Lastly, like all events and actions, they should be used with care, so don't forget to unsubscribe when necessary!
Getting Started
Network Contract Wizard (NCW)
Remote Procedure Calls (RPCs)
Unity Integration
Basic Network Samples
Scene Navigation
Master Server
Netcoding Design Patterns
Troubleshooting
Miscellaneous
-
Connection Cycle Events
-
Rewinding
-
Network Logging
-
Working with Multiple Sockets
-
Modify Master and Standalone servers
-
NAT Hole Punching
-
UDP LAN Discovery
-
Offline Mode
-
Ping Pong
-
Lobby System
-
Upgrading Forge Remastered to Develop branch or different version
-
Forge Networking Classic to Remastered Migration Guide
-
Script to easily use Forge Networking from sources
-
Run Two Unity Instances with Shared Assets for Easiest Dedicated Client Workflow