[DGD] Saving to disk

Raymond Jennings shentino at gmail.com
Tue Apr 16 19:37:18 CEST 2013


On Tue, Apr 16, 2013 at 8:51 AM, Noah Gibbs <noah_gibbs at yahoo.com> wrote:

> The all-in-one /obj/thing isn't primarily to allow mutation of one object
> type into another.  It's primarily to avoid the repetitive and error-prone
> coding of many nearly-the-same sub-paths in your code for various types of
> objects that don't quite share properties, but almost do.  By saying "there
> is one global object type with properties and I will just code the
> properties", you avoid that.  Sufficiently careful coding of your various
> types, for instance by flagging them with properties, will also allow you
> to avoid that...  And then you basically have one object type, but with
> properties.
>
> The various player-body stuff isn't actually about save files versus
> persistent.  You can implement any of the player-body features you mention
> with either design.
>
> Your various arguments about swap files also apply to your save files.
>  That is, none of your nominal reasons for choosing one over the other
> actually favor one over the other significantly.  There's nothing wrong
> with save files for objects, of course.  The basic tradeoffs are:
>
> * swapfiles are faster because the save code is done custom in C, and you
> don't need to separately marshal the objects.
> * swapfiles, managed well, are already 50%+ pre-saved at any given time
> because DGD swaps out idle objects.
> * swapfiles can preserved leaked objects, while good save files never
> should.
> * swapfiles are less human-friendly to edit.
> * swapfiles require upgrading objects in place rather than allowing
> save/restore-style upgrades.
>

Actually noah with DGD you can do both.  Just destruct the old blueprint,
compile the new one, and you suddenly have a bunch of legacy objects that
you can save and restore the old fashioned way.

Come to think of it though I don't think swapfiles have anything to do with
upgrading in place.


> * swapfiles always automatically fully preserve object relationships,
> while save files can have save/restore errors.
> * swapfiles require no marshalling code, while save files require writing
> it.
>
> That's not a slam-dunk either way.  A hybrid design gets a hybrid of these
> tradeoffs -- you have to write some save/restore code and it can have some
> (fewer) errors.  Savefile objects are fairly unlikely to leak, while
> non-savefile objects can.  Savefile objects are editable and upgradable,
> while your non-savefile objects aren't.  And so on.
>
> You're right about areas -- being able to write, import and export areas
> requires some kind of disk format.
>
>
> ________________________________
>  From: Blain <blain20 at gmail.com>
> To: All about DGD and Hydra <dgd at dworkin.nl>
> Sent: Tuesday, April 16, 2013 8:01 AM
> Subject: [DGD] Saving to disk
>
>
> I'd like to put out there one of my mudlib design ideas regarding saving to
> disk vs. letting the swapfile handle it alone.  I've read numerous
> discussions in the archives, but I think that a lot of the points made for
> letting the swapfile handle saving objects only weren't quite accurate in
> my humble opinion.  I also discuss other persistence-related topics after.
>
> For starters, users should not be ever-present in the game.  In a standard
> LPMUD/MudOS game, a user is represented by a .o file.  This makes sense.
> This also means that the user connection can and should be destructed on
> logout.  The body, if separate can also be saved to a .o file and
> destructed.  Other players and NPC's don't usually need to interact with an
> offline player in most MUD designs.  If a designer really wanted to, they
> could redirect private messages (usually called 'tells') to an internal
> mail system or a cache waiting for the player to return.  Also, I don't
> think an environment object should be trying to load a player's body when
> that player isn't on.  Of course, there are ways which this can handled
> appropriately in most any persistence scheme.
>
> Persistence seems to be a great way to keep the Game going without skipping
> a beat, but players can choose not to be logged in, and so they should not
> quite be included in the persistence of the Game.  Someone mentioned
> activating an AI program to drive the player's body around while the user
> isn't logged in, but this can really only cause confusion.  I do have plans
> to move a player's body to a nearby inn (or their personal home if it's
> nearby).  This is about as far as manipulating a player's body I am willing
> to go, lest I piss off the masses.
>
> So, to implement this in a globally standard way (that is, other objects
> may wish to be excluded from being handled by the environment) I devised
> the concept of an object flagging itself as a 'save point'.  While I intend
> to use persistence in my lib design, I am also allowing for saving
> individual state to disk for certain objects using this flag.  When an
> object is asked to save(), it will usually return a mapping of its internal
> variable data.  If an object is flagged as a save point, it will instead
> save itself to its own personal save file and return nil to the calling
> environment object.  The object will also recursively save its inventory
> and compile the data mappings received into a string variable, and it will
> reconstruct its inventory using that string upon reconstruction.  The
> environment zones are also save points and will save any inventory objects
> to disk, except for save-point objects, such as players.  The only example
> of a non-player save-point I have so far is a travelling NPC who will
> control where it is at a given point in time.  It will do this using 'load
> point' objects which it drops in the various environment zones that its
> travels take it through.  This way, when a zone is loaded from disk, the
> 'load point' is loaded and it notifies the NPC in case the NPC should be in
> that particular zone at that moment in time.  This is for NPC's who operate
> on a cicular schedule, not those who wander aimlessly.
>
> The main reason I can't see going swapfile-only as a good thing is because
> of a couple main issues:
> - The loss of a swapfile due to corruption means the loss of everything the
> builders ever worked on, or
> - Booting from a backup will cause the loss of any recent changes, which
> could be catastrophic if any real complicated work has been done since the
> backup was made.
> - Being able to edit a save file can sometimes be the last resort if
> something just won't load with it.  Without save files, one would have to
> hand-edit the swapfile.
>
> I think that a hybrid mudlib is really the better way to go.  Persistence
> for normal operation, but saving to disk for dealing with problems.
> Persistence for most NPC's and world events, but saving to disk for
> players, who control their own existence in the game world.
>
> Saving players to disk (including their inventories) means that they need
> to be upgraded on login.  I intend to code an upgrade service to do exactly
> this.  All player save files will be loadable by data LWO's.  The version
> of the save file can be detected and the appropriate LWO can then load and
> update the data to migrate it from one version to the next.  After all
> upgrades have been performed, the body object can then load the
> newly-updated save file.  Also, while upgrading save files from version to
> version, certain processes can inform the player of any changes they need
> to know about, such as:
>
> As of <patch date>, the Sword of DOOM is no longer available.
>
> Then it removes the sword from the player's inventory.
>
> I think that this system design is probably a lot similar to how a lot of
> MMO's may run, although I know WoW just has item number pointers in your
> inventory list, and items are updated separately, though WoW does keep
> arbitrary data for your version of an item, such as enchantments and stat
> modifications, etc.  I would likely do the same.
>
> Another problem I have with some of the ideas brought up in these
> persistence discussions is the all-in-one /obj/thing.  I can't see a reason
> why any object should ever be mutated into another object as far as the
> mudlib is concerned.  I agree that most objects should be wieldable, even
> if they suck as a weapon, but this should be done from the player body just
> using the object's physics as an indicator of being wieldable and its
> effectiveness as a weapon.  If an object truly is mutated into another by a
> magic spell, one can merely replace the object with another.  If reversal
> is wanted, repeat the process, or store the original in some kind of magic
> effect object held inside the new object.  Then swap and destruct the
> mutated one.  I intend to have inheritance chains because some behavior
> code will need to accompany different types of objects.  I tried mapping
> out some sort of module tracking array, but it seemed inefficient.
> Inheritance allows for easier masking of a parent function, but if modules
> are held as siblings, it's difficult to decide which module's decision wins
> out over that of the other modules.  I'm sure it can be done just fine
> either way, but modular objects felt kludgy, and I'm trying to use a design
> which uses minimal objects.  A shared library is often better than a cloned
> module.  I will use modules to define the behavior of a given sword, but
> all swords will load from a standard sword inheritable which defines
> default behavior that non-swords need not worry with.  Of course, the sword
> lib will inherit the weapon lib, so there probably doesn't need to be much
> different in the sword lib itself.
>
> All in all, my design requires that a full, true shutdown save all
> save-point objects to disk with save strings of their non-save-point
> inventory objects.  When there are no problems to deal with, the MUD can
> use the swap to do mini-boots once a day or so for memory reasons (if I
> understand all this correctly).  Clearing the memory of all game objects
> also helps with finding object leaks, I'd think.  I also like the idea of
> the MUD booting only the Kernel and System and not loading the Game until a
> player logs in.  Using only the swap for a continued state prevents that.
> Choosing to do a cold boot with no state dump could also achieve this, but
> then you'd be right back where you started if you shut down and booted from
> a state dump.  I'll have to play with this to be sure I'm thinking
> correctly.
>
> Another aspect of my design which requires save files is building areas and
> installing them.  If a user builds an area, they will need to save
> everything to disk so that the save files can be copied over to the Game
> directory structure and be loaded from there.  I can't see how this can be
> done if the objects only ever exist in memory and swap, aside from loading
> objects and pulling the data over for each one, which could introduce
> problems of its own.  I think I'll have to do this before I can truly see
> what problems can arise, though.
>
> Using LPC startup files can also be useful in some cases where an object
> needs very exact behavior.  The builder code I'm designing will also allow
> for this.  So, in summary for building, builders will deal with .c and .o
> files for some of their area objects, but usually only .o files.  Quest
> handler services and the like will likely need to be coded in LPC also.
> I'll see about making some of this standardized and thus be loadable from
> the main lib files, though.
>
> Thoughts?
>
> --Blain
> ____________________________________________
> https://mail.dworkin.nl/mailman/listinfo/dgd
> ____________________________________________
> https://mail.dworkin.nl/mailman/listinfo/dgd
>



More information about the DGD mailing list