• Post Reply Bookmark Topic Watch Topic
  • New Topic

newb confused about persisting game states  RSS feed

 
Darren Estcourt
Greenhorn
Posts: 25
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok so, I am writing a football management game and I am puzzled as to what the best strategy would be for persisting my data. At the moment, I have a Java based GUI and a MYSQL database as the back end. I know how to read and write to my database. However, my question pertains to saving games and loading games. I realise that I need to store my game "state" , and my initial thought was to have an original database which can be loaded, if the player starts a new game. Likewise, if a saved game is loaded, I would load the sqldump when I made a copy of my database, which contains user info, such as a name they have entered.

Eventually this will be a large database, and therefore I have ruled out using serialization, purely because I will need to be able to search through my data. Please can someone offer some suggestions in terms of loading/saving database states.

Thanks
 
Stevens Miller
Bartender
Posts: 1445
30
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That's a pretty broad question, Darren. Let me offer a few broad thoughts that might help.

What's necessary to define the state of a game? For example, the score for each team might be part of the state, whereas the location of the players on the field might not. How about which players are on the bench, versus which are on the field? Once you know that, then I think the you might want to consider how you are going to store that state. My personal preference is to store state in plain text. That makes it easy to inspect for debugging purposes. It also allows you to edit the state "by hand," which can also be useful for testing and debugging. Plain text helps you with platform independence too, though I sometimes think that's more of an imaginary problem than a real one.

Some folks are in love with XML as a form of plain text for storing state. It's nice and there is some Java support for it. My limited experience with it, however, has not made me a fan. It can be a bit high-maintenance when all you want is to read and write some data. I have heard that JSON is XML's successor, but have not used it myself.

Mostly, I use a Scanner object. The reason I like Scanners is that you can use them to have objects load themselves. That is, you can open a Scanner on a file, then pass the scanner to, say, a Game object. The Game knows it needs to load, say, two Teams, so it what it might do is pass the Scanner to the constructor for the home Team object, then pass it to the constructor of the away Team object. Team objects might know they have to load, perhaps, lists of Player objects, so the Scanner could be passed to Player constructors, reading Players from the file. The idea is to make each class responsible for reading itself from a plain-text file, completely decoupled from the class of the object that calls its constructor. You are free, in that approach, to let each class use whatever format it likes for storing/loading its state, provided the Scanner can read it. Now, my files to tend to get a bit bloated, but disk space is cheap these days, so that doesn't worry me. Long ago, I used to store my data in native formats (four bytes for a float, and so on). That was because the overhead in converting from text to native was significant. Let's just say that's not a problem I worry about in 2017.

One word about serialization: don't. It's tempting, because it is easy to use and stores things in a compact format. But, you can't read it and (much more importantly) it may change from one release of Java to the next. Just don't.

Let us know more about what your game state requires you to save/load, and maybe I or others can say more to help.

Cheers!
 
Darren Estcourt
Greenhorn
Posts: 25
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for that As a starting point, I want the users name and selected team to be persisted. To me, that means invoking a Java method which either run executeUpdate() or executeQuery() to my MYSQL database. The latter using a SELECT statement. For small amounts of data, this is fine. But then I wonder, what happens when player statistics need to be updated and then read back...that's a lot of MYSQL queries.

My other issue is knowing how I should present data in my GUI. I am thinking about "seperation of concerns" and yet I am tempted to run a SELECT statement from a method in my GUI, but then of course it will slow my GUI down.

Suffice to say I am still a newb in this context. Grateful for any advice
 
Stevens Miller
Bartender
Posts: 1445
30
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I'd suggest keeping these two notions in mind:

1. Keep your data model and your user interface separate. Among other things, that means your SELECTs and other SQL stuff should never appear in your GUI code. Instead, figure out what data your GUI will need, and create getter methods to retrieve that data. Those getter methods are where your SQL belongs. One advantage to this approach is that you can change how the getter works, while your GUI code can remain the same. For example, you may switch from a SQL database to something else entirely, something that may not even use SQL. You sure don't want to have to recode your GUI to cope with that. Another advantage is that not everyone knows how databases work, but most any Java programmer will understand a getter. So, if anyone else ever has to work on your code, isolating the SQL behind a set of methods keeps it simpler for the next person.

2. Don't optimize.  Go ahead and fire off as many SQL commands as it takes to maintain your data. If and when your program starts acting sluggish (which, from the little I can glean about your project so far, I would guess will never happen), you can figure out where the slow parts are and speed them up. Until then, don't waste time on problems you don't have.

That second one can be a hard rule to follow, I know. But computers are so fast today, compilers are so good, and SQL servers are so advanced that it really does make sense to just forget all about optimization unless and until you need to. To be clear, I'm not saying you should write sloppy code you know is inefficient. Just do good work without making any specific effort directed at improving performance. There's a lot of wisdom out there about this, but my version harkens back to the '80s, when we followed these steps in every project:

First, make it run.

Second, make it work.

Third, make it fast.

These days, that last one is amended to read, "make it fast (if you need to)."
 
Carey Brown
Saloon Keeper
Posts: 3310
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
How much data is in a Game State? Is it flat or hierarchical?

what happens when player statistics need to be updated and then read back...that's a lot of MYSQL queries

Why wouldn't that be only one query? Do you not have a "player_statistics" table? (edit) Or the ability to emulate one using SQL joins.

...loading/saving database states

Not clear on this one. You have a database which has a state, you modify the database and you have a new state. When you say you're going to load/save a database state do you mean you are going to make copies of the database at some point in time? Why not add a timestamp or similar state identifier column to your tables?

(edit) I'm getting the sense that your database schema doesn't fit well with the intended goals of your program.
 
Darren Estcourt
Greenhorn
Posts: 25
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have gone down the route of reading about timestamps and I can't find anything which suggests what type of field should have a timestamp.

My objective is just to version tables, so that when the user loads a saved game, the correct version of the table(s) are loaded.

I figured I wouldn't import a whole database, which might take a long time, given this database will be relatively large. Instead I would version tables with a timestamp and just load the tables required.

Can anyone offer me their insight on this issue?

Thanks

 
Carey Brown
Saloon Keeper
Posts: 3310
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darren Estcourt wrote:I have gone down the route of reading about timestamps and I can't find anything which suggests what type of field should have a timestamp.

Fields don't have timestamps. You usually have one timestamp for an entire row.

I suggested timestamps as a possible way to handle versioning. Not being familiar with your requirements, you might have also used a unique ID of some sort.

My objective is just to version tables, so that when the user loads a saved game, the correct version of the table(s) are loaded.

I figured I wouldn't import a whole database, which might take a long time, given this database will be relatively large. Instead I would version tables with a timestamp and just load the tables required.

If the rows have some sort of versioning ID then you don't have to load the entire table, you could add a WHERE clause to your query which would only return applicable rows. Potentially, adding a table index on the ID would make such queries very fast.

To be of much more help you'd need to give us some additional information on your fields (columns).
 
Junilu Lacar
Sheriff
Posts: 11477
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Stevens Miller wrote:
First, make it run.

Second, make it work.

Third, make it fast.

These days, that last one is amended to read, "make it fast (if you need to)."

Not sure what the nuance is between the first and second one.

Did you mean Make it work, make it right, make it fast?
 
Junilu Lacar
Sheriff
Posts: 11477
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darren Estcourt wrote:
My objective is just to version tables, so that when the user loads a saved game, the correct version of the table(s) are loaded.

I figured I wouldn't import a whole database, which might take a long time, given this database will be relatively large. Instead I would version tables with a timestamp and just load the tables required.

Can anyone offer me their insight on this issue?

That sounds like NOT a good idea. You're using a relational database, so create some relationships. Peter Coad has something he calls a Moment-Interval - that's what comes to my mind for this. Basically, you want to capture a "snapshot" at a given moment in time of the state that you want to save. Everything in that snapshot will be related to the Moment-Interval that will tell you the when/where/who of what was going on at the time.  All that information goes into the same tables as the information saved for all the other snapshots and the way you separate on set of data from others is via unique keys/identifiers. There's no need to go down to the database level and load/unload stuff. That would be like buying a GPS device to get you to one place, then buying another GPS to get to another place, then another GPS to get to another place, then ... well, you get the picture, right?
 
Stevens Miller
Bartender
Posts: 1445
30
C++ Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Junilu Lacar wrote:
Stevens Miller wrote:
First, make it run.

Second, make it work.

Not sure what the nuance is between the first and second one.


This doesn't run:


This runs, but it doesn't work


This works, but it isn't fast:


This is fast:



Looks like you understood me after all! 
 
Darren Estcourt
Greenhorn
Posts: 25
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"All that information goes into the same tables as the information saved for all the other snapshots and the way you separate on set of data from others is via unique keys/identifiers".

Given the above comment, please can someone provide a link, which shows examples of sql code to capture a snapshot, without using mysqldump ?

The official mysql doc shows to use mysqldump.

I have googled this quite a lot and can't find anything specifically useful.
 
Carey Brown
Saloon Keeper
Posts: 3310
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You seem to be wanting MySQL to supply an answer to your problem. MySQL doesn't have one. Instead it provides abilities to read/write/update/delete records from your tables. So, the question becomes, how do you design your tables to facilitate versioning and how would you manipulate your records so as to make them behave like versioned records.

Determine which version you want to load, e.g. '1'.
Read all records whose Version is '1' into a list of java objects.
Play the game, updating the java objects as you go.
Update the Version in the java objects to '2'
write the list of java objects out to the database as new records

An example set of records where 'Version' keeps track of your versioning
VersionPlayerScoreLast Move
110410
123942
210711
2231248

So, next time read all records with a Version of '2' and when you're done write them back out with an Version of '3', etc..
 
Junilu Lacar
Sheriff
Posts: 11477
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The table that Carey showed would be your version details table. A master table might have columns for date/time and version number. Each row in the master table will have a unique timestapm and version number. This would be your way to keep a catalog of all the snapshots you have taken of your data. So if you want to see the data for the snapshot taken at 4pm yesterday, you would look up that timestamp in the master table, get the corresponding version number, then go to the details table and show all the data that have that matching version number.
 
Carey Brown
Saloon Keeper
Posts: 3310
46
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Darren, I feel we are trying to help you by guessing at your requirements.
  • Why do you want a "snapshot" (aka version)?
  • What event drives the creation of a snapshot?
  • Under what circumstances would you need to access an old snapshot?
  • Would a sequential 'version' number column suffice or do you need something more specific such as a timestamp?

  • It's hard to suggest how you might modify your tables to support versioning without a clue as to what is in the table.
     
    Dave Tolls
    Ranch Foreman
    Posts: 3056
    37
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I'm not sure about newer games, but the old Championship Manager ones essentially saved the database.  So each save game was the db for that particular run.

    What sort of level of detail does this game have?
    To take the CM games, each player/coach/scout/etc (as in team player, not human game player) has their own "row".
    If you have the same level of detail, then each save game will end up with duplication of those players etc.
    That'll be one massive db quite quickly.  Again, depending on the level of detail you go down to.

    I would have gone with an embedded db (Derby or similar).
    Back up of that (eg a save game) would simply be a case of close the db and zip it up.
    Restoring a save game would be close the db and delete it, find the zip file, unzip it to the old location...well, similar to that anyway (you probably want to ensure it unzips before blatting the old db).

    MySQL is too big and chunky to handle that sort of thing.
     
    Darren Estcourt
    Greenhorn
    Posts: 25
    • Likes 1
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Thanks all

    My requirements are simply to allow the user to click "save game" in my Java gui, and it will load their previous game. I started out using serialization, but then realised two things.

    1. Serialization is limited, I can't create relationships per se, and I cannot read data from multiple sections aka there are no joins in serialization.

    2, I felt it would useful to learn another language other then Java and my game will require some form of storage. I opted for mysql because it is open source. It might not be the most suitable RDBMS but I am a newb to back end code.

    The point of the snapshot, was to simply save the game at a specific point, such that, the game can be re-loaded when the Java event is triggered by clicking the "load game" button.

    Now then, I already know how to backup and re-load a mysql database using mysqldump and as Dave pointed out, this is one strategy which has been used in commercial software before. BUT it surely isn't the most elegant solution. In terms of level of details, I want the detail to be comprehensive, so I am anticipating a large database.
     
    Dave Tolls
    Ranch Foreman
    Posts: 3056
    37
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Well, mysql's backup and restore is pretty heavy duty.
    From what I can remember it essentially creates a bunch of SQL for rebuilding the database, which is fine for normal usage.

    This is not, however, normal usage.

    What I'm suggesting is using something like Derby where the backup and restore are, simply, zipping up the database directory.

    Trying to put the save state into the database will, I think, prove complex, large, and inevitably prone to bugs.

    The advantage of derby is that it comes with the SDK as well.
     
    Carey Brown
    Saloon Keeper
    Posts: 3310
    46
    Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Darren Estcourt wrote:Thanks all

    My requirements are simply to allow the user to click "save game" in my Java gui, and it will load their previous game. I started out using serialization, but then realised two things.

    1. Serialization is limited, I can't create relationships per se, and I cannot read data from multiple sections aka there are no joins in serialization.

    2, I felt it would useful to learn another language other then Java and my game will require some form of storage. I opted for mysql because it is open source. It might not be the most suitable RDBMS but I am a newb to back end code.

    The point of the snapshot, was to simply save the game at a specific point, such that, the game can be re-loaded when the Java event is triggered by clicking the "load game" button.

    Now then, I already know how to backup and re-load a mysql database using mysqldump and as Dave pointed out, this is one strategy which has been used in commercial software before. BUT it surely isn't the most elegant solution. In terms of level of details, I want the detail to be comprehensive, so I am anticipating a large database.

    Excellent response. Your efforts here are appreciated.

    1. Serialization: The fact that you were even considering this says to me that your "Game" including all associated objects (Teams, Players, etc.) will fit into memory. A database to hold this probably won't be as large as you'd think, especially in relation to the size of a database that MySQL is designed to handle. As for joins, a java object can reference another java object (has-a). Java objects can have Lists or Maps of other java objects. When you serialize your "Game" object it will also serialize any objects and collections that your Game refers to.

    2. Learning about Java and Databases will add to your skill set and give you a powerful tool for handling other kinds of problems. MySQL is a good choice. Whether or not Derby would be a better choice I can't say. MySQL requires that you have a service running, with Derby you can use it through a service or you can embed it (I like Derby for this embedded feature an my come back to it at some date). If I recall correctly, MySQL is more "SQL standard" compliant than Derby but Derby has most of the SQL features but it might involve some research into the Derby specifics when you go to implement it.

    Backing up a MySQL database creates a very verbose copy of the data, essentially a SQL text file that contains all the SQL statements to rebuild a database. If you think your database will be very large then these will be huge.

    If I understand you correctly, you'd write out the state of your Game when you click "Save", this would save the current game. When you start up your program it would automatically load the "current" saved Game. When the user clicks "Load" they will be given a list of historical saved Games to load and then load one of them.

    Sounds like you'd have the concept of a "current" Game and 1 or more historical Games. How many historical Games do you need to keep around? Would you need to deal with more than one Game at a time, e.g. for comparison?

    I don't see anything in your description that would lead me to be concerned about the size of your database. Purging old Games is an option if that becomes an issue.

    I still see versioning the data in your tables is the way to go.
     
    Consider Paul's rocket mass heater.
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!