Stand Alone Erlang for Windows. yet again

classic Classic list List threaded Threaded
38 messages Options
12
Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Chris Pressey
Chris Pressey wrote:
> Well, it seems as if you have two processes here (one for the logic, one
> for the object-state), while I don't see why you need more than one
> process (which can handle both logic and object-state.)

Wait, I think I get it now.

In Erlang 'tis generally better to have two processes with infinite
timeouts (interrupt model) than one process with finite timeouts
(polling model.)

:-)

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
In reply to this post by Chris Pressey
On Fri, Mar 16, 2001 at 01:35:47PM -0600, Chris Pressey wrote:
> I totally agree.  However, I can't think of a way to stop people from
> writing 'bot code like:
>
>   apply(unix, cmd, ["rm -rf *"]).
>
> And that would be bad!  I suppose taking out the unix module entirely
> might help... I'm not familiar enough with Erlang to know how many other
> holes are possible, though.

I'm not sure if someone has written the equivalent of Python's
"bastion" or Java's sandbox, essentially a restricted environment in
which only access to listed modules and builtins is allowed.  That's
really what this project would need to allow scripting in Erlang
inside the server.

> I have no idea if my Erlang project will turn out anything like that,
> though.  Currently my temptation is to have a more hierarchical,
> abstract world, mainly because it would simplify it greatly if you could
> just see everything in the current 'room' instead of calculating
> line-of-sight to determine the set of visible objects.

Ie. the "MUD" concept in which the universe is broken into groups of
"cells" or rooms, and all things within a given cell can freely
interact.  Its certainly the simplest means of implimenting a
universe, and the easiest to explain to an outside observer.

> My feelings - though I'm a mnesia newbie - is that one big table (in
> RAM) is going to be the fastest solution - because any partitioning
> would mean more resource-accesses per data-access.  I don't see a lot of
> reason to add filesystem directories to the mix, as mnesia already has
> many of the properties that files have but database fields traditionally
> do not (variable length, complex structures etc.)

The main reason to add a filesystem hierarchy to the system is to make
it easy to modify things from INSIDE the system, on the fly.  Its an
intuitive, understandable thing to say "OK, I need to edit
/server/things/player/commands.erl to add the ability to hug random
people," and then commence said operations, than to say "OK, I need to
grab the "commands" field of the "player" record ... now, where is
that related to everything else?"  Its purely a human-access concern.
One could, theoretically, lay a false filesystem hierarchy over the
mnesia database itself ... but since filesystems already exist, it
seems redundant.  As a pleasant addition, the mnesia database ends up
holding ONLY the persistant data, not the sourcecode.

> That is pretty much the case.  Imagine functions player_loop() and
> npc_loop().  They act very similarly except that player_loop() gets its
> orders from a socket, and npc_loop() calculates its orders using AI.
> Sure, they could be the same function, since they share some
> functionality, but I think it would be a tad more efficient if they were
> seperate functions (so that NPC's aren't continually checking for their
> non-existant sockets.)

Its all the more efficient to have the Thing/object itself only have a
reference to its "master," which could, in turn, be a Pid of one of
the above.  Thus, you genericise the Thing and allow it to be driven
by either mode, improving your code reusability.

> There are also some 'higher-order sense' that turn out to be useful.
> For example, being able to see someone else move.  {see_move, Sender,
> NewPosition} or something.

Sure; defining the set of messages your Things can respond to is one
of the basics of game design.  Allowing that kind of extensibility on
a Thing by Thing basis is one of the advantages of being able to drive
a generic core.  :)

> I dunno.  In my scheme, 'live' objects can be suggested to do actions,
> but what they actually do is up to them.  You could suggest to your dog
> that it follow you, and if it is loyal it will obey.  But if it catches
> rabies, it's AI might change and it might not be so complicit!

Not "suggested" as an in-game issue, but controlled by another
process.  Like a Teleport Device can force a move on a Thing, if it
has sufficient priviliges, or, the way an Administrator on a MU* can
@force a Thing to execute actions as if done by the Thing itself.
"Suggesting" is an in-game issue and, as such, is constrined by the AI
of the game.  I'm talking about external forces.

> Well, it seems as if you have two processes here (one for the logic, one
> for the object-state), while I don't see why you need more than one
> process (which can handle both logic and object-state.)

Because logic can change.  The Thing with state persists.  For
example, modelling the Dog that can potentially become RabidDog
becomes easy once you separate logic and state.  As a Dog, it uses a
passive AI instance (PetDog) and its stats are all bound on the
DogThing.  When it goes rabid, Dog is sent a {goRabid} message, it
changes its stats appropriately, and switches its control from PetDog
to RabidDog, wjich then drives its behaviours.  Now, let's say that
the Dog is needed to do some custom things that its best if a person
drives; we reconnect the behaviour Pid from RabidDog to
PlayerConnection where a person is logged in.  Voila, it retains its
rabid stats but takes orders from a person.  When done, swap the
PlayerConnection for RabidDog until RD decides its time is up, then it
says to {returnToNormal} or just tells the Dog to {die}.

Separating state and behaviour lets you do all kinds of fun and
perverse things.  :)

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Vlad Dumitrescu-3
In reply to this post by Alexander Williams
> So, we end up needing another unique ID system.  (Gensym, come home,
> all is forgiven!)  

wouldn't references work well here? with today's system dynamic atoms ? la Gensym are not GCed...

/Vlad


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
On Sat, Mar 17, 2001 at 10:06:05AM +0100, Vlad Dumitrescu wrote:
> wouldn't references work well here? with today's system dynamic atoms ? la Gensym are not GCed...

They might, if we were talking about Erlang-level constructs, but
we're not.  In reality, we're talking about the mapping-key between
Game Level objects and the Erlang Processes that contain the actual
code being executed.  Pids aren't stable entities, they'll end up
changing between one run of the server and the next.  Object
References really should be unique across multiple nodes, if we want
to allow for interlinked servers in the future (or even one MU*
distributed over multiple nodes).

Now, the hard part of this bit will be managing the linkage of Pid to
Persistant ID to the state information restored from the database when
bringing it back from the dead ... that'll be the challenge.

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Ulf Wiger-4
In reply to this post by Vlad Dumitrescu-3
On Sat, 17 Mar 2001, Vlad Dumitrescu wrote:

>> So, we end up needing another unique ID system.  (Gensym, come home,
>> all is forgiven!)  
>
>wouldn't references work well here? with today's system dynamic
>atoms ? la Gensym are not GCed...

References should work well as long as they don't have to be
persistent. The same goes for pids. You can't dump a pid to disk
and expect to reuse it later. As for references, they are not really
unique if you keep them long enough (or has that changed in R7?)

I tend to prefer to generate a globally unique ID whenever I need a
reference. The scheme I prefer is

  ID = {node(), erlang:now()}.

It's fast, and under most realistic circumstances (even persistently)
unique with very high probability.


/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Ulf Wiger-4
On Sat, 17 Mar 2001, Ulf Wiger wrote:

>I tend to prefer to generate a globally unique ID whenever I need a
>reference. The scheme I prefer is
>
>  ID = {node(), erlang:now()}.
>
>It's fast, and under most realistic circumstances (even persistently)
>unique with very high probability.

It's actually also quite easy to produce a nice external ID this way:

(mud)2> F=fun() -> N=node(),{MS,S,US} = erlang:now(),
atom_to_list(N) ++ "." ++ integer_to_list(MS) ++ "." ++
integer_to_list(S) ++ "." ++ integer_to_list(US) end.
#Fun<erl_eval.20.95849314>
(mud)3> F().
"mud"
(mud)4> F().
"mud"
(mud)5>

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
On Sat, Mar 17, 2001 at 12:04:28PM +0100, Ulf Wiger wrote:
> (mud)3> F().
> "mud"
> (mud)4> F().
> "mud"
> (mud)5>

I rather like this result, actually.  A bit long and cumbersome to
type, but that's all the more reason to use the POO-esque
dereferencing of objects based on their holding environment for human
access.

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Chris Pressey
In reply to this post by Alexander Williams
Alexander Williams wrote:
> On Fri, Mar 16, 2001 at 03:30:32PM +0100, Ulf Wiger wrote:
> > This can be done, as long as one doesn't make any assumptions about
> > Pid (it will change), and there's a stable state in which to do this.
> So, we end up needing another unique ID system.  (Gensym, come home,
> all is forgiven!)  I'd really like to shy away from the
> MU*-traditional form of just increasing integers, but ... it is simple
> and effective, I suppose.

My prototype currently uses just that, courtesy of
mnesia:dirty_update_counter.  References would also be sufficient, I
would think, considering they are IIRC unique into the billions.

Alexander Williams wrote:
> > I have no idea if my Erlang project will turn out anything like that,
> > though.  Currently my temptation is to have a more hierarchical,
> > abstract world, mainly because it would simplify it greatly if you could
> > just see everything in the current 'room' instead of calculating
> > line-of-sight to determine the set of visible objects.
> Ie. the "MUD" concept in which the universe is broken into groups of
> "cells" or rooms, and all things within a given cell can freely
> interact.  Its certainly the simplest means of implimenting a
> universe, and the easiest to explain to an outside observer.

"Because it is there" is also a reason to go around the mountain  :-)  I
got LoS working quite well last night, so I'm going to keep the
interface 'roguelike' and resist the temptation to resort to the simpler
hierarchical structure of a classical MU*.

That does mean I have to handle far more objects, though, as a single
large 'room' could be a hundred seperate wall/floor/ceiling blocks!
There is correspondingly less emphasis on textual descriptions, though.

> The main reason to add a filesystem hierarchy to the system is to make
> it easy to modify things from INSIDE the system, on the fly.

But I do not understand how working in the filesystem is easier than
working in mnesia tables.  The main reason I see to go with the
filesystem is performance under the current mnesia.  If that were not a
problem, using mnesia only would be simpler (& maybe faster.)  Using the
filesystem is more complex for several reasons, e.g. not all filesystems
are created equal.

> One could, theoretically, lay a false filesystem hierarchy over the
> mnesia database itself ...

Well, no.  The game world is hierarchical, the database records are
hierarchical.  There is just a hierarchy, not a "false filesystem
hierarchy": that step is just outright skipped.  I think
mnesia+filesystem is a redundant combination too, I just think the
redundant part is the filesystem.

That doesn't rule out "uniform resource locators" which can look like
"item/weapon/sword/katana/magic.erl" - though granted Erlang will
probably not parse this quite as quickly as a filesystem would.  But
once you've referred to it once, you can use it's unique key to refer to
it quickly again.

Then again it's fairly clear we've got different games in mind.  I
wasn't at all planning to build or help build "the" Erlang MMUD... I
already have a game, I'm just trying to get it out of Perl and into
Erlang and experiment with making it multiplayer.  If I can provide
help, it'll probably be in the form of letting people learn from the
mistakes I make in my prototype anyway :-)

> > There are also some 'higher-order sense' that turn out to be useful.
> > For example, being able to see someone else move.  {see_move, Sender,
> > NewPosition} or something.
> Sure; defining the set of messages your Things can respond to is one
> of the basics of game design.  Allowing that kind of extensibility on
> a Thing by Thing basis is one of the advantages of being able to drive
> a generic core.  :)

Yes.  But there's always a tradeoff between generality and performance.
If you're saying I should do an inheritance-tree-traversal every time a
message comes in, to find out what I should do, I don't agree.  That is
the most flexible system (and it is easy to write) but it is also one of
the least efficient.  In the interests of speed, all my 'instances' are
merely copies of older 'exemplar' objects, with some things changed; the
instance practically never 'defers' or 'delegates' to the exemplar.

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
On Sat, Mar 17, 2001 at 03:10:48PM -0600, Chris Pressey wrote:
> My prototype currently uses just that, courtesy of
> mnesia:dirty_update_counter.  References would also be sufficient, I
> would think, considering they are IIRC unique into the billions.

Except, as I think someone else mentioned, the References are only
ephermal and not persistant across database loads.  For a Roguelike,
that's fine, since about the only truly persistant information is
stuff about the character and his equipment, all else can be regenn'd
at load time.  For a MU* universe, that would hurt.  A lot.

> "Because it is there" is also a reason to go around the mountain  :-)  I
> got LoS working quite well last night, so I'm going to keep the
> interface 'roguelike' and resist the temptation to resort to the simpler
> hierarchical structure of a classical MU*.

Cool.  Though ... a Roguelike MU* might be intrresting.  I think you'd
need to impliment LoH (Line of Hearing) to really handle folks talking
to one another, and you'd need a specialized client.  Hmmmmm, LoH
could probably be implimented as a sort of flooding algorithm.  Set
the player's site to an Int value, set the neighboring ones to Int-1,
recurse until you can't spread anymore.  Any square with a val > 0 is
in the LoH.  Might be slow, I guess.  Only have to do it once for
every move, though ... as long as you stand still, it doesn't change.

> That does mean I have to handle far more objects, though, as a single
> large 'room' could be a hundred seperate wall/floor/ceiling blocks!
> There is correspondingly less emphasis on textual descriptions,
> though.

I can see that; you don't have to describe a room if you can see it.
On the other hand, you've got more little fiddly bits to manage, along
with a far stronger emphasis on autonomous drone beasties, which'll
just be huge fun.  (If I were implimenting them, I'd probably just
impliment a suite of "sensors" and then have the AI /only/ key off
that knowledge.  You can be a lot more emergent-begaviour-esque that
way.)

> But I do not understand how working in the filesystem is easier than
> working in mnesia tables.  The main reason I see to go with the
> filesystem is performance under the current mnesia.  If that were not a
> problem, using mnesia only would be simpler (& maybe faster.)  Using the
> filesystem is more complex for several reasons, e.g. not all filesystems
> are created equal.

Well, because its easier to communicate to a human what
"/server/player/soul.erl" actually /is/ than to try and find it in a
swarm of mnesia tables which may not be necessarily nested.  Its
purely a user interface issue, really, though there IS a goodly
measure of "how can I make this easy for people to update remotely"
too.  Its very easy for folks to edit code locally with Their
Favourite Editor(tm) then use ftp to drop it into the right directory.

> That doesn't rule out "uniform resource locators" which can look like
> "item/weapon/sword/katana/magic.erl" - though granted Erlang will
> probably not parse this quite as quickly as a filesystem would.  But
> once you've referred to it once, you can use it's unique key to refer to
> it quickly again.

Probably wouldn't parse it as quickly, no, but it could parse it
pretty easily.  I wouldn't use a unique key to access that particular
/file/ again, in my mind it represents just straightforward, inert
sourcecode.  Actual live Things would be running instances of said
code and, as such, would be tagged with Unique IDs (maybe of the kind
Ulffe laid out in the other message), and would need them, because
each would be unique.

> Then again it's fairly clear we've got different games in mind.  I
> wasn't at all planning to build or help build "the" Erlang MMUD... I
> already have a game, I'm just trying to get it out of Perl and into
> Erlang and experiment with making it multiplayer.  If I can provide
> help, it'll probably be in the form of letting people learn from the
> mistakes I make in my prototype anyway :-)

[grin]  Letting others learn from your mistakes is probably the best
help anyone can provide.  In a sense, you have a somewhat easier time
of making it multiplayer than others.  Just set the cookie on your
node to the same thing every time, and you can transparently tag
another node with a ping, add it to your known nodes, then access it
as if it were right next door.

> Yes.  But there's always a tradeoff between generality and performance.
> If you're saying I should do an inheritance-tree-traversal every time a
> message comes in, to find out what I should do, I don't agree.  That is
> the most flexible system (and it is easy to write) but it is also one of
> the least efficient.  In the interests of speed, all my 'instances' are
> merely copies of older 'exemplar' objects, with some things changed; the
> instance practically never 'defers' or 'delegates' to the exemplar.

Right, in your case, instances probably /won't/ be any deeper than a
single level, perhaps two, at any given time.  In my case ... I very
well have a tree that looks like this:

  Weapon -> Sword -> \
                      - Magic Sword -> Excalibur -> Excalibur (jnstance)
     Magic Weapon -> /

The actual Excalibur game-object/Thing might be inheriting 3-deep and
possibly with a mix-in (with Magic_Weapon.erl defining an override for
the {attack} message or somesuch).  Of course, all this inheritance
probably takes place at the Erlang module level and not with "real"
inheritance, with Magic_Sword.erl doing an -import of Sword.erl and
Magic_Weapon.erl ...

On the other hand, that brings me to an actual Erlang issue I haven't
quite figured out yet.  One can't specifically import from a specific
file in a specific place in the file hierarchy.  It'd be nice to have
some way to define a "package" as the top of some file directory than
refer to it with an import like:

  1> top.dir.dir2.dir3:function(args) ...

Unfortunately ... I don't think I can and that's a pretty hefty syntax
hack.

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Chris Pressey
Alexander Williams wrote:
> On Sat, Mar 17, 2001 at 03:10:48PM -0600, Chris Pressey wrote:
> > References would also be sufficient, I
> > would think, considering they are IIRC unique into the billions.
> Except, as I think someone else mentioned, the References are only
> ephermal and not persistant across database loads.

True.  Drat!  Only unique within the group of nodes in the current
'session'.  If you shut everything down and restart, that restarts the
reference counter too.  Ulf's external-id function would probably be
better in a scenario with both distribution and persistence.

> For a Roguelike,
> that's fine, since about the only truly persistant information is
> stuff about the character and his equipment, all else can be regenn'd
> at load time.

Most of it, yes.  In my model, state for each object - if any - is
stored in its database record.  Every so often, the process uses that
state information to decide what to do, and updates the state in the
record if needed.  And many creatures don't have very complex lives, so
they need little or no stored state.  If the state information
disappears, the creature will eventually find something else interesting
to do, so there's not much to be lost either.

> For a MU* universe, that would hurt.  A lot.

I have to admit I haven't programmed in an actual MU* for years.  I was
heavily into one called MicroMUSE but that was a long time ago, seven
years probably.  I seem to remember its objects had registers 'A'
through 'Z', and that was pretty much all they had for state information
- not including things like the gender of the object or it's position,
which are less general-purpose forms of "state".

In a MU* setup it is indeed more important that the internal state be
saved, but I was using that as the reason to think about how to get all
that state into a (e.g.) database record, instead of thinking about
keeping the state in the process's local variables, and somehow freezing
arbitrary processes to portable representation on disk (which sounds
very complicated.)

> > "Because it is there" is also a reason to go around the mountain  :-)  I
> > got LoS working quite well last night, so I'm going to keep the
> > interface 'roguelike' and resist the temptation to resort to the simpler
> > hierarchical structure of a classical MU*.
> Cool.  Though ... a Roguelike MU* might be intrresting.

I'm certainly no expert, but I believe MAngband and Ultima Online are
probably the two most popular examples of the genre.  UO costs money and
MAngband has licensing problems, though.

> I think you'd
> need to impliment LoH (Line of Hearing) to really handle folks talking
> to one another, and you'd need a specialized client.

Definately a specialized client, probably in Perl.  Without one, you
need a great deal of patience and imagination.  :-)  I considered just
sending cursor control sequences down the socket connection (i.e.
telnet) but that requires VT100 emulation, of course, and isn't very
abstract.  Possibly an option for users who don't want to use
specialized client software, though.

> Hmmmmm, LoH
> could probably be implimented as a sort of flooding algorithm.  Set
> the player's site to an Int value, set the neighboring ones to Int-1,
> recurse until you can't spread anymore.  Any square with a val > 0 is
> in the LoH.  Might be slow, I guess.  Only have to do it once for
> every move, though ... as long as you stand still, it doesn't change.

The flood algorithm is just about right to approximate acoustics, but it
is fairly slow.  It might be good to precompute it and cache it.  It
would be easier to do this with hearing than sight, as it changes less
as things move around.  In fact, if creatures don't block line-of-sight,
maybe that could be precomputed too, changing only when the scenery
(walls &c) change.  Doors that open and close frequently still present
problems though.

> > But I do not understand how working in the filesystem is easier than
> > working in mnesia tables.  The main reason I see to go with the
> > filesystem is performance under the current mnesia.  If that were not a
> > problem, using mnesia only would be simpler (& maybe faster.)  Using the
> > filesystem is more complex for several reasons, e.g. not all filesystems
> > are created equal.
> Well, because its easier to communicate to a human what
> "/server/player/soul.erl" actually /is/ than to try and find it in a
> swarm of mnesia tables which may not be necessarily nested.  Its
> purely a user interface issue, really, though there IS a goodly
> measure of "how can I make this easy for people to update remotely"
> too.  Its very easy for folks to edit code locally with Their
> Favourite Editor(tm) then use ftp to drop it into the right directory.

Ah, OK.  I also misunderstood the problem a bit.  I'm not proposing that
actual Erlang source code in text form be stored in a mnesia database.
While I'm sure it's possible, I'm not sure it's recommended.  What I'm
mainly considering is storing *funs* in the database.  It also makes
sense to be able to index that fun to its source code somewhere; much
more important in a MUSE where everyone's a "programmer".

The FTP thing in and of itself is a good reason to use the filesystem to
accomodate multiple users using tools they already have.  Trying to
incorporate an on-line code editor would be complex and probably a bit
futile.

> > If I can provide
> > help, it'll probably be in the form of letting people learn from the
> > mistakes I make in my prototype anyway :-)
> [grin]  Letting others learn from your mistakes is probably the best
> help anyone can provide.  In a sense, you have a somewhat easier time
> of making it multiplayer than others.  Just set the cookie on your
> node to the same thing every time, and you can transparently tag
> another node with a ping, add it to your known nodes, then access it
> as if it were right next door.

That's so easy it's almost criminal.  I wasn't considering clients
written in Erlang too, but with that I suppose I could bypass sockets
almost completely... and with SAE the client could still be pretty
small..

But, I considered the peer-to-peer model for multiplayer games, and I
concluded hacked peers open up too much of a loophole for cheating,
leading me to stick to a pretty strict client-server model.

But the using-Erlang-nodes-as-peers thing might work in other multi-user
contexts, like peer-to-peer file-sharing... not that the world needs
another peer-to-peer file-sharing protocol, mind you ;-)

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
On Sat, Mar 17, 2001 at 06:25:13PM -0600, Chris Pressey wrote:
> Most of it, yes.  In my model, state for each object - if any - is
> stored in its database record.  Every so often, the process uses that
> state information to decide what to do, and updates the state in the
> record if needed.  And many creatures don't have very complex lives, so
> they need little or no stored state.  If the state information
> disappears, the creature will eventually find something else interesting
> to do, so there's not much to be lost either.

Makes perfect sense, though if you're going to bring beasties back
after a game save, you still have to find a unique tag to associate
between a Pid and a DatabaseEntry.  Mmm, though I suppose in your
case, rebuilding straight from the DB would be acceptible.  The
initialization/restore code would simply walk the DB in some order,
and create a controlling Pid for this run, set it up from the data in
the DatabaseEntry, and run with it.  

That's probably not a bad idea for coming back up with a MU* server,
in the majority of cases.  I wonder about Things which are dependent
on other Things being up to work, but ... I suppose if all names are
resolved through a NameServer Pid, and you make sure it comes up
reasonably first/early, then it can just make things wait until their
targets wake up.

> I have to admit I haven't programmed in an actual MU* for years.  I was
> heavily into one called MicroMUSE but that was a long time ago, seven
> years probably.  I seem to remember its objects had registers 'A'
> through 'Z', and that was pretty much all they had for state information
> - not including things like the gender of the object or it's position,
> which are less general-purpose forms of "state".

MUSE evolved into the MUSH/MUX servers of today.  The "register"
concept got expanded to arbitrarily-named and -lengthed (up to
4k), and are, additionally, able to hold either code or data (mainly
because code is just text ... and MUSH/MUX language is very simple
scripting, though you can impliment complex things in it if you don't
mind the bleeding from the eyes).  All in all, its a very nice,
simple, straight-forward system overall ... but I really wish I had a
more powerful programming language embedded.  :)

> In a MU* setup it is indeed more important that the internal state be
> saved, but I was using that as the reason to think about how to get all
> that state into a (e.g.) database record, instead of thinking about
> keeping the state in the process's local variables, and somehow freezing
> arbitrary processes to portable representation on disk (which sounds
> very complicated.)

As long as processes can be marshalled and restarted, its golden
gravy.  I sometimes long for facilities like the old LispM's had of
just freezing the whole memory-state to disk for resumption at a late
time.  That kind of facility would be perfect.  :)

> I'm certainly no expert, but I believe MAngband and Ultima Online are
> probably the two most popular examples of the genre.  UO costs money and
> MAngband has licensing problems, though.

UO doesn't really count; it is pretty much a 3d MUD with pretty flash
graphics (like EverCrack).  I really /hate/ those interfaces, btw; its
impossible to gauge distances without binocular vision, actually
targeting things is nearly impossible to do while standing still, much
less moving, and let's not even get into the ballance issues.  Oi vey!

> Definately a specialized client, probably in Perl.  Without one, you
> need a great deal of patience and imagination.  :-)  I considered just
> sending cursor control sequences down the socket connection (i.e.
> telnet) but that requires VT100 emulation, of course, and isn't very
> abstract.  Possibly an option for users who don't want to use
> specialized client software, though.

Depends on how you impliment the VT100 controls; with enough
abstraction, it can be ... tolerable.  Still, probably nowhere NEARLY
as useful as a custom client written in Erlang using Erlang-based GUI
tools.  Despite all the complaints regarding them, they /do/ work.

> The flood algorithm is just about right to approximate acoustics, but it
> is fairly slow.  It might be good to precompute it and cache it.  It
> would be easier to do this with hearing than sight, as it changes less
> as things move around.  In fact, if creatures don't block line-of-sight,
> maybe that could be precomputed too, changing only when the scenery
> (walls &c) change.  Doors that open and close frequently still present
> problems though.

Might be hard to precompute all the areas sound could flow to
... you'd have to run flow for every point on the map, which could be
several hundred (at a minimum) sites.  Hmmmm, for precomputing LoS,
you might as well just precompute for each door state ... but that
gets nuts quickly if you can't break regions down cleanly by "this
area will never be affected if that door changes state."

> The FTP thing in and of itself is a good reason to use the filesystem to
> accomodate multiple users using tools they already have.  Trying to
> incorporate an on-line code editor would be complex and probably a bit
> futile.

Oh, I've done it in other languages.  Its a bit ... ugly ... but it
can be done.  The trick is replacing for a time the usual command
editor with another specialized for editing, then switching it back.

> But, I considered the peer-to-peer model for multiplayer games, and I
> concluded hacked peers open up too much of a loophole for cheating,
> leading me to stick to a pretty strict client-server model.

If you're worried about cheating, you might as well just not write a
game these days, if it involves ANY code in any form running on a
client.  Even telnet is susceptible to folks running front-ends which
do macro moves, etc.  Web-based games get daemon-flooded by bots which
play faster with simple logic than any human hopes to.  And so on.
Cheaters always find a way.  If they have to learn Erlang (and BEAM,
if you distribute it pre-compiled) to do it, I consider that a net
win.  :)

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Ulf Wiger-4
In reply to this post by Chris Pressey
On Sat, 17 Mar 2001, Chris Pressey wrote:

>But, I considered the peer-to-peer model for multiplayer games, and
>I concluded hacked peers open up too much of a loophole for
>cheating, leading me to stick to a pretty strict client-server
>model.

I've been thinking part time about how to address such problems.

One way would be to hack net_kernel.erl, and rpc.erl, only allowing
message passing and rpc calls that you feel are kosher.

Hacking net_kernel.erl is no picnic, but here's a place to start:

%%
%% The spawn/4 BIF ends up here.
%%
handle_call({spawn,M,F,A,Gleader},{From,Tag},State) when pid(From)->
    Pid = (catch spawn(M,F,A)),
    group_leader(Gleader,Pid),
    {reply,Pid,State};

%%
%% The spawn_link/4 BIF ends up here.
%%
handle_call({spawn_link,M,F,A,Gleader}, {From,Tag}, State)
when pid(From) ->
    catch spawn(net_kernel,do_spawn_link,[{From,Tag},M,F,A,Gleader]),
    {noreply,State};

handle_info({From,registered_send,To,Mess},State) ->
    send(From,To,Mess),
    {noreply,State};


I spent some time trying to figure out from where these messages
came. It seems as if they come from dist.c directly.

The interesting thing is that sometimes, the emulator dispatches
messages directly, while they sometimes are routed via net_kernel.
My understanding is that they come up to net_kernel only when
the distributed handshake is not quite done.

Then, hacking net_kernel doesn't solve anything. A pity.

/Uffe
--
Ulf Wiger                                    tfn: +46  8 719 81 95
Senior System Architect                      mob: +46 70 519 81 95
Strategic Product & System Management    ATM Multiservice Networks
Data Backbone & Optical Services Division      Ericsson Telecom AB



Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yetagain)

Chris Pressey
In reply to this post by Ulf Wiger-4
Ulf Wiger wrote:
> I've had a few ideas:
> - if code runs in another node, one might want to specialize the RPC
>   behaviour. Then, in fact making RPC a behaviour would be very handy.
>   One could perhaps specify at Erlang boot time via a kernel
>   environment variable which behaviour module to use for rpc.
>   When you think about it, lots more modules in OTP should really
>   be behaviours that could be specialized.

I totally agree.  In an ideal world, almost everything would be a
behaviour, and it would be just as easy to create a new behaviour as a
new module... they're very cool.

> - We've played around with different ways of taking care of really
>   hairy upgrade scenarios. One idea that came up (I think OTP is
>   still thinking about whether to cheer or throw eggs at us) was
>   to make it possible via the OTP R7B trace mechanism to reroute
>   a function call to another function (with same arity). For example
>   all calls to mnesia:write/1 could be rerouted to myMnesia:write/2;
>   a corresponding trap for message sending could be to call
>   M:F(Pid, Message) instead of sending the message. Dangerous stuff,
>   but it would be extremely flexible.

I thought about it over the weekend and I think I'll cheer, and save my
eggs for people who decide to abuse it.  I like it, it's probably worth
the danger.  Lying to the computer about what's going on is a long
standing tradition, after all...

> Have you read the thesis on OTP behaviours for simulations?
> I don't remember the URL, but it was posted on this list recently.

Yes, I've read most of it now.  It's a very good paper so the URL is
probably worth posting again.
  ftp://ftp.csd.uu.se/pub/papers/masters-theses/0178-ekstrom.pdf

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Chris Pressey
In reply to this post by Alexander Williams
Alexander Williams wrote:

> On the other hand, that brings me to an actual Erlang issue I haven't
> quite figured out yet.  One can't specifically import from a specific
> file in a specific place in the file hierarchy.  It'd be nice to have
> some way to define a "package" as the top of some file directory than
> refer to it with an import like:
>
>   1> top.dir.dir2.dir3:function(args) ...
>
> Unfortunately ... I don't think I can and that's a pretty hefty syntax
> hack.

"7.7 Module names

"Erlang has a flat module structure (i.e. there are not modules within
modules). Often, however, we might like to simulate the effect of a
hierarchical module structure. This can be done with sets of related
modules having the same module prefix.

"If, for example, an ISDN handler is implemented using five different
and related modules. These module should be given names such as:
isdn_init, isdn_partb, isdn_..."

  -- http://www.erlang.se/doc/programming_rules.shtml

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

erlang packages

Richard Carlsson-4


I presented a scheme for adding Java-style packages to Erlang at the
Erlang User Conference last year; the report is avaliable from:

        http://www.it.uu.se/research/reports/2000-001/

Feedback appreciated. I hope we will be able to implement this some day.

    /Richard Carlsson


On Wed, 21 Mar 2001, Chris Pressey wrote:

> Alexander Williams wrote:
> > On the other hand, that brings me to an actual Erlang issue I haven't
> > quite figured out yet.  One can't specifically import from a specific
> > file in a specific place in the file hierarchy.  It'd be nice to have
> > some way to define a "package" as the top of some file directory than
> > refer to it with an import like:
> >
> >   1> top.dir.dir2.dir3:function(args) ...
> >
> > Unfortunately ... I don't think I can and that's a pretty hefty syntax
> > hack.
>
> "7.7 Module names
>
> "Erlang has a flat module structure (i.e. there are not modules within
> modules). Often, however, we might like to simulate the effect of a
> hierarchical module structure. This can be done with sets of related
> modules having the same module prefix.
>
> "If, for example, an ISDN handler is implemented using five different
> and related modules. These module should be given names such as:
> isdn_init, isdn_partb, isdn_..."
>
>   -- http://www.erlang.se/doc/programming_rules.shtml
>
> _chris
>
> --
> "Ten short days ago all I could look forward to was a dead-end job as a
> engineer.  Now I have a promising future and make really big Zorkmids."
> Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
> Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html
>

Richard Carlsson (richardc)   (This space intentionally left blank.)
E-mail: Richard.Carlsson WWW: http://www.csd.uu.se/~richardc/



Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
In reply to this post by Chris Pressey
On Wed, Mar 21, 2001 at 11:56:56AM -0600, Chris Pressey wrote:
> "If, for example, an ISDN handler is implemented using five different
> and related modules. These module should be given names such as:
> isdn_init, isdn_partb, isdn_..."
>
>   -- http://www.erlang.se/doc/programming_rules.shtml

I'm well aware of this.  My problem is it rather, well, "sucks."
"Sucks" isn't too strong for this particular bit, I don't think.

Maybe I'm a living oddity, but I like tucking files into nice, neat
little directory-structures that mimic inheritance and such, so that I
know exactly what I'm looking at within any given point.  Such
hierarchies let multiple people be responsible for different bits,
even down to directory permissions (and, in this case, that's a
biggie).  They are, all in all, just really darn handy.

Python does the "right thing" here, I think.  You can import a
directory containing the proper initialization module filename and it
implies the whole structure on down as sub-modules.  Accessing deep
structures becomes easy.  Erlang's module system, especially given the
gen_* servers, doesn't have that same kind of innate simplicity.  That
makes it difficult to pursue things like the MU* project with certain
designs that, nevertheless, seem perfect for it.

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Chris Pressey
Alexander Williams wrote:
> On Wed, Mar 21, 2001 at 11:56:56AM -0600, Chris Pressey wrote:
> > "If, for example, an ISDN handler is implemented using five different
> > and related modules. These module should be given names such as:
> > isdn_init, isdn_partb, isdn_..."
> I'm well aware of this.  My problem is it rather, well, "sucks."
> "Sucks" isn't too strong for this particular bit, I don't think.

I don't think it sucks.  Nested packages are often a sign of
overclassification anyway - then again I'm more familiar with Perl than
Python or Java, perhaps that has coloured my viewpoint.  Nested packages
are handy when you have one abstract package (directory) and several
different concrete packages that implement it (subdirectory) - but
Erlang has behaviours that should probably be used instead - one
behaviour and several packages that implement that behaviour.

But I honestly don't mind that it's flat.  What I worry about a bit more
(although not too much) are namespace clashes.  What if someone else
wants to release a module named 'foo' while I want to release a module
called 'foo'?  How does the user that wants to use both of our modules
deal with it?  Should I prepend every module I name with some unique
prefix just to be safe?  I'd rather not, as that tends to make source
code rather less readable.

_chris

--
"Ten short days ago all I could look forward to was a dead-end job as a
engineer.  Now I have a promising future and make really big Zorkmids."
Chris Pressey, Cat's Eye Technologies, http://www.catseye.mb.ca/
Esoteric Topics Mailing List: http://www.catseye.mb.ca/list.html


Reply | Threaded
Open this post in threaded view
|

Fun with Erlang (was Re: Stand Alone Erlang for Windows. yet again)

Alexander Williams
On Wed, Mar 21, 2001 at 08:07:30PM -0600, Chris Pressey wrote:
> different concrete packages that implement it (subdirectory) - but
> Erlang has behaviours that should probably be used instead - one
> behaviour and several packages that implement that behaviour.

The way I generally structure code, I'd have one behaviour directory
with multiple directories beneath for packages, each of which'll
require multiple files, as will the overall behaviour glue.  If I'm
trying the impliment an application on top of all this, that's one
more subdirectory over the behaviours.

> called 'foo'?  How does the user that wants to use both of our modules
> deal with it?  Should I prepend every module I name with some unique
> prefix just to be safe?  I'd rather not, as that tends to make source
> code rather less readable.

To use an example from the MU* concept to illustrate the problem
(incidently, I heavily agree with you here):

We have a generic sword with the name sword.erl ...  And I want to
build a custom version that inherits the methods of the first one, so
do so ... but call it magic/sword.erl.  Makes sense, structurally
... but I can't get to it in a flat access structure.

I've read the description of the Java module system that was
previously posted and like it a lot, except for the inability to
resolve packages with a single import, allowing automatic sub-package
imports.

--
Alexander Williams (thantos)               | In the End,
  "Blue Jester needs food."                             | Oblivion
  "Blue Jester needs fuku-wearing cuties."              | Always
  http://www.chancel.org                                | Wins


12