SyncListStruct not syncing on log in

Alright so I’m having a bit of an issue with SyncListStructs here, I’ve googled like crazy watched different networking videos, read through the network documentation and I feel stumped.

ServerHandler is attached to its own GameObject, not attached to the player.
WorldHandler is where I add TileStructs to the TileStructList.

I know my IsServer else is missing a call but I just can’t honestly figure out what. I believe I should send an update from the server to all clients about the contents of its TileStructList but i genuinely have no idea how to do that.

What I want to accomplish
I want all players to get the same exact TileStructList that the host client has.
Is this beyond UNET or am I just totally missing something?

using UnityEngine;
using UnityEngine.Networking;

public class ServerHandler : NetworkBehaviour
{
    public class SyncListTile : SyncListStruct<TileStruct> { }

    public SyncListTile TileStructList = new SyncListTile();

    public GameObject WorldHandlerPrefab;

    public override void OnStartServer()
    {
        base.OnStartServer();
    }

    public override void OnStartClient()
    {
        base.OnStartClient();

        GameObject worldGo = GameObject.Instantiate(WorldHandlerPrefab) as GameObject;

        if (isServer)
        {
            worldGo.GetComponent<WorldHandler>().CreateEmptyWorld(this);
            TileStructList.Callback = OnTileChanged;
        }
        else
        {

        }
    }

    public void OnTileChanged(SyncList<TileStruct>.Operation op, int index)
    {
        Debug.Log("INDEX: " + index);
    }
}

Here is my TileStruct class. It’s in its own TileStruct.cs file.

[Serializable]
public enum TileType { Empty, Ground, FarmPlot, WoodPlot };

[System.Serializable]
public struct TileStruct
{
    public int X;
    public int Y;
    public TileType Type;

    public TileStruct(int x, int y, TileType type)
    {
        X = x;
        Y = y;
        Type = type;
    }
}

I really just want a player who logs in to get the changes to the tiles that have occurred since the server was started.

Right now I have it so that when a player logs in they get a base world, same amount of tiles as everyone else but none of them are changed. I want those tiles to be updated to match the ones that the server has changed since the server started running.

I’m fine with the one person hosting the game model, I just want all clients who log in to get the tile data from that host instead of only getting updates on tile changes that occur AFTER they log in because those changes are currently working fine. The problem is getting the changes that occurred before they logged in.

I’m going to try a SyncList that keeps an index of each tile that is changed since the server started, then compare those tiles with the players on log in and hopefully cause an update there.

I got it working.

I’m sure there are better ways to go about it, but here’s what I did.

I figured, tiles were updating once the players were in the game, but they weren’t getting the SnyncListStruct updates that occurred before they entered the game.

1. I created a list on the sever that contains a list of Structs (in my case TileStructs). This is on top of the SyncListStruct list that I already have.

2. When I click to change a tile I call a [Command] Function to send the information from the Client to the Server to let the server know that I changed a tile in the SyncListStruct List.

void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            CmdChangeTile(Mathf.RoundToInt(_currFramePosition.x),
                                         Mathf.RoundToInt(_currFramePosition.y),
                                          TileType.FarmPlot);
        }
    }

[Command]
    public void CmdChangeTile(int x, int y, TileType type)
    {
        ServerHandler serverHandler = FindObjectOfType<ServerHandler>();

        TileStruct t = WorldHandler.Instance.GetTileStructAt(x, y);
        int index = serverHandler.TileStructList.IndexOf(t);
        t.Type = TileType.FarmPlot;
        serverHandler.TileStructList[index] = t;

        //Here we call a Server Command to update the tile across all clients
        serverHandler.ChangeTile(t, index);
    }

It’s ugly but I just got it working, I’ll optimize soon.

3. As you can see, at the bottom of the Cmd function I call another function (ChangeTile()). This Function is a [Server] Function as I want the server definitely be aware of the update.

[Server]
    public void ChangeTile(TileStruct t, int index)
    {
        TileStructList[index] = t;

        ServerChangedTileStructlist.Add(t);
    }

Then it gets a bit more complicated. Keep in mind all the previous scripts were attached to the player Object, because it has to be in order to call a [Command] function.

4. I have a ServerHandler script that isn’t attached to the player, it’s attached to it’s own GameObject. It handles all my OnStartServer() and OnClientConnect() calls, but if I use OnClientConnect it’s a call from the client connecting, not from the Server. Now that I write this, I realize I could do a [Server] call inside of there, but anyway, this is how I approached reading when a client connects and passing that information to the server.

void Update()
    {
        if (isServer)
        {
            if (NetworkServer.connections.Count > _connectedPlayerCount)
            {
                Debug.Log("We have a new connection!");
                ServerUpdateTilesForClient();
                _connectedPlayerCount++;
            }
        }
}

5. My ServerUpdateTilesForClient() function loops through the list I created back in Step 1 and finds the matching Struct from the SyncListStruct List. I then pass each tile in the list that’s update to a [ClientRpc] so that all the clients get this updated list. I should probably optimize it for clients who just log in, but right now its for everyone.

Now I’m sure there are a hundred different ways to do this, but this is how I figured it out. If you’re trying to do something similar I’d be happy to answer questions, but other than that, I hope what I’ve figured out at least helps someone else that would be great.

So to recap what is actually happening in very simple terms.

In order for your players to get the Hosts changes that occurred when they weren’t connected, you need a way to trigger the SyncListStruct callback when they log in so they get the most up to date list.

The extra list of changed Structs I had on the host machine may be redundant, trying to see if I can remove it and just simply have the above handle everything.

I tried Forge networking and it solved all my problems instantly with good documentation. I don’t work for them or am I affiliated in any way, but I’d check it out if the above has been a problem for you.