# Object Persistence for a MUD

**URL:** <https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164>\
**Category:** Ruby\
**Created:** [October 5, 2008, 3:48am UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164 "2008-10-05T03:48:06Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Brent\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b9bd4f/32.png) [@Brent\_D](https://www.ruby-forum.com/u/Brent_D)\
**Post date:** [October 5, 2008, 3:48am UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164/1 "2008-10-05T03:48:06Z")

</div>

Hi all,

For fun, I’m writing a MUD with Ruby. I thought I’d query the hive  
mind here and ask some opinions on what library I might use for object  
persistence – that is, storing objects like players and rooms  
somewhere.

I could do something really simple like store everything in YAML, I  
could try DRb, or I could go all out and use an ORM like DataMapper…  
DataMapper is the first route I took, but I soon realized that I’ll  
have to be really careful when using a lot of the ORM niceties while  
still ensuring that a database row only every represents one object in  
memory. i.e.:

# assuming Player has\_one :room …

player = Player.get(1) # get Player with ID=1  
player.room # the player’s current Room association

… player logs out, logs back in later …

player.room

Oh noes! The ORM fetches the same room from the DB, but creates a  
totally new object to represent it. Two players could be in the same  
room ID, but actually reference different objects, and thus couldn’t  
see or interact with one another. Bad.

This problem is hackable by carefully keeping a cache of loaded  
objects – but might end up negating the value of using an ORM like  
DataMapper. So, any suggestions out there of what I might do instead?

Thanks! 🙂

---

<div class="post-metadata">

**Author:** ![Brent\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b9bd4f/32.png) [@Brent\_D](https://www.ruby-forum.com/u/Brent_D)\
**Post date:** [October 6, 2008, 2:29am UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164/2 "2008-10-06T02:29:09Z")

</div>

Brent D. wrote:

> Hi all,
> 
> For fun, I’m writing a MUD with Ruby.

I’ve been doing something similar with a multi-user space game. I  
haven’t arrived at any firm conclusions but the first thing that I have  
observed is the split between static/stateless data and dynamic/stateful  
data.

There is a tremendous amount of static data (maps, buildings, locational  
characteristics, etc) so it seems to make some sense to separate this  
from the dynamic data/stateful (current health, ammo, factional  
affiliations and status, etc).

At this point, I’m generating the static part of the universe and  
Marshaling it to file so it can be re-used. Some would argue with  
Marshal as a choice but I’m using DRb between clients and servers and  
Marshal is the default object protocol within DRb so in for a penny, in  
for a pound as they say…

On the plus side, it’s considerably faster than YAML or a database.

On the minus side but isn’t readable or mindful changes in object  
version. If you’ve modified the object definition between store and  
load, you need to rebuild. This is the reason I’ve relegated it to  
managing static data only.

The dynamic/stateful part looks like it’s going to require a database of  
some sort largely to provide a relatively stable/secure repository.

SQLite looks like my first choice at this point as it’s supposed to be  
fast, small and zero maintenance. We’ll see…

Best of luck

djief

---

<div class="post-metadata">

**Author:** ![Brent\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b9bd4f/32.png) [@Brent\_D](https://www.ruby-forum.com/u/Brent_D)\
**Post date:** [October 6, 2008, 1:49am UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164/3 "2008-10-06T01:49:02Z")

</div>

On Sat, Oct 4, 2008 at 8:46 PM, Brent D.  
[removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> have to be really careful when using a lot of the ORM niceties while  
> player.room
> 
> Oh noes! The ORM fetches the same room from the DB, but creates a  
> totally new object to represent it. Two players could be in the same  
> room ID, but actually reference different objects, and thus couldn’t  
> see or interact with one another. Bad.
> 
> This problem is hackable by carefully keeping a cache of loaded  
> objects – but might end up negating the value of using an ORM like  
> DataMapper. So, any suggestions out there of what I might do instead?

There are probably a hundred different ways to approach this. I’ve  
never programmed a MUD, but after playing around with the Sequel gem  
and Postgresql, I had a simple map with locations, players, and  
objects. I updated the DB on the fly, but I’m sure there are other  
paradigms.

Very, very simple example…

sql…

create database mud;

create table map (  
x int not null,  
y int not null,  
synopsis varchar not null,  
description varchar  
primary key (x, y)  
);

create table people (  
name varchar not null primary key,  
xcurrent int not null,  
ycurrent int not null,  
foreign key (x, y) references map (x, y)  
);

insert into map values (0, 0, ‘start’);  
insert into map values (1, 0, ‘hallway’);  
insert into people values (‘Loki’, 1, 0);  
insert into people values (‘Thor’, 0, 0);  
insert into people values (‘Freya’, 1, 0);

…ruby…

require ‘rubygems’  
require ‘sequel’  
Area = Struct.new(:description, :synopsis, :x, :y)  
DB = Sequel.connect(“postgres://user\_name:password@localhost:5432/mud”)

#print everyone in the hallway…

DB[:map].join(:people, :xcurrent =\> :x, :ycurrent =\> :y).where (:x =\>  
1, :y =\> 0).all.each {|row| p row[:name]}

#=\> Loki  
#=\> Freya

Todd

---

<div class="post-metadata">

**Author:** ![Brent\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b9bd4f/32.png) [@Brent\_D](https://www.ruby-forum.com/u/Brent_D)\
**Post date:** [October 6, 2008, 4:32am UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164/4 "2008-10-06T04:32:21Z")

</div>

Brent D. wrote:

> have to be really careful when using a lot of the ORM niceties while  
> player.room  
> Thanks! 🙂  
> I am working on a similar project. I started off using PStore but  
> switched to using Marshal and gdbm, which is quite a bit faster. But, in  
> either case, objects are not read and written to/from disk all the time.  
> Most of the time they are in memory and only occasionally saved (a  
> player would be saved when logging out, for example). To avoid the  
> situation you mentioned, just keep track of which objects are in memory  
> (give each a unique ID) and then only load them if they are not already  
> loaded.  
> If keeping everything in memory doesn’t sound like a good plan, you can  
> also dynamically load/unload objects as needed.

I guess it just depends on how you want to approach it, though. I don’t  
have a strong need for any kind of fancy database functions, so storing  
them with gdbm works fine for me.

-Justin

---

<div class="post-metadata">

**Author:** ![Brent\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b9bd4f/32.png) [@Brent\_D](https://www.ruby-forum.com/u/Brent_D)\
**Post date:** [October 6, 2008, 8:24pm UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164/5 "2008-10-06T20:24:11Z")

</div>

Jeff M. wrote:

> At this point, I’m generating the static part of the universe and  
> Marshaling it to file so it can be re-used. Some would argue with  
> Marshal as a choice but I’m using DRb between clients and servers and  
> Marshal is the default object protocol within DRb so in for a penny, in  
> for a pound as they say…
> 
> On the plus side, it’s considerably faster than YAML or a database.
> 
> On the minus side but isn’t readable or mindful changes in object  
> version. If you’ve modified the object definition between store and  
> load, you need to rebuild. This is the reason I’ve relegated it to  
> managing static data only.
> 
> The dynamic/stateful part looks like it’s going to require a database of  
> some sort largely to provide a relatively stable/secure repository.

You might want to have a look at Madeleine, which could be a suitable  
half-way house: it uses a Marshal (or YAML) dump as a snapshot of your  
universe, plus incremental transactions for updates.

At startup it reads in the last snapshot plus the intervening  
transactions. This means you only have to write out a full snapshot  
occasionally. The code is also small and simple enough to be easily  
understood.

---

<div class="post-metadata">

**Author:** ![Brent\_D](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/b9bd4f/32.png) [@Brent\_D](https://www.ruby-forum.com/u/Brent_D)\
**Post date:** [October 8, 2008, 12:00am UTC](https://www.ruby-forum.com/t/object-persistence-for-a-mud/150164/6 "2008-10-08T00:00:56Z")

</div>

Some great responses here! Thanks everyone.

Madeleine is definitely something I’m going to give a try. I’d heard  
of it before, but no one seems to talk much about it… so I was kind  
of hoping someone would mention it here.

I want to avoid hitting a database as much as possible, so it seems  
like a decent solution. RAM is cheap copious enough these days that I  
shouldn’t have any problem keeping the entire game in memory (we’ll  
see). It’s possible that I’ll end up with some kind of hybrid solution  
like Jeff mentioned.

I’ll try to report back when I get a little further along for the  
benefit of others that may have similar questions down the line 🙂

Thanks again,

Brent
