Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (107)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1] 2
  ignore  |  Print  
  Savegame design  (Read 3014 times)
0 Members and 1 Guest are viewing this topic.
Offline markus.borbely

Junior Member





« Posted 2010-08-30 15:24:27 »

I don't want to pollute the minecraft thread anymore, doing a manual breakout thread. Smiley

Cas:
Quote
XML = yuk! Custom binary format FTW!

Me:
Quote
A little of topic but... why binary? A simple text format can be pretty compact, not compared to binary but is that an issue?
Text is more human readable but also editable. I couldn't care less if some guy cheated to beat my game.
Am I missing something?

Cas:
Quote
Easier for a machine to read and write. And therefore easier for you to code. Why deal with Integer.parseInt() when you can just read 4 bytes as an int and know it will work and not throw a NumberFormatException? and so on.

Riven:
Quote
Sure, but if it breaks, and you have to do debugging, binary looks like a bunch of random bits, whereas you can probably figure out what went wrong when browsing through human readable data.
Offline markus.borbely

Junior Member





« Reply #1 - Posted 2010-08-30 15:43:21 »

I assume "easier for the computer to read" == "easier to code" if you know exactly how to do it...
For me it is easy to slap together a few strings and write them to disk. Then I can read them back, split on various stuff and easily pick out the data. But something in me thinks it would be nice with a binary format.

Also, I plan on using the persistence API (to be able to run sandboxed). So it can't be a Reader for me. Anyone have any experience with this?
Offline appel

JGO Wizard


Medals: 50
Projects: 4


I always win!


« Reply #2 - Posted 2010-08-30 17:31:10 »

It depends on the purpose of the file.

If it's a configuration file, human readable (and editable), XML, INI or whatever, is the way to go.

Savegames? I don't think you'll ever want your players to edit those. I think Cas is right here, machine-readability/writeability should be the primary focus here. Having it in a human readable format implies that it can be modified.

Check out the 4K competition @ www.java4k.com
Check out GAMADU (my own site) @ http://gamadu.com/
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #3 - Posted 2010-08-30 18:43:18 »

Savegames? I don't think you'll ever want your players to edit those. I think Cas is right here, machine-readability/writeability should be the primary focus here. Having it in a human readable format implies that it can be modified.
Why not? Let people cheat if they want to cheat. I've always appreciated games that have cheats or character editors or whatever built in, even though I rarely use them, and when I do it's usually for a second save after I've already beat the game so I can mess around with "god-like" characters and saves. Usually I don't end up playing for very long that way, but I still enjoy it.

Plus I always feel cool if I am smart enough to change a save file without outside help. I've done it a few times via a hex editor and value searching in binary save files, but it's much more a pain and rarely worth my time.

Why get rid of something that might make your players play longer?

See my work:
OTC Software
Offline zammbi

JGO Coder


Medals: 4



« Reply #4 - Posted 2010-08-30 19:54:48 »

For my latest game I'll be doing all its settings in a basic text format. Saves me from making an editor for now.

Current project - Rename and Sort
Offline markus.borbely

Junior Member





« Reply #5 - Posted 2010-08-30 20:09:34 »

Quote
Savegames? I don't think you'll ever want your players to edit those.

Not want is one thing. Not care another. Besides, if I really want to, I can save the file as zip (or invert all bytes) and block out 99% of the cheaters Smiley

Or course, if it is a game with online highscores, protecting your save games is vital. Possibly should they be saved on the server.

My main concern here (I may not be very good a getting it out) is that I don't particularly like writing the code that does save/load. Discussing how to do it optimally is much more fun! I have been thinking on how to write a binary format easily, maybe it can be made more simple than my text format.

But it is so easy to like this (super simplified, but it took less than a minute to write):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
String wholeSaveGame = ...
String[] lines = wholeSaveGame.split("\n");
for (String line : lines) {
    String[] keyValuePairs = line.split("$");
    for (String pair : keyValuePairs) {
        String key = pair.split("=")[0];
        String value = pair.split("=")[1];
        //use BeanUtils from apache to set this keyValue to the object at hand
   }
}


If you don't like BeanUtils, writing it yourself takes less than 5 minutes.
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #6 - Posted 2010-08-31 01:04:37 »

Or course, if it is a game with online highscores, protecting your save games is vital. Possibly should they be saved on the server.
I would remove the possibly and say absolutely. If you actually care about data getting hacked, no matter how you mess with your save file people are still going to find a way to break it, so you absolutely must put it on a server - if you care. If you don't why waste time?

See my work:
OTC Software
Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #7 - Posted 2010-08-31 02:17:19 »

If you don't like BeanUtils, writing it yourself takes less than 5 minutes.

Check out my sig. In less time than it took you to write those for loops, you could write out AND read in objects in either binary format using Kryo or human readable text format using YamlBeans. Smiley

Offline markus.borbely

Junior Member





« Reply #8 - Posted 2010-08-31 11:23:12 »

Check out my sig. In less time than it took you to write those for loops, you could write out AND read in objects in either binary format using Kryo or human readable text format using YamlBeans. Smiley

Thanks, will have a look.
Offline dime

Senior Newbie





« Reply #9 - Posted 2010-09-02 01:04:02 »


I keep my settings in INI, easy to pull out.  For static game data (weapons, classes, etc) I haven't decided yet, but think sqlite might be a good way to store that info

For dynamic game data (players, levels, etc) you can serialize a java object and write it to disk.  Super easy and quick to save/load.
You can even run it though gzip or encrypt it before saving it to disk if worried about cheats.  Not fool proof, but will slow them down.
Also serialized objects can be sent over net.

The only downside is if your classes change (ie. game update) then reading old data files (saved games) might get kind funky.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #10 - Posted 2010-09-02 01:11:29 »

I could have written a fancy pants XML writer (and reader let's not forget), or even gone super-verbose and used javabeans XML output, or done something with JSON, or whatever. But because my time is rather valuable I did this:
1  
2  
3  
4  
5  
6  
FileOutputStream fos = new FileOutputStream(file);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(gameState);
oos.flush();
fos.close();

and thus in 5 lines of code solved all my actual real problems forever and got back on with the more urgent requirement to figure out how to put "medals" into Revenge of the Titans. This has been working nicely for me and 1,000,000 players for the last 7 years or so.

Yes, gameState is the entire state of the game. References to game data are stored with a bit of fancy pants serialization trickery but nothing that clever (which basically involves replacing references to stuff like textures with strings that I can use to look up that texture again on loading).

YMMV.

Cas Smiley

Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #11 - Posted 2010-09-02 03:14:12 »

Yes, gameState is the entire state of the game. References to game data are stored with a bit of fancy pants serialization trickery but nothing that clever (which basically involves replacing references to stuff like textures with strings that I can use to look up that texture again on loading).
Aha, so it isn't as simple as you made it look. Smiley

Java's built-in serialization is workable for many tasks, but has a typical ugly Sun API. Also, it uses an extralinguistic mechanism to create objects that bypasses constructors. This is hacky and can have unpredictable results.

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #12 - Posted 2010-09-02 06:41:33 »

That's why, like I said before, you just make a SavedObject that has the information it needs to construct the actual objects you want. Solves all the problems - what Cas is describing is more or less the same thing, from what I understand.

See my work:
OTC Software
Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #13 - Posted 2010-09-02 07:13:11 »

That's why, like I said before, you just make a SavedObject that has the information it needs to construct the actual objects you want. Solves all the problems - what Cas is describing is more or less the same thing, from what I understand.

So you duplicate the storage of all the data you want to serialize? This is fine for shallow graphs, but could easily be tedious to implement and maintain for larger graphs. FWIW, Google Protobuf generates the data storage classes and says these classes "don't make good first class citizens in an object model". They recommend wrapping the data storage in an application object. This is a PITA, but if you want to exchange data with other languages, it may be worth it to use Protobuf. Otherwise, IMO it generally isn't worth the trouble to use this approach. Better to use a mechanism that can serialize your application objects directly. Using the built-in serialization for this has the issue I mentioned. Most serialization libraries can serialize third party classes. Typically you implement an interface or register some serialization code for a class to customize serialization.

It isn't really a hard problem to solve, so it really comes down to how invasive is the serialization API and any specific features you need (speed, size, customization, versioning, forward/backward compatibility, binary/text, etc).

For my libs, I tried to make a clean API that gets in the way as little as possible. Simple POJOs can be written out with less code than Cas posted for built-in serialization. I make the assumption that Java + my lib is what is going to consume the serialized format, which allows for some optimization (eg, the class definition *is* the schema).

Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #14 - Posted 2010-09-02 13:35:12 »

You could indeed make a rather simpler serialization mechanism. Except by the time you were finished you'd end up with exactly what Sun have already done for you.

Cas Smiley

Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #15 - Posted 2010-09-03 01:00:33 »

You could indeed make a rather simpler serialization mechanism. Except by the time you were finished you'd end up with exactly what Sun have already done for you.
I did make a rather simpler serialization mechanism and it is not exactly what Sun has done for me. Smiley

Offline loom_weaver

JGO Coder


Medals: 17



« Reply #16 - Posted 2010-09-19 21:04:33 »

What strategies did you use to handle upgrading the save game from a previous version to the current?
Offline CyanPrime
« Reply #17 - Posted 2010-09-19 21:16:26 »

easier to code FTW.
Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #18 - Posted 2010-09-20 10:25:18 »

What strategies did you use to handle upgrading the save game from a previous version to the current?
I keep the game in "alpha" state and break savegames frequently Wink

Cas Smiley

Offline OttoMeier

Senior Member


Medals: 4
Projects: 1



« Reply #19 - Posted 2010-09-20 19:24:32 »

What strategies did you use to handle upgrading the save game from a previous version to the current?
Thats the main problem. With serialization you break the data encapsulation so that refactoring is hard if you need backward compatibility.
Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #20 - Posted 2010-09-20 22:33:55 »

It's not such a problem if you plan ahead for it and design accordingly.

Cas Smiley

Offline Karmington

Senior Member


Medals: 1
Projects: 1


Co-op Freak


« Reply #21 - Posted 2010-09-21 00:45:55 »

Once had a project spanning many years and backwards compatibility had to be good for all users from day one, so they wouldn't lose their stuff. we had a different loading + initialize function for all the save versions going back a dozen revisions. I don't know if there are any cleaner ways of doing it.
So if the user had v1.11 saved on server, boots up the new version 1.12 client, the server would update the savefile.
I believe we also kept the last couple of versions backed up in case of goofups.


Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #22 - Posted 2010-09-21 02:08:18 »

Once had a project spanning many years and backwards compatibility had to be good for all users from day one, so they wouldn't lose their stuff. we had a different loading + initialize function for all the save versions going back a dozen revisions. I don't know if there are any cleaner ways of doing it.

While that approach is the most flexible, it is also the most tedious. There are other ways of providing forward and backward compatibility.

Rather than assuming the saved data will be in a specific order, if you annotate each piece of data with what field it corresponds to, your saved data will be larger, but makes it easy to support limited compatibility. Eg, if a field has been removed, you can just ignore the old data for that field. If a field has been added but doesn't exist in old data, you can just leave the field at its default. If a field's type has been changed, you can attempt to massage the value into the new type (int -> float, long -> String, etc). It isn't easy to support renaming fields with this approach, so don't do that.

If you have a schema for your saved data, adding/removing field could work the same way but you could also describe differences in versions (eg, renaming fields or type conversions) and have whatever parses your data handle it. I find writing and maintaining a schema to be annoying though.

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #23 - Posted 2010-09-21 02:53:38 »

Just use java.io.externalizable and then you can use ObjectOutputStream. Then just use a Map with and any values that don't exist get set as a default. This works fine.

See my work:
OTC Software
Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #24 - Posted 2010-09-21 05:06:28 »

Just use java.io.externalizable and then you can use ObjectOutputStream. Then just use a Map with and any values that don't exist get set as a default. This works fine.
Sigh... no!

Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #25 - Posted 2010-09-21 11:31:12 »

Ordinary serialization already does all of the difficult work involved in this problem. The problem exists no matter what binary or ascii format you use to actually encode the data; that is, if you change the data model, you have to figure out what to do with all the persisted data in the wild.

If you're looking for a magic bullet that miraculously solves the problem, and for example write your own serializer, all you've done is reinvent a perfectly good working wheel probably incompletely, and then you're left with exactly the same problem you had when you started.

Cas Smiley

Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #26 - Posted 2010-09-21 14:23:11 »

Aaaand we're back to reply #14.

Offline princec

JGO Kernel


Medals: 343
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #27 - Posted 2010-09-21 14:37:45 »

Exactly. Running around in circles reinventing something that already does what it says on the tin, trying to find a shortcut to solving a problem that cannot be solved with shortcuts.

Cas Smiley

Offline Nate

JGO Kernel


Medals: 145
Projects: 4
Exp: 14 years


Esoteric Software


« Reply #28 - Posted 2010-09-21 15:30:12 »

The built-in serialization is crappy. If it happens to be sufficient for you, that is great, but there are many scenarios where it is a poor choice. Eg, if you wanted serialization to be fast, or if you wanted the output to be small, or if you wanted to use standard constructor invocation, etc.

You'll notice "java-built-in" does badly in the benchmarks, while "java-manual" does well. The latter uses java.io.Externalizable and is hand written serialization code. This is fast and efficient, but extremely tedious. It isn't any special win for the built-in serialization, as any interface with "readBytes" and "writeBytes" methods could do the same. It also doesn't handle backward/forward compatibility.

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #29 - Posted 2010-09-21 16:30:48 »

LOLLOLLLLOLLLL.

All right I'm going to stop discussing this topic now. Tongue

See my work:
OTC Software
Pages: [1] 2
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (8 views)
2014-07-30 21:08:39

Riven (20 views)
2014-07-29 18:09:19

Riven (14 views)
2014-07-29 18:08:52

Dwinin (12 views)
2014-07-29 10:59:34

E.R. Fleming (32 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (42 views)
2014-07-24 01:59:36

Riven (42 views)
2014-07-23 21:16:32

Riven (29 views)
2014-07-23 21:07:15

Riven (30 views)
2014-07-23 20:56:16
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!