I am trying to convert a single Player unity 3d game into a multiplayer. I am using unity netcode for gameobjects.
This script is responsible for procedural generation of the map. I am generating the map when host is started...the generation works fine. Now, I was tryign to sync the same generated map over to client. In the other script - MapManger.cs, I serialized the generated map by storing the map data into a string and then passing it via RPCs to the client. The mapData will be then deserialized on the client and the map would ideally be generated same as host.
But for some reason the rpc calls are not being executed at all. I have placed debug logs at every place possible. The client is indeed connecting to the host but the map wouldnt appear. I verified this with the client debug log in the script and also NetworkManager's debug logs. I dont seem to locate the issue. Is it the mapData is too big to go over the network? If it is, then also the rpcs should have been called and gave a fatal memory error.
........MapGenerator.cs
public void isHostBttnEvent()
{
if (!NetworkManager.Singleton.IsHost)
{
NetworkManager.Singleton.StartHost();
GenerateHexagonGrid();
mapManager.initMap(map);
GenerateCrystals();
mapManager.SerializeMap();
}
if (NetworkManager.Singleton.IsHost) { Debug.Log("host started..."); }
}
public GameObject GetPrefabByType(string type)
{
switch (type)
{
case "Water":
return waterPrefab;
case "Lowland":
return lowlandPrefab;
case "Highland":
return highlandPrefab;
case "Mountain":
return mountainPrefab;
case "Crystal":
return crystalPrefab;
case "Desert":
return desertPrefab;
case "Grassland":
return grasslandPrefab;
case "TreePrefab2": // Assuming you want to map the treePrefab2 by a unique name
return treePrefab2;
case "PalmTree":
return palmTreePrefab;
case "ExtraMountain":
return extraMountainPrefab;
case "TreePrefab": // Assuming you want to map the treePrefab by a unique name
return treePrefab;
default:
Debug.LogError("Unrecognized tile type: " + type);
return null;
}
}
// Call this method to send map data to all clients after generation
public void SendMapDataToClients()
{
if (IsServer)
{
Debug.Log($"[HexagonMapGenerator] Sending map data to clients. Serialized Map Data Length:" + serializedMapData.Length);
TransmitMapDataToServerRpc(serializedMapData);
}
}
[ServerRpc(RequireOwnership = false)]
void TransmitMapDataToServerRpc(string mapData, ServerRpcParams rpcParams = default)
{
Debug.Log($"[HexagonMapGenerator] Transmitting map data to clients. Map Data Length: {mapData.Length}");
// Directly call the ClientRpc to relay the data to all clients
ReceiveMapDataClientRpc(mapData);
}
[ClientRpc]
void ReceiveMapDataClientRpc(string mapData, ClientRpcParams rpcParams = default)
{
if (!IsServer) // Ensure this doesn't execute on the host, as it already has the map
{
Debug.Log($"[HexagonMapGenerator] Received map data on client. Map Data Length: {mapData.Length}");
// Client-side method to deserialize and instantiate the map
GetComponent<MapManager>().DeserializeAndGenerateMap(mapData);
}
}
public void StartClientAndReceiveMap()
{
if (!NetworkManager.Singleton.IsClient)
{
// Starts the client
NetworkManager.Singleton.StartClient();
Debug.Log("[HexagonMapGenerator] Client started. Awaiting connection and map data...");
// Register a callback for when the client is connected and ready to receive map data
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
}
}
private void OnClientConnected(ulong clientId)
{
// Check if the connected client is this instance
if (NetworkManager.Singleton.LocalClientId == clientId)
{
Debug.Log($"[HexagonMapGenerator] Client successfully connected to host. Local Client ID: {clientId}. Waiting for map data...");
// The client is now waiting for the map data to be sent from the host.
// The map data will be handled by ReceiveMapDataClientRpc method.
}
}
// Remember to unsubscribe from the event when the object is destroyed to prevent memory leaks.
void OnDestroy()
{
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected;
Debug.Log("[HexagonMapGenerator] OnDestroy called. Unsubscribing from OnClientConnectedCallback.");
}
}
This the MapManager.cs script where I am using mapData and then serializing and deserializing the data.
.......
public string SerializeMap()
{
StringBuilder sb = new StringBuilder();
HexNode[,] mapData = getMap();
for (int i = 0; i < mapData.GetLength(0); i++)
{
for (int j = 0; j < mapData.GetLength(1); j++)
{
HexNode node = mapData[i, j];
// Example serialization: type,x,y,z;
// You may need to include more data based on your game's requirements
sb.Append($"{node.type},{node.Vec3Location().x},{node.Vec3Location().y},{node.Vec3Location().z};");
}
}
return sb.ToString();
}
public void DeserializeAndGenerateMap(string serializedMapData)
{
Debug.Log($"Deserializing map data: {serializedMapData}");
string[] items = serializedMapData.Split(';');
foreach (string item in items)
{
if (!string.IsNullOrEmpty(item))
{
string[] parts = item.Split(',');
string type = parts[0];
Vector3 position = new Vector3(float.Parse(parts[1]), float.Parse(parts[2]), float.Parse(parts[3]));
GameObject prefab = hexMap.GetPrefabByType(type);
if (prefab != null)
{
Debug.Log($"Instantiating prefab of type {type} at position {position}");
Instantiate(prefab, position, Quaternion.identity);
}
else
{
Debug.LogError($"Failed to find prefab for type {type}");
}
}
}
}
From the logs, host and client connection seems fine
client debug logs -- client debug logs
host debug logs -- host debug logs