You are viewing a potentially older version of this package. View all versions.
darmuh-MirrorPlumber-0.1.0 icon

MirrorPlumber

Utility Mod that allows modders to insert and use new NetworkActions (Commands, ClientRpcs, and TargetRpcs)

Date uploaded 5 months ago
Version 0.1.0
Download link darmuh-MirrorPlumber-0.1.0.zip
Downloads 43
Dependency string darmuh-MirrorPlumber-0.1.0

README

Mirror Plumber

Utility BepInEx Mod that allows modders to insert and use new NetworkActions (Commands, ClientRpcs, and TargetRpcs)

  • This was built for YAPYAP, however, it should work in any other unity game that utilizes the same style of Mirror Networking.

Mirror Network Prefabs

Note: These steps assume you have some prior Unity modding knowledge.
If you do not need a background on Mirror Networking and just wnat to know how to use this utility, skip to Using MirrorPlumber for your NetworkBehaviour

Create a GameObject that will serve as your Network Prefab containg your NetworkBehaviour

  • This game object should at the minimum contain a Networkidentity component.
    • Your class inheriting NetworkBehaviour should also be attached to this game object either during in Unity or added during runtime.
    • You cannot add a Networkidentity component at runtime because the assetId property will not be set properly.
  • Once you have created your Prefab with the NetworkIdentity component, build it into an asset bundle.

Loading your GameObject Assetbundle as a Network Prefab

  • Load your asset bundle containing your game object at Plugin Awake. If you have not added your Network Behaviour classes already, add them as components now.
    • You'll want to cache your GameObject as it will be used in a few other places.
  • Either at Plugin Start or at another appropriate time (before hosting a game session), you'll want to then use NetworkClient.RegisterPrefab on your game object.
    • You'll also need to cache the assetId by performing GetComponent<NetworkIdentity>().assetId after you've registered your prefab.

Spawning your Network Prefab

  • Once your prefab has been properly registered, you can now spawn it once a game session has been started and the server is active.
    • Ensure you are ONLY spawning the object from the server client.
  • To spawn a NetworkPrefab you will Instantiate a copy of your cached GameObject and then run NetworkServer.Spawn on the copy with your cached assetId.

YAPYAP Simple NetworkPrefab Load/Spawn Example

        internal static ManualLogSource Log { get; private set; } = null!;
        internal static GameObject Networker = null!;
        internal static uint NetworkerID = default!;

        private void Awake()
        {
            Log = Logger;

            Log.LogInfo($"Plugin {Name} is loaded!");

            //Networker Bundle
            string networkAsset = Path.Combine(Path.GetDirectoryName(Info.Location), "networker");
            AssetBundle networker = AssetBundle.LoadFromFile(networkAsset);
            Networker = networker.LoadAsset<GameObject>("Networker");
            Networker.AddComponent<NetworkingTestWithPlumbing>();
            GameManager.OnPlayerSpawned += OnPawnSpawn;
        }

        private void Start()
        {
            Log.LogMessage("Registering network prefabs");
            NetworkClient.RegisterPrefab(Networker);
            NetworkerID = Networker.GetComponent<NetworkIdentity>().assetId;
            Log.LogDebug($"NetworkerID - {NetworkerID}");
        }

        private static void OnPawnSpawn(Pawn pawn)
        {
            Log.LogMessage($"Pawn spawned {pawn.PlayerName}");

            if (!pawn.isLocalPlayer)
                return;

            if (pawn.isServer)
            {
                Log.LogDebug("Spawning networker");
                var networker = Object.Instantiate(Networker);
                NetworkServer.Spawn(networker, NetworkerID);
            }
        }

In the above example:

  • The NetworkBehaviour NetworkingTestWithPlumbing is added to the Networker GameObject at Plugin Awake
  • Networker is then registered as a Network Prefab in Plugin Start and the assetId is cached as NetworkerID
  • OnPlayerSpawn is listening to the GameManager.OnPlayerSpawned event. When a player is spawned, it checks if the player is the server and then also spawns the testing networker object.

Where MirrorPlumber comes in

  • Without MirrorPlumber, this is where you would find that the various Attributes [ClientRpc], [Command], etc. are not actually utilizing Mirror to send the information across the network.
  • You could perform your own plumbing and register each and every NetworkAction yourself following the logic for RemoteProcedureCalls.RegisterDelegate or RemoteProcedureCalls.RegisterRpc or RemoteProcedureCalls.RegisterCommand
    • However this process is incredibly tedious and will certainly cause you some headaches.
  • MirrorPlumber does all of this manual plumbing for you. You'll just need to perform a few alternative steps in your NetworkBehaviour to start the process.

Using MirrorPlumber for your NetworkBehaviour

  • To start, it is recommended to create a static reference to each Plumber you create.
    • This is because you will be the one to invoke these network actions in your code, so you'll need a reference to it.
    • Example:
   internal static Plumber GeneratedCommand = null!;
   internal static Plumber<string, int> GeneratedRPC = null!;
  • Creating the Plumbers is recommended to be done in your NetworkBehaviour's Awake method, however it can be done any time after the prefab holding your NetworkBehaviour has been spawned.
    • You create the Plumber with a simple constructor that takes the following parameters:
      • System.Type netBehaviour You'll provide this by converting your NetworkBehaviour to a System.Type - ie: typeof(MyNetworkBehaviour)
      • string methodName This is the name of the Method you are performing plumbing for - ie: nameof(MyNetworkedMethod)
      • NetType netType This is an enum created by MirrorPlumber to help identify what kind of NetworkAction you are requesting plumbing for.
      • bool requiresAuthority = false (Optional) This bool determines if the NetworkAction requires ownership of the Network Prefab before being used.
    • NOTE: You cannot invoke Network Actions without having created your Plumber.
    • Once you have created your Plumber, you should then add the method you wish to run when the NetworkAction is received via AddListener.
      • This can be multiple methods so long as each one has the number of parameters expected with the correct type.
  • Example:
   private void Awake()
   {
       GeneratedCommand = new(typeof(NetworkingTestWithPlumbing), nameof(CmdSendHello), PlumberBase.NetType.Command);
       GeneratedCommand.AddListener(RpcShowHelloMessage);

       GeneratedRPC = new(typeof(NetworkingTestWithPlumbing), nameof(RpcShowHelloMessage), PlumberBase.NetType.TargetRpc);
       GeneratedRPC.AddListener(HelloFromTheNetwork);
   }
  • Now that you have your Plumbers created, all you need to do now is Invoke them wherever you would typically call the method with the NetworkAction.
    • It's recommended to use a null conditional operator before invoking your Plumber.
    • Below are some of the parameters you can expect in the Plumber's Invoke method:
      • TSource instance This is the instance of your NetworkBehaviour that is calling this method.
      • NetworkConnection target = null! (OPTIONAL) If your NetworkAction is a TargetRpc, you'll need to set this to the client you wish to send the NetworkAction to.
      • TParam param or TParam1 param1 or TParam2 param2 All of these potential parameters are values of the parameter types you are sending to other clients.
    • Examples: GeneratedCommand?.Invoke(this); GeneratedRPC?.Invoke(this, "Hello World from the network!", 1337, NetworkServer.connections[0]);
      • Both of these examples are called from inside non-static methods inside my NetworkBehaviour NetworkingTestWithPlumbing
    • For information on what types can be passed in TParams over to Mirror's NetworkWriter/NetworkReader, please see this page of Mirror's Documentation.
      • Some games may also have custom NetworkWriter/NetworkReaders that you can utilize, YAPYAP does not and you cannot add new ones via a Mod (they require Weaving from Mirror)

CHANGELOG

MirrorPlumber Changelog

0.3.1

  • Updated xml documentation for PlumbVars
  • Added OnValueChanged event to PlumbVars that can be subscribed to similarly to Mirror's native SyncVar hooks attribute.

0.3.0

  • Updated project to generate xml documentation file.
  • Updated AutoPlugin version in project.
  • Added PlumbVar which acts as a psuedo syncvar (using an internal command and clientrpc)
    • Defined with the class name, value type, and initial value
    • Get and set the value via the Value property. Setting the value will send your changes over the network.
  • Found and provided fix for issue of NetworkEvent delegate listeners persisting past class destruction.
    • In order to clear these delegates with destroyed (null) references, you can now use the ClearListeners method in your NetworkBehaviour's OnDestroy method.
    • You can also swap to SetListener in place of AddListener that will automatically clear existing listeners before adding your new listener.
    • To add additional listeners for one networkevent you can still utilize AddListener, just ensure it is after ClearListeners or SetListener
  • Found and provided fix for issue where NetworkPrefabs loaded from asset bundles will get cleared from the NetworkClient when they are no longer hosting.
    • This is due to Mirror natively running NetworkClient.ClearSpawners during NetworkClient.Shutdown (in yapyap this method is called when closing a hosted lobby)
    • The extension method TryRegisterPrefab has been updated to handle registration for you.
      • MirrorPlumber will keep a list of gameobjects that have been queued for registration and ensure they've been registered with NetworkClient at NetworkClient.Initialize
      • An overload exists that does not provide the assetId as it's no longer necessary to keep track of.
  • New game object extension method can be used to remove a prefab from MirrorPlumber's prefab game object list via TryUntrackPrefab
    • This will not remove the prefab from an active server, but will ensure it is not in the prefab list for the next time NetworkClient is initialized.
  • New game object extension method for getting a prefab's assetId
  • New game object extension method for spawning a prefab on the server.
  • Examples updated with latest changes
  • Readme updates for latest version.

0.2.1

  • removed sample classes from compiler that I accidentally included in last build

0.2.0

  • Moved Plumber registration from constructor to Create method (breaking change from 0.1.1)
    • This was to solve an issue where Commands/Rpcs were trying to be re-added to Mirror after a lobby reload.
    • Now rather than creating a new Plumber every awake, it should be defined only once and then Create can be ran multiple times without any issues.
  • Added Examples folder to github.
    • This should help the visual learners who learn strictly thru code.
  • Added BehaviourAdder class for adding network behaviours to existing prefabs at runtime.
    • Handles both the PlayerPrefab and any spawnPrefab in the list that you can match to an assetId
  • Added GameObjectExtensions class for useful extension methods relating to Mirror/MirrorPlumber
    • TryRegisterPrefab will attempt to take your GameObject prefab and register it with MirrorClient
      • Returns true/false and provides you the NetworkIdentity assetId when successful.
  • Some msbuild project changes to make building the release package a bit easier

0.1.1

  • Fixed some typos in the readme
  • Removed some old debugging logs for more accurate ones in Plumber.cs

0.1.0

  • Initial release.