Runtime Netcode Patcher
Patches Netcode RPC methods during runtime utilizing Harmony
Date uploaded | 4 months ago |
Version | 0.2.5 |
Download link | Ozone-Runtime_Netcode_Patcher-0.2.5.zip |
Downloads | 4565712 |
Dependency string | Ozone-Runtime_Netcode_Patcher-0.2.5 |
This mod requires the following mods to function
BepInEx-BepInExPack
BepInEx pack for Mono Unity games. Preconfigured and ready to use.
Preferred version: 5.4.2100README
[RNV] Runtime Netcode Validator
A BepInEx plugin utilizing HarmonyX to patch methods labeled with [ServerRpc]
or [ClientRpc]
, inside a specified type that derives from NetworkBehaviour
, to run the same format of checks NGO patches in during compile-time.
F.A.Q.
- Why is my
NetworkBehaviour
added to a pre-existingNetworkObject
not working?- RNV used to auto-magically patch your
NetworkBehaviour::Constructor
to call a custom method to synchronize with the parent NetworkObject (something that registering a new NetworkObject w/ NetworkPrefab, and .Spawn()ing avoids). To prevent confusion this is now a manual process but is still possible.
- RNV used to auto-magically patch your
- What does Runtime Netcode Validator mean?
- In simplest terms, 'Netcode Validation' is a way to describe the process of verifying the associated information that makes a RPC(Remote Procedure Call) transmit it's information across the network and then doing that transmission. This is universal, the
Runtime
is what sets this apart, as it does it's "code insertion" at runtime.
- In simplest terms, 'Netcode Validation' is a way to describe the process of verifying the associated information that makes a RPC(Remote Procedure Call) transmit it's information across the network and then doing that transmission. This is universal, the
- How does this differ from what NGO (or implementations of the NGO IL emitter such as Weaver) does to my RPC methods?
- This utilizes HarmonyX to patch your methods at runtime and add this 'validation' check in the form of a custom method with as little overhead as possible (along with other QoL NGO features). This comes with some benefits, like adding custom serialization (discussed later), as well as allowing you to un-patch your RPC methods.
- What are the implications of runtime patching?
- Arguments could be made about the memory overhead that patching causes but this should be minimal and no worse than if you were to patch any other method. The actual check itself is designed to be no more intrusive than the NGO checks and can be manually reviewed as the method that is called (Determining if your rpc should proceed or if we should transmit across the network) is under NetworkBehaviourExtensions::MethodPatchInternal
- What can I put in the RPC parameters?
- Typically NGO only allows you to send anything that implements
INetworkSerializable
which usually is fine; However if you want a simple struct or class and writing a wholeINetworkSerializable
implementation method just for a few variables is too much, then you can mark the object with a[System.Serializable]
attribute and RNV will handle serializing it over the network as well as your normalINetworkSerializable
parameters.
- Typically NGO only allows you to send anything that implements
Table of Contents
Getting Started
-
Reference Runtime Netcode RPC Validator by installing the NuGet package from the terminal (in your projects directory):
dotnet add package NicholaScott.BepInEx.RuntimeNetcodeRPCValidator
-
Add a BepInDependency attribute to your
BaseUnityPlugin
.[BepInDependency(RuntimeNetcodeRPCValidator.MyPluginInfo.PLUGIN_GUID, RuntimeNetcodeRPCValidator.MyPluginInfo.PLUGIN_VERSION)]
-
Instantiate NetcodeValidator: Create and maintain a reference to an instance of
NetcodeValidator
and callNetcodeValidator.PatchAll()
. If, and only if, you wish to revert any patches applied you can callDispose()
, orUnpatchSelf()
if you want to keep the instance for re-patching. -
Define and Use RPCs: Ensure your Remote Procedure Calls on your NetworkBehaviours have the correct attribute and end their name with ServerRpc/ClientRpc.
Examples
For more robust examples check the Github Repo of the UnitTester plugin, which is used during development to verify codebase.
// Example of using NetcodeValidator
namespace SomePlugin {
[BepInPlugin("My.Plugin.Guid", "My Plugin Name", "0.1.1")]
[BepInDependency(RuntimeNetcodeRPCValidator.MyPluginInfo.PLUGIN_GUID, RuntimeNetcodeRPCValidator.MyPluginInfo.PLUGIN_VERSION)]
public class MyPlugin : BaseUnityPlugin {
private NetcodeValidator netcodeValidator;
private void Awake()
{
netcodeValidator = new NetcodeValidator("My.Plugin.Guid");
netcodeValidator.PatchAll();
netcodeValidator.BindToPreExistingObjectByBehaviour<PluginNetworkingInstance, Terminal>();
}
}
}
// Example of using Server or Client RPCs. Naming conventions require the method to end with the corresponding attribute name.
namespace SomePlugin {
public class PluginNetworkingInstance : NetworkBehaviour {
[ServerRpc]
public void SendUsDataServerRpc() {
// Log the received name
Debug.Log(name);
// Tell all clients what the sender told us
TellAllOtherClientsClientRpc(NetworkBehaviourExtensions.LastSenderId, name);
}
[ClientRpc]
public void TellAllOtherClientsClientRpc(ulong senderId, string name) {
Debug.Log(StartOfRound.Instance.allPlayerScripts.First(playerController => playerController.actualClientId == senderId).playerUsername + " is now " + name);
}
[ClientRpc]
public void RunClientRpc() {
// Send to the server what our preferred name is, f.e.
SendPreferredNameServerRpc("Nicki");
}
private void Awake()
{
if (!IsHost) // Any clients should ask for sync of something :shrug:
StartCoroutine(WaitForSomeTime());
}
private IEnumerator WaitForSomeTime()
{
// We need to wait because sending an RPC before a NetworkObject is spawned results in errors.
yield return new WaitUntil(() => NetworkObject.IsSpawned);
// Tell all clients to run this method.
SendUsDataServerRpc();
}
}
}
Notes
Utilize the NetworkBehaviourExtensions.LastSenderId
property to retrieve the ID of the last RPC sender. This will always be NetworkManager.ServerClientId
on the clients.
Pre-Existing NetworkObject
So you don't wanna make a prefab eh? Don't feel like registering it with the network? Afraid of what might come? Fear no more, as you can bind your NetworkBehaviour to a pre-existing (native) NetworkBehaviour utilizing a method anytime before NetworkManager
is initialized. Generally this would be in your Plugins Awake, right after you create and patch with your NetcodeValidator
. See the Examples above for usage and below for a detailed signature.
public void NetcodeValidator::BindToPreExistingObjectByBehaviour<TCustomBehaviour, TNativeBehaviour>()
Version Compliance
- Networking For GameObjects (NGO) No version issues reported.
- Built for BepInEx 5.4.2100 but no version issues reported.
- HarmonyX packaged w/ BepInEx but considering to drop back to MonoMod implementations.
Acknowledgments
- @Lordfirespeed for invaluable support and insights throughout the development.
Contributing
We welcome contributions! If you would like to help improve the RNV, please submit pull requests, and report bugs or suggestions in the issues section of this repository.
Contact
Discord: @Day
CHANGELOG
Changelog
v0.2.0
Changed
- The final changes to the
NetcodeValidator
class occur w/ this update. This will be the final form, the only change on your end is anew NetcodeValidator(YourPluginGUID)
instead ofnew NetcodeValidator(YourPlugin)
. This is to be more in line with how Harmony instances are handled and to make things easier on the back-end. This includes a few new methods listed below following the pattern of the Harmony class. - NetcodeValidator.Patch(Type type)
- NetcodeValidator.Patch(Assembly assembly)
- NetcodeValidator.PatchAll()
v0.1.8
Fixed
- Pretty big README.md fix!
v0.1.7
Fixed
- Incorrect error logging in a few places.
- Project structure was out of control. It's now.. In control.
- Git fixes.
v0.1.1
Added
- Introduced a new
LogErrorAndReturn
method inNetworkBehaviourExtensions.cs
to streamline error logging. - Implemented a new network logger in
Plugin.cs
.
Changed
- Reorganized error reporting in
NetworkBehaviourExtensions.cs
, now utilizingLogErrorAndReturn
to improve coding practices. - Pruned extraneous variables in
RpcData
struct. - Modified package dependencies in
.csproj
file, removing unnecessary ones and adding a supplemental package reference.
v0.1.0
Removed
- Imports: The namespaces
System.Collections.Generic, System.IO, System.Runtime.Serialization.Formatters.Binary, and HarmonyLib
have been removed. - Data structures: The dictionaries
NetRPCStates, NetRPCData, NetRPCParams, NetRPCSender
have been removed which were being used to track RPC state, data, params, and senders. - Methods: The methods
GetNetworkState, GetNetworkData, LastRPCSender, VerifyAsRegisteredWithNetworkObject, ValidateRPCExecution, PrepareRPCParamsForSending, SendRPC, ProcessRPC
have been removed.
Added
- Classes: New inner class
RpcData
has been added. - Enumerators: An Enumerator
RpcSource
has been added to the RpcData class andRpcState
has been moved insideRpcData
. EnumeratorRpcState
values changed from[AwaitingMessage, MessageReceived]
to[FromUser, FromNetworking]
. - Methods: The method
LastSenderId
has been added to get the last SenderId from RpcData. - MethodPatchInternal Updates: The logic of MethodPatchInternal has been changed quite significantly.