#Make Any Client-Side mod Networked

14 messages · Page 1 of 1 (latest)

smoky marlin
#

These are two code snippets that add an extra class to make a client-side mod require all players in the lobby to have it installed.

  • if you have AssemblyPublicizer:
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;

[HarmonyPatch(typeof(NetworkManager))]
internal static class NetworkPrefabPatch1
{
    private static readonly string MOD_GUID = MyPluginInfo.PLUGIN_GUID;

    [HarmonyPostfix]
    [HarmonyPatch(nameof(NetworkManager.SetSingleton))]
    private static void RegisterPrefab()
    {
        var prefab = new GameObject(MOD_GUID + " Prefab");
        prefab.hideFlags |= HideFlags.HideAndDontSave;
        Object.DontDestroyOnLoad(prefab);
        var networkObject = prefab.AddComponent<NetworkObject>();
        networkObject.GlobalObjectIdHash = GetHash(MOD_GUID);

        NetworkManager.Singleton.PrefabHandler.AddNetworkPrefab(prefab);
        return;

        static uint GetHash(string value)
        {
            return value?.Aggregate(17u, (current, c) => unchecked((current * 31) ^ c)) ?? 0u;
        }
    }
}

if you don't:

using System.Reflection;
using HarmonyLib;
using Unity.Netcode;
using UnityEngine;

[HarmonyPatch(typeof(NetworkManager))]
internal static class NetworkPrefabPatch2
{
    private static readonly string MOD_GUID = MyPluginInfo.PLUGIN_GUID;

    [HarmonyPostfix]
    [HarmonyPatch(nameof(NetworkManager.SetSingleton))]
    private static void RegisterPrefab()
    {
        var prefab = new GameObject(MOD_GUID + " Prefab");
        prefab.hideFlags |= HideFlags.HideAndDontSave;
        Object.DontDestroyOnLoad(prefab);
        var networkObject = prefab.AddComponent<NetworkObject>();
        var fieldInfo = typeof(NetworkObject).GetField("GlobalObjectIdHash", BindingFlags.Instance | BindingFlags.NonPublic);
        fieldInfo!.SetValue(networkObject, GetHash(MOD_GUID));

        NetworkManager.Singleton.PrefabHandler.AddNetworkPrefab(prefab);
        return;

        static uint GetHash(string value)
        {
            return value?.Aggregate(17u, (current, c) => unchecked((current * 31) ^ c)) ?? 0u;
        }
    }
}

original discussion in: https://discord.com/channels/1168655651455639582/1348089079673393152

coral wraith
#

wwhat

smoky marlin
nova wharf
#

How does that work? And what happens if client & host mismatch -- client gets an error "could not join lobby" or gets stuck in void? Needs a bit more context for those who are not Unity pros.

smoky marlin
#

the point is exactly to have a quick piece of code for those who do not know ( and don't care / have time to learn ) networking

#

it works because unity ( at least in the configuration zeekers uses ) does not allow clients to join if they have a different list of prefabs from the host

#

the client will get the generic "an error occurred" message and is sent back to the main menu

nova wharf
#
var networkPrefab = NetworkManager.Singleton.NetworkConfig.Prefabs.Prefabs
    .FirstOrDefault(prefab => prefab.Prefab.name == JesterEnemyPrefabName);
networkPrefab.Prefab.AddComponent<MuzikaGromcheJesterNetworkBehaviour>();

IIRC it wan't even mine idea to patch specifically GameNetworkManager.Start. Surely someone else suggested it.

smoky marlin
#

keyword: prefabs
a prefab is identified by the GlobalObjectIdHash of the NetworkObject at the root of the prefab

#

if you modify an existing prefab. or register a different one with the same id as an existing one. unity will not be able to distinguish them

#

see the various errors from some mis-configured mod:

[Prefab] has a duplicate GlobalObjectIdHash source entry value of: X!

nova wharf