[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