[DGD] Saving to disk
Blain
blain20 at gmail.com
Sat Apr 20 06:24:03 CEST 2013
All good thoughts, guys. I did intend to make a player's body unattackle
once linkdeath was noted (if I don't decide to just destruct immediately).
Unfortunately, any delays in detecting linkdeath could cause the player to
die, but that's the same with any game. On Anguish, players "statue" at
linkdeath and at 5 minutes idle. At this point they become unattackle and
most other actions (especially harmful ones) are prevented as well. For
me, though, doing something like statuing or just making their eyes go dim
to indicate their "driver" is not there is really a thematic one. My lib
is intended to be generic and then extended for each individual thematic
game on top of it. So I think that the points brought up about dying in
combat on linkdeath, etc. can be handled in various ways depending on the
theme of the game. But my original point was deciding if to move the body
(upon quitting and/or linkdeath) to a meat locker forever or saving to disk
and destructing. Many who like persistence posted before (in the archives)
that persistence gives a free license to just let the body hang around
waiting for the player. I expressed my dislike for the idea because
swapfiles can become corrupted. Of course, so can a savefile! But the
savefile of a player who hasn't logged in for a long time has less a change
to become corrupted if it's a stand-alone file as opposed to being mingled
with currently active data in the swapfile. I think this was and is my
primary point regarding this design decision.
On the topic of the "/obj/thing", I'm still leaning toward using
inheritance trees for the various object classes. It just seems to be less
confusing if each inheritor can build on its inheritee by setting up some
general settings. But also, each inheritor can introduce its own set of
modules and redirect some sets and queries to these modules before the
inheritees can do the same to their own sets of modules. These modules
would not be inherited, but off to the side in an array. Some examples of
modules might be a sword which has a special process when it hits a
monster, or even simple modules like a container being openable and
closeable. Although the latter could be coded inside the container object
with this inheritance scheme. Modules could still get a swipe at modifying
the behavior of the opening/closing sequence, though. I think the
/obj/thing idea really just pushes all the customization into the memory
instead of having startup files do the basic setup of a given object class.
I think this is where the confusion can come in because builders and
coders have to deal with memory-based object classes instead of being able
to see the code on file. Maybe it's just personal preference, though. I'm
really trying to move away from builders having to write startup files,
though, and I've taken great strides to do that. Startup files make things
too rigid. Savefiles, though, allow an object to change over time. But
this puts the onus on the object class libraries to define the behavior of
a given object, and that's why I keep pulling away from an all-encompassing
/obj/thing. I just see way too much class-specific behavior code going
into my objects that shouldn't be in -every- object class. My most basic
object class at this point is an environment or zone. This code doesn't
need any behavior code on opening and closing like a door or container
does. Obviously the code to interact with objects in this way are going to
be in the body (yet another class which has unique behavior code that other
objects don't need), but some things will need to be defined in the class
objects to decide how to react and what messages to give. In my design
notes which do pertain to using an /obj/thing, though, I was intending to
set up basic classes in memory which the builders would pull from, complete
with generic messages for each action that can be performed on them. I
guess I just couldn't envision how this would actually look like when I sat
down to code it, so I kept moving back to inheritance trees. At this very
moment, though, I only have data settings for all objects' physics and
descriptions, etc., so I haven't wasted a bunch of time on coding in either
direction just yet. I'm still trying to figure out which route is best.
You guys have been a help, and so has everyone in the archives. I'm up to
2005 now, I think. ;)
Wish me luck on making the best damn mudlib ever (second only to Felix's!).
;)
On Tue, Apr 16, 2013 at 10:01 AM, Blain <blain20 at gmail.com> wrote:
> 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
>
More information about the DGD
mailing list