Online RTS with a persistent world - a basic design issue

Started by
7 comments, last by Insdeath 12 years, 6 months ago
Hello gamedev.net forum!

For some time now, I have been thinking to make a game of my own. It's nothing big or fancy, I don't have high expectations nor am I overly ambitious about this, it's mostly to see what I am capable of doing and to gain a lot of experience in game design and programming in general.
I use Java as programming language, because I have a lot of experience with it. I have been maintaining a simple (java-based) MMORPG (not made by me) for about 2 years and currently have an understanding of how everything works inside. I mean to take this a step further, and actually create a game of my own from scratch. But instead of an MMORPG, I would like to make an (MM)ORTS (basically like Evony/Tribal Wars).

At first, I would like to start simple by having the following:
- A client
- A server with a persistent world
- A persistent world which consists of continents, countries and villages. Villages are part of countries, countries are part of continents.
- A database to save the persistent world and player-data
- Buildings which can be placed, upgraded and destroyed, producing resources or units
- Some units which can walk around, fight each other and destroy buildings
- A bit of basic AI

I know how to make most of these things work, I know a great deal about algorithms, networking, database and real-time rendering.
However, I am struggling with a very basic yet very important issue: I need to know how to save the persistent world in both the server's memory and a database (database only being used in case the server crashes to rebuild the world), in an efficient and proper fashion.

(Note I am only talking about Arrays and ArrayLists below, but this datastructure can be replaced with any other datastructure which is a better choice in each situation)

1) Do I keep a static Array of my continents, each containing an Array of countries, and each country has an ArrayList of villages? Does each village contain an ArrayList of buildings and units placed within?
2) Does each building/unit have a reference to the village it is in? Does each village have a reference to the country it is in? Does every country have a reference to the continent it is in?
3) Where do I keep track of the units? Especially given they can move from one village to the other.
4) Same 3 questions, but this time in the database. How do I link everything together? I know how to link countries and continents to each other in a database, but I'm not sure how to link the villages/units/buildings together especially since they are quite dynamic.
5) Say the server crashes. After the crash, the server has to rebuild the persistent world based on the contents of my database. What is the best approach (design-wise) to prevent desynchronization of events, rollbacks or other inconsistent data?


I hope the questions are quite clear, and that someone is willing to assist me with this issue. I'm not expecting a clear-cut answer, but anything to point me towards the right direction is helpful. Anyone who has some experience with (online) RTS games probably knows the answer to many of these questions, and I don't think there is a major difference between C++ and Java design-wise.

Thank you!
Advertisement

1) Do I keep a static Array of my continents, each containing an Array of countries, and each country has an ArrayList of villages? Does each village contain an ArrayList of buildings and units placed within?


Seems reasonable enough (except for using arrays).


2) Does each building/unit have a reference to the village it is in? Does each village have a reference to the country it is in? Does every country have a reference to the continent it is in?
[/quote]

Depends on what you need to do with them. Probably.


3) Where do I keep track of the units? Especially given they can move from one village to the other.
[/quote]

In a collection in the village I'd guess. Probably a few other collections too. Depends on what they're doing.


4) Same 3 questions, but this time in the database. How do I link everything together? I know how to link countries and continents to each other in a database, but I'm not sure how to link the villages/units/buildings together especially since they are quite dynamic.
[/quote]

Foreign keys seem to be the straight-forward approach here. Not sure why you'd think that another approach is even viable.


5) Say the server crashes. After the crash, the server has to rebuild the persistent world based on the contents of my database. What is the best approach (design-wise) to prevent desynchronization of events, rollbacks or other inconsistent data?
[/quote]

Transactions are your friends. Prevent data issues in the DB, treat that as the source of truth, and things flow fairly well from that. Events are... not your friends for this sort of thing.
Thanks for your quick response. So apparently, there doesn't seem to be any specific, 'special' approach for this kind of games, just following my gut instinct then :P

Concerning the database, what do you mean exactly by Transactions vs Events?
I would present Events as following: it has a starting point (the current time in milliseconds as obtained from System.currentTimeMillis()) and the time it takes to complete/start the event (also in milliseconds). However, say the server is down for about one hour, how do I then make sure my event still works properly and isn't desynchronized with the rest of the world data?

I'm not exactly sure as to what Transactions are...
Well, first things first, search for transactions. They're a vital aspect in maintaining database integrity.

As for events, you'll need to be more specific since I perhaps misunderstood what you were aiming for.
An example of an event is the following:
A building is being constructed. I create an event for this which I place in a priorityqueue. This queue handles so-called timed events for me (events which I give a starting time and an execution time).
Let's say the building starts being constructed at sept 28, 4PM GMT. The construction takes 20 minutes. So we save that information in the database.

However, if the server were to crash in the middle of this event, and is only rebooted say an hour later, then how do I make sure the server doesn't suddenly think the building is already constructed at the moment it reboots? It will think the construction has been finished, based on the starting time and the time it takes to build.

I probably need a special frame of reference for this. Maybe an internal clock in the server which only runs when the server runs, and everything is calibrated according to that clock?

Thanks for the information about transactions, I'm looking up how exactly those work and I will make sure to integrate this into the server.
[EDIT] Someone who works with me and who is responsible for all database-related issues said he knows about transactions and how they work. So we have that :)

However, if the server were to crash in the middle of this event, and is only rebooted say an hour later, then how do I make sure the server doesn't suddenly think the building is already constructed at the moment it reboots?


Why isn't the building already constructed at the moment it reboots?

[quote name='Insdeath' timestamp='1317159087' post='4866585']
However, if the server were to crash in the middle of this event, and is only rebooted say an hour later, then how do I make sure the server doesn't suddenly think the building is already constructed at the moment it reboots?


Why isn't the building already constructed at the moment it reboots?
[/quote]

It's not constructed because 20 minutes of in-server time hasn't passed. By simply recording the start and duration, if the server is offline for the entire duration and comes back up later it will assume the construction has completed.

One way to handle this is to initialise a counter to a certain number of "ticks", and then decrement it every so often while the server it running and then check for it reaching zero. If you do that, you don't even need to store the start time. You're effectively storing a "time until construction is complete". For an MMO, 1 second per tick is probably too frequent, you don't want to overload the server unnecessarily. Depending on the event durations involved you could push it out to 15, 30 or even 60 seconds if you're not too concerned about the timing being a little inexact.
[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

[quote name='Telastyn' timestamp='1317161521' post='4866597']
[quote name='Insdeath' timestamp='1317159087' post='4866585']
However, if the server were to crash in the middle of this event, and is only rebooted say an hour later, then how do I make sure the server doesn't suddenly think the building is already constructed at the moment it reboots?


Why isn't the building already constructed at the moment it reboots?
[/quote]

It's not constructed because 20 minutes of in-server time hasn't passed. By simply recording the start and duration, if the server is offline for the entire duration and comes back up later it will assume the construction has completed.
[/quote]

Right, I gathered that was the issue, but why is that the game design? Isn't that confusing to users? They see it'll be done in 3 hours. 3 hours passes, they come back and see 2 hours left?

Frankly that's a more complex technical implementation that provides (from my perspective) no benefit to your players.

Right, I gathered that was the issue, but why is that the game design? Isn't that confusing to users? They see it'll be done in 3 hours. 3 hours passes, they come back and see 2 hours left?

Frankly that's a more complex technical implementation that provides (from my perspective) no benefit to your players.


Very good point.

Then I assume it's best to do the following:
At server startup, execute any events that would have been executed during the server downtime, such as unit training, building construction, resource gathering, battles, ..., based on the start time and duration.

Thank you very much for your help, I think I can manage my project on my own now. I was unsure about whether my basic design was good or not. Thing is, if my basic design is bad and I base everything off that, then at some point I may have to throw away all my current code and start all over again. I'd prefer not to have that happen :P

This topic is closed to new replies.

Advertisement