Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


EDI

Member Since 05 Jan 2002
Offline Last Active Jun 26 2015 12:55 PM

#5235281 Tiny Serialization Library

Posted by EDI on 17 June 2015 - 08:16 AM

 


I looked into google protocol buffers as well, and the code-pre-processor/generation feels like an awful hack to me.

It may not suit your particular needs, but for most users, protocol buffer's code-generation is really its #1 strength.

 

Picture a fairly typical modern-day web service: you have a Java web server, a REST client written in JavaScript, a native client written in Objective-C on iOS, and maybe an acceptance test suite written in Python. Would you really want to implement (and test!) the same serialisation code in 4 different languages? That would be an unmaintainable nightmare.

 

And thus we have tools like Protobuf to let us write our specifications just once, and never again deal with this sort of compatibility problem.

 

I suppose code generation with external tools is OK for some folks; in my case I've never wanted to use a code-generation technique.

Protobuf afaik also does not support object references/cycles; without building your own system atop it; which is a large part of the compexity to begin with.   wire-formats like XML, JSON suffer the same issues; but, references and cycles are extremely common occurences in game state formats.

 

 

it was huge, and complicated; and also did not have important features such as; adding/removing serialized members; without having to write version conditionals.

Metaclass management is not exactly simple or good usage of memory resources. The reason version conditionals are used often is because the solution takes almost no extra code to do right and supports the vast majority of cases (variable addition and removal) without any extra effort.

In my own rather simple, template-based library, I just have to add a few arguments to a function call, like so:
arch( size, arch.version >= 4, 0 ); // variable to serialize, condition, default value 
Does not seem that hard. Besides, I use the same function for serialization and unserialization and it works across two different serializers (text and binary).

and the code-pre-processor/generation feels like an awful hack to me.

Not sure where you got that idea. Code generation has been around to solve various metaprogramming issues for a long time. Whoever makes you think it's a hack, better not take such "advice". Any method has its good sides and its bad sides and evaluating it by "feels" would be a big mistake. Try it, improve it, change it for something different. Exhaust all options to have a better idea of what works and what doesn't. It really is the only way.

As for your solution, what you're proposing is writing huge read/write functions that require lots of code, lots of declarations and lots of void pointer workarounds. Furthermore, it appears that only iostream is supported even though it would take just a two-function interface to read from and write to just about anything. Quite frankly, I don't see the point of using dynamic memory for what could easily reside in static memory as well.

 

First I'll address version blocks; in any /real/ complex game, especially where change is the norm; with version blocks you will accure 'entropy'; having to specify version blocks for new members and member drop-outs is a gross misuse of technical resources; and unescapably creates technical debt; that you will live with, until you decide to make a clean format break (breaking past user saves preceeding that point).

Concerning code generation; a large degree boils down to preference; I'll admit. If you're ok with preparing special markup and running external tools, when you essentially don't have to, that is obviously an option.

Concerning iostream, it is an obvious choice, as it supports both file level and in-memory (stringstream) for deep copying etc.

The issue with the 'two function' solution for arbitrary readers/writers is that for naive iostream usage, you end up having to tie it in.
You could say implementing your own format against iostream is a solution as well.




#5235184 Tiny Serialization Library

Posted by EDI on 16 June 2015 - 03:03 PM

Hi all,  was going to post this in 'Your Announcements', but after looking down the guidelines I felt it might be more applicable here.

So, I've written a few games over a few years (see http://edigames.com ); and it has irked me, to no end that I've been unable to find a very easy/approachable method to serializing (saving state) of my games.

When I originally was faced with the problem, some people recommended Boost::Serialization; but it was huge, and complicated; and also did not have important features such as; adding/removing serialized members; without having to write version conditionals.

I looked into Google protocol buffers as well, and the code-pre-processor/generation feels like an awful hack to me.

So after many years of this being a pet project; and trying out various method to achieve good, soft, binary serialization; I set out recently to code up a two-file library, get it on GitHub and make it open-source and free for commercial and non-commercial work.

https://github.com/edigames/object-model-serializer

And now, I need help from indies writing games that require serialization, so that I can hone the library to real-world needs; and of course I want to help solve the issues that people face when trying to create a save-game mechanism.

All feedback is welcome, thanks!




#5090121 questions about singletons

Posted by EDI on 29 August 2013 - 09:25 AM

and therefore don't really understand why people hate them.

 
People hate global variables for three reasons:

  • access to information from anywhere without formal declaration of collaboration means you can't adequately control or change how sections of code are connected.
  • global variables represent application-lifetime information, in order to adequately 'reset' your program, for testing or say a 'new game' you have to manually 'drive' these values to a known good state, instead of them being destroyed naturally as part of an object graph.
  • global variables are often 'autos' and the construction order of file-scope/static automatic variables is not sanely controllable

i use them is very specific ways only - ways which i'm hard pressed to find a better solution for

 

Look into dependecy injection.

 

guns don't kill people, people kill people.

 

Unless your gun and ammo was made by you, unsafe, and blows up at the shooting range.

 

i mean am i supposed to use a setter and getter for everything?

In short, yes; your public accessable interface should be well defined; reaching into an object for various internals is violating proper usage of a class.

But this is less of an issue than using globals.




#5089997 questions about singletons

Posted by EDI on 28 August 2013 - 10:31 PM

Lot's of folks here have answered the questions well but I thought I'd throw my hat into the ring as well:

Singleton as a "one and only one" instance enforcement

 

This is better handled with standard object construction / destruction; if there should only be one instance of an object in your program, instantiate only one.

 

If your code would break because more than one object has been instantiated that is a big problem that should be solved.

 

In theory properly designed code should not care about instances created in isolation, instances only become useful when associated with other instances or directly acted upon.

 

 

Singleton as a global point of access

 

Many people use singletons for the ability to access features from various points in their program; this is a huge design flaw.

 

By making a direct reference to say "TextureManager::getInstance()" you have failed to properly declare your collaborators from the accessing class.

 

Collaborators should be explicitly declared either via constructor parameters (for required objects for normal baseline functionality) or via setters for optional functionality.

 

This explicit declaration and requiring to pass instances to other instances, forms your object graph, the ability to construct and destroy your object graph without any residual state, is hugely important for testing, and avoiding flaky behavior.

 

"I can't go around passing instances into objects, that's too tedious and I don't know all the places I want to use my object"

 

First off, the excuse of not wanting to explicitly declare what objects can operate on other objects is laziness; and will lead to bugs, hard refactoring, "spaghetti" code smell, and will make it harder to see and understand good design choices from poor ones.

 

Many developers provide the scenario that, when creating an object from within another object, they may not have the instance they need to construct that object.

 

The problem with this scenario is deeper than the problem suggested however, if you have objects deep in your object graph creating other objects; you've already lost the battle.

 

You should take steps to have top-level code, such as a Factory, build and construct objects according to a design specification (such as loaded game data), these objects then work when assembled properly and have no concern about how they were joined together.

 

Consider the example of a Car object, within its constructor it creates an Engine, and four Wheel objects.

 

You would rightly assume that the Car constructor would need all the parameters that the Engine and Wheel objects require, putting a considerable number of confusing parameters into the Car constructor.

 

e.g: Car(color, horsePower, rpmRedLine, whiteWalls, treadPattern);

 

If instead you have a CarFactory object, take in such information, it can then create Car, Engine and Wheel objects in isolation, and join them together based on specification in CarFactory.

 

This keeps specification and implementation of Car, Engine and Wheel light; and allows for Substituting of subclasses if required; which would not be possible if Car's constructor were doing the 'new' ing.




#5086552 Revel Immortal

Posted by EDI on 16 August 2013 - 01:09 PM

The continued story of Morning's Wrath, once again you'll assume the role of Princess Morning in this action/rpg set in an ever expanding realm.

Click here to view the project


#4787012 How many people have bailed on Gamedev.net?

Posted by EDI on 17 March 2011 - 08:30 AM

I've pretty much bailed on Gamedev.Net

the theme changes over the last five or so years have steadily gone from bad to worse; this most recent version is eye-frying, information overload.

I also feel like I've lost touch with the community; like a lot of folks who were very active during 2000-2007 have moved on.


I'm holding on for a better black theme, better formatting of text; and much much less text-noise on all the pages.


PARTNERS