Project 1935 Devlog #3
(Originally written on 11th Jun @ indiedb)
This is the final devlog copied over from indiedb, I will be writing them here from now on.
I am just going to preface this by saying that, In hindsight, aiming for 1 devlog a week when my workflow is so erratic and where the work I do complete is very small simply because I am still laying the groundworks for the game, was a bad decision, and therefore I am going to aim to do a devlog every 2 weeks, after all the devlog is for me to look back on what work I have done, and so giving myself more breathing room seems like the best choice.
Provinces
In the last devlog I got each province to recognise when it was clicked, and to raise slightly. This lead towards the ultimate goal of loading a provinces data into the province management UI when the province is clicked. This now works perfectly and will load the data associated with a province when it is clicked, whilst also still raising it slightly. You can see this in action below, bearing in mind the data for each province is arbitrary at the moment however you can see that the name of the province is updated as that is the only difference between them currently.
The system shown above works for all nations in the game, if you set your nation enum to France for example, you will able to select any of the provinces belonging to france and their data will be loaded. I will talk about networking next in the devlog but the province data that is stored, is only for your nation’s provinces, and if, down the line, you acquire a new province, that province’s object can just be added to your provinces List and it will work as expected.
The base province system is close to being finished, excluding the temporary UI. All that needs to be added is a building system that will carry out actions either for that province, or on that province and also the resources provinces bring in overtime and how they attribute to the overall resources income. I aim to get most, if not all, of this done by July.
Networking
Now, it was at this point in the previous attempt at this project where I stumbled and quit and honestly, when tackling the problem this time around I felt almost exactly the same sense of dread and inability as I was stuck on the same issue that plagued me previously, before I get into that issue and how I came over it, let me talk a little bit about the work done leading up to that point.
So I got basic networking in place, clients can connect and the data associated with the nation chosen, including the nation enum is now taken from its locally stored position and is stored on a PlayerManager that is synced over the network and spawned in when a client connects. At this point, if the host/server moved a unit, it will happen for both the server and the client, but if the client moved a unit, it would only happen locally for the client. This was the issue that stopped me previously, as I searched and searched without any results, everything I found was geared towards games where an object was obviously the player, and that object needed to be the only thing that was controlled however in this game the player is only an object holding data related to them, and the objects that need to be networked are acting like pieces on a chessboard.
My goal now was to have the client tell the server to do something, everything that had an effect on the game (such as moving a unit), needed to be carried out by the server. Without going into too much detail, every unit was both an object on the server and on the client and on the client’s local unit I need to call a function that moved the server’s local unit when the client’s local pin was placed. I achieved this using a [Command] function that would trigger the unit’s isMoving bool whilst passing in the client’s local positional data. So everything up until when the pin is placed happens locally on the client, but then once the pin is down the server’s unit will start moving toward the pin, even though no pin is actually on the server. I also send a quick RPC call to the client when the unit on the server has reached its destination, so it knows to remove the locally placed pin.
You can see above that as soon as the pin is placed, CmdPinPlaced is called which resides on the PlayerManager belonging to the currently connected client.
This might seem obvious now, and it sort of is, but networking requires a different mindset and way of approaching problems, afterall, networking using an already available solution such as UNET isn’t inherently difficult, just the way in which you need to think is. Anyway, using the code above, this worked. Now obviously I have simplified it a lot and I didn’t just come up with the solution, I needed to realise that everything the client had to tell the server, needed to come from the client object (PlayerManager), and so what you see above is the abstraction of the pin placement functionality from being isolated on the Unit, to being triggered by the player.
Now the actual movement of a unit was out of the way, I set to work on spawning a unit for each client that connected so that I could see how the passing of information worked, and whether a unit that does not have a parent nation of your nation could be interacted with. This proved more difficult than I had imagined, but I managed to get it working.
When a client connects, I set their nation locally, randomly at the moment for testing but down the line a nation will actually be chosen, but it will work exactly the same. When setting their nation locally it avoids the issue of assigning different nations to a client on the server to the one that is local to the client. This is done by checking if the client is local before choosing a nation at random as what tended to happen was the server would choose a nation via the spawned PlayerManager and then the client would also do the same causing the aforementioned problem.
*Top tip, use enums, you get lovely inspector drop downs, and you can reference them by index allowing you to choose an enum value at random like shown above!
This is key because when a unit is spawned, I need to check its parent nation against the clients that are connected, but this needs to happen serverside for obvious reasons. When a unit is spawned I set the access matrix for that unit as an RPC call which basically means it occurs on the server, but also on all clients, ensuring that there are no discrepancies between the server unit and client unit.
There was an obvious issue though, being that if a client connects, and has a unit that has checked all other clients when it is spawned to see if they own it, what happens if another client connects when a unit has already been spawned, it will not set its access matrix for that client. So I need to re-call a unit’s InitialiseAccessMatrix() function when a client has connected, I did this by storing every unit into a List of gameobjects when they are spawned, or more specifically their Unit.cs component and I then call that RPC function via a client when it connects. Right now this happens for all units, although some check in the future should be put into place to ensure units that already have their access matrix set aren’t being asked to do so again, and to make sure that the RPC call only occurs for the client requesting it.
So, this was a relatively boring devlog as I feel most of them will be until I get into the thick of the work but I’d just like to say that getting the base of the networking up and running was a big milestone for me, and has made me feel like I can actually make the game I want to make now. I’d like to thank the community at GDN as they helped me fix some issues I just couldn’t get my head around, more specifically @radicalchristo and @Hayaweh on the Discord.
0 comments