#Simple RTS save/load game setup

51 messages · Page 1 of 1 (latest)

gray mango
#

Hey everyone, I'm creating my first multiplayer game with Mirror, and would love some pointers on how to organise it.

It's an RTS game with a procedurally generated world. There's a finite amount of islands, each with random surface and different units on it.

Since the islands are procedurally generated, I only need to sync the world seed at game start, and the client will know how to create each island's mesh etc, and does so automatically.

Once created, I would like the Island : NetworkBehaviour script's variables to be synced with the server (SyncVar), to be able to independently affect weather etc on each island.

I also want to save the state of each island and then load it again the next time the server starts.

This all sounds very simple in principle - naively, I'd make a SyncList<Island> islands, create the game object on the server, populate its Island instance with the save state, and then use NetworkServer.Spawn to spawn the object on all clients.

However, I read that GameObjects are dangerous in SyncLists, and I'm not even sure if I can put the Island script as a reference. So how do I create a connection between the object on the client and my save data tree which has a reference to each island and its settings?

How is this mapping from save game data to GameObject and vice-versa usually done? What would you suggest in my case?

Thanks in advance for any input 😊

sharp abyss
#

server loads / saves state to disk / database / whatever

#

server instantiates island prefab, feeds SyncVar data into it from its internal List<Island>, including your seed, and spawns it. I'd suggest Scene Interest Management and putting each of the island prefabs and data in its own subscene

#

Just so clients only have to load the island they're on, instead of the whole world

#

Depends on size / scale I suppose.

gray mango
#

the game will include travelling and quick switching between islands on the map (like Anno, for example), so I suppose all islands on the map should be the same scene. it's not focused around a commander unit. If I implement multiple maps that players can travel between, I will look into scene management :)

sharp abyss
#

loading / unloading additives on client should be very quick, just the generation for that island, which I'd assume would be smaller / faster than the whole world, but you can implement that later if the world gets too big.

#

scene int mgmt gives you isolation so clients aren't getting updates for things that are far away on other islands

gray mango
# sharp abyss server instantiates island prefab, feeds SyncVar data into it from its internal ...

thanks, this helps already. in order to understand it more concretely, let's say I want to place a building on a specific island. If I understand correctly, I can only call Command functions that are attached to the local player object, so I'd add a Player.CmdPlaceBuilding(Island island, Vector3 posRelative) function. But ideally, I'd want to call it on the Island directly. Is this possible in a setup where the server has authority?

#

I also don't think my above idea would work because I can't send over the Island instance as command parameter. I'd have to use the index, or some other identity I guess?

sharp abyss
#

oh hang on - we're adding user creating content and building stuff to all this?

gray mango
#

yes :D the user will be able to manipulate the islands

#

players are able to place buildings on each island from a predefined set of buildings

#

each building will have production systems etc and affect the player's resource balance

sharp abyss
#

What's that game that runs ads on tv all the time?

#

Build your kingdom sort of thing

gray mango
#

not familiar, but yeah, a basic real time strategy concept of building an empire/settlement

sharp abyss
#

yeah same idea

#

been running ads for like a year

#

in US anyway

#

I can see the ad in my head but the name is escaping me atm

gray mango
#

in any case, let's say I have an island instance - how can I tell the server which island I want to manipulate so that it can update and sync the according Island instance?

sharp abyss
#

oh hang on - contractor just arrived - back in a bit

gray mango
#

no rush :) will be afk for a bit too

sharp abyss
#

Forge of Empires is the game

gray mango
#

yep, that’s a valid comparison

sharp abyss
gray mango
#

now what if 2 players build on the same island, e.g. an invasion?

#

one island is not owned by a player, they can just settle on it and occupy space

sharp abyss
#

You'd have to separate that out to prefabs each player owns to do the building for them

#

so that it could store data for that player owning those things

#

then comes the problem of players not being online and their stuff not being there

#

your Island manager that has all the seed data will need to store all items for all players who put things on a given island and keep track of who owns what

#

so Player A can see B's stuff even if B isn't online

#

it's all server-side dictionary data though

gray mango
#

I understand the concept, I guess the main question is that of synchronization between server state and what the client sees, and the other way around

sharp abyss
#

When a player goes to an island, that Island manager will have to assign ownership of stuff on that island to that client while they're online.

#

Scene Interest Mgmt will be critical here now that I know you're having players building stuff, especially since that stuff will need to be networked because they will contribute to player's economy

#

When someone goes to Island 42, let's say, server will create a subscene for it, spawn an Island Manager to it, load the items from database, spawn all that, and spawn the player into that scene, and assigns ownership to whichever items that player owns per their login.

#

When another player comes on, and goes to 42, server already has that scene loaded, so just spawn that player in and assign their stuff to that client per login

#

since no client owns the Island Manager, you can have Cmd's on it that any client can call with bypassing authority, and inside the Cmd make sure the client is actually in same scene

#

When last player leaves an island subscene, server can unload it and everything in it

#

That way you can have hundreds of islands in the database, and only the ones being actively played will be loaded at any given time

#

the subscene would just be a generic template with an island manager in it - server can load many instances of that.

gray mango
#

interesting, this is really valuable information, and I'll follow this approach!
two questions arise:

  1. Islands can be close to each other, so that multiple islands need to be rendered at once. I assume multiple scenes (islands) can be loaded at the same time (additive scenes?) to allow this?

  2. when an island is unloaded, the production buildings should still do all of their tasks (i.e. consume resources from nearby warehouses and produce different resources). is this possible with the scene being unloaded?

#

I really appreciate the input btw 😊

#

now one final question to close the remaining gap for me:

the IslandManager now has a command to add a Building : NetworkBehaviour. This building is spawned on the server, and added to the server's list of Building that will be persisted when the island needs to be saved.

Now I also want to have the list of Building instances on the island available on the client, for example so that I can focus my camera on all of them in sequence. To achieve this, do I need to add some sort of callback on the client when the building is spawned (ClientRpc?) to add it to a list? or should I use a custom spawn handler?

sharp abyss
sharp abyss
sharp abyss
# gray mango now one final question to close the remaining gap for me: the `IslandManager` n...

For the client spawned Building instances....

public class Building : NetworkBehaviour
{
    public readonly static List<Building> buildingsList = new List<Building>();

    public override void OnStartClient()
    {
        buildingsList.Add(this);
    }

    public override void OnStopClient()
    {
        buildingsList.Remove(this);
    }
}

Then you can iterate the list for focusing the camera, building.transform.position