The random rantings of a concerned programmer.

Erlang MUD V

January 26th, 2008 | Category: Random

So I just got back from a “watch girls wrestle half-naked in a pool filled with jello” party, and it was fairly entertaining. Got to see tits, grabbing, etc while drinking free (as in free beer) beer and enjoying the company.

goodbye-satchii.PNGAnyway, now that I got that bit of bragging off my shoulders. As I was walking home I was thinking about Dennou Coil (since I’m modelling my Erlang MUD’s world around it, a bit). The best parts of Dennou Coil revolve around fight scenes, where the characters battle each other (and the constructs in the system) with programs manifested within objects. These programs are forged from items called “metabugs”, which aren’t really explained well, but are rare and sought-after glitches which occur in the digital space.

The thing is, the characters need metabugs to produce the programs they use (really, they barter with other people who can use the metabugs and refine them into things). This was always a bit curious to me, since a program is just data. And data can easily be replicated, so why can’t they just make a couple copies of that powerful metatag they only have 2 more of?

Well, durr, security. They’re interacting with a large system, and any such a system is going to have restrictions on what kind of code it’s going to execute, so some random user can’t just execute any arbitrary code. I mean, stuff like this is already done today, shadow memory and shit where you pad all the data in the machine with extra attribute bits to mark executability or taint or whatever the hell you want.

ghibli1.jpgMy conclusion is that the metabugs are bits of data which have favorable meta-characteristics that allow them to be used to create user-generated programs which can be executed on the system.

And then you introduce the Imago and encodings and it fucks up my entire hypothesis, lol.

But I was thinking, if I were to build this MUD, I’d have to have a fairly good idea of how everything “works” in the make-believe system, so that it all makes sense and shit. I think you’d be able to collect metabugs, but each bug actually is represented as a block of data. The actual data is essentially random (garbage data), and as garbage data is affected by the environment which spawned it.

The characteristics of the metabug would be gleaned from the value of the garbage data; things like color, shape, size, images and sounds perceived within, etc, in addition to what you could turn it into would all be dependent on this data, such that you can just supply any random string of garbage data and it would always describe a unique metabug.

Essentially procedural metabugs.

This, of course, has all the drawbacks of procedural generation: there’s a good chance it could generate dull, boring and expansive possibilities. Which isn’t good.

I dunno. Need to think moar I guess.

No comments

Erlang MUD IV

January 15th, 2008 | Category: Random

So, after watching Dennou Coil, I thought back to my idea for a card game. Well, it wasn’t so much an idea for a specific card game, but more along the lines of “lol cards are cool”. The idea came back mostly because of the awesomeness of Metatags in Dennou Coil. Really an awesome series.

Anyway, so I was thinking some more, and you know, card games really aren’t that fun unless you play them with other people. Which means I’m gonna need a server backend for the whole thing. Which means… Erlang!

It’s been a long time since I last thought about it, and you know, it really needs some more thought. The shitty gen_tcp wrapper I wrote a while back is really dumb, and easily killable. Additionally, the network layer needs to not only abstract the client stuff, but it needs to do other tasks like prevent flooding, basic input processing (backspaces…), etc.

So, lulz, I’m once again rewriting the network layer. Because that’s what I seem to do in Erlang. Like many of my “projects” I’ll probably get bored with it after a couple of days, then come back to it at a later date. Here’s the interface that I’ve laid out for it:

-module( mud_serv ).
-export( [
        start_async/2,
        serv_listen/2,
        serv_handle_clients/2,
        client_listen/3,
        client_sockrecv/2
] ).

% Primary function, opens a listener port and spawns the listener.
% Non-blocking.
%
% Arguments:
%       Port - port number to open a listener port on.
%       ClientFunc - a fun/1 which gets spawned for each client; is given
%               the PID of the client_listen process for control. Will be passed
%               { sock_recv, Msg }, { sock_connect } and { sock_disconnect }.
%
start_async( Port, ClientFunc )
        ->
        ok
        .

% Listener process for the server socket. Waits until a connection is
% incoming, and then hands the request to a serv_handle_clients/2 process
% which then decides whether or not to accept the connection. Essentially
% a gen_tcp:accept blocker.
%
% Arguments:
%       ServSock - the pre-created valid socket handle to listen with
%
serv_listen( ServSock, PID_Handler )
        ->
        ok
        .

% Dedicated process for handling incoming connections and already connected
% clients. Maintains a list of clients (and their associted IP addresses and
% sockets). Is notified when a client disconnects by client_listen.
%
% Arguments:
%       ClientFunc - passed in by start_async/2
%       ClientList - a list of currently-connected sockets.
%
serv_handle_clients( ClientFunc, ClientList )
        ->
        ok
        .

% Process which is spawned for each client; serves as an interface between the
% socket and the actual application code.
%
% Arguments:
%       ClientSock - the socket handle for the client
%       PID_Client - PID to the application process handling this client, spawned from
%               the ClientFunc passed to serve_async/2.
%       PID_Handler - the PID to the serv_handle_clients/2 process, to notify the
%               handler process when the client disconnects.
%
client_listen( ClientSock, PID_Client, PID_Handler )
        ->
        ok
        .

% Process which is spawned for each client; acts as a gen_tcp:recv loop
% to allow the socket to be processed in an asynchronous manner.
%
% Arguments:
%       ClientSock - the socket handle for the client
%       PID_Listener - PID to the client_listen/3 process to forward messages
%               received from the socket.
%
client_sockrecv( ClientSock, PID_Listener )
        ->
        ok
        .
No comments

LOATHSOME BACKSPACES

December 24th, 2007 | Category: Random

So one of the issues I wanted so solve in my Erlang MUD was backspaces. When a shitty telnet client sends a backspace, the server should be able to recognize that and treat it in a sane manner. This implies two things:

  1. Each backspace should remove the first preceeding non-backspace character from the string.
  2. No backspaces should be remaining in the string after processing.

I’m not sure if it’s possible to do with a regex, but there are some funny strings that actually come up quite often which broke a couple of my previous hacks. So I finally sat down and wrote this (which appears to handle them properly) -

handle_backspaces( 8, { Work, N } )
        ->
        % This character is a backspace
        { Work, N + 1 }
        ;
handle_backspaces( A, { Work, 0 } )
        ->
        % Just append A onto the front of Work
        { [ A | Work ], 0 }
        ;
handle_backspaces( _, { Work, N } )
        ->
        % Delete a character, delete a backspace
        { Work, N - 1 }
        .

Which is invoked with foldr like so -

{ Output, _ } =
        lists:foldr(
                fun( X, Y ) -> mmo_client:handle_backspaces( X, Y ) end,
                { [], 0 },
                Input
        )
.

This, of course, can be wrappered so it can be used without spilling the guts of the implementation everywhere. Hooray <3

2 comments

Erlang MUD III

December 04th, 2007 | Category: Random

I’ve been spending some more time thinking about the Erlang MUD, namely, how all the data is going to be structured. The last time I worked on it (a week ago?) I was rewriting the rewrite to use records instead of tuples for all the user/room data. In Erlang, “records” are basically structured tuples crossed with dictionaries, so the tuple is composed of a bunch of key->value pairs.

I need to use records, because it makes everything play nice with Mnesia later down the road.

I’ve also given some more thought to some designy things. I’ve always liked the idea of games within games, and hell, why not make this a meta MUD? To do this, we’ll define an environment, making each environment independent.

What this implies is that each user account is associated with (possibly) an independent entry in the user-data table for each environment that user has been in. I actually don’t think this adds much complexity to the code; given there will exist a table for user data, I can just change the table key from the user_id to a tuple { user_id, env_id } and, possibly, add in another table mapping each user_id to the env_id to load at login.

There’s still a couple of design issues which need to be considered, namely, transitions between environments. When you transition into an environment, does it get pushed onto a per-user environment stack? Or does it take the place of the last environment completely? This is important for defining what happens when the user “exits” the environment (or, if they can exit it). I think the solution I’m playing with in my head uses both methods for different ends.

The need behind this feature is to meet one of the themes of the game – realities. Each environment essentially represents a different reality. How you define reality, however, is something which is up for interpretation, thus the above problems.

How about some use cases.

Assume your player goes to sleep, for example, and has a dream. This dream might manifest itself by spawning another environment as a child to the environment the character was already in. The character interacts with this environment, does some stuff, and then wakes up. They exit the dream environment and re-enter the unchanged parent environment.

Another approach might be to use the environments for a mini-game, like gambling. The problem with this is that the gambling environment needs to get the state of the player. One approach is to make a copy of the player state and pass that into the environment, then restore the old player state when the player leaves. The problem with using this for gambling is that the affects on the copied player state will probably need to be propagated back to the parent state, to reflect any winnings/losses made.

Anyway, tl;dr, I need to think about it some more. I think there’s a lot of benefits with any approach (like having support for independent player-managed environments on external hosts running non-Erlang applications, etc), but we’ll see.

No comments

Erlang MUD II

November 29th, 2007 | Category: Random

Okay, so there’s a shitton of stuff I need to plan out for a MUD. MUDs are XBOX HUEG things, I realized. It’s the technology behind them that’s typically less than other projects.

So far, I’ve written a simple non-persistent talker throwaway prototype to become acquainted with the gen_tcp module. It works, but it isn’t good enough to use for anything but the most basic of references. The source can be found here.

In addition to better working out the overall program structure, there’s a couple more things I need to be better acquainted with, like Mnesia, the Erlang distributed database backend.

I think my next project is to write another prototype, adding additional features like:

  • Persistent player state.
  • Emotes and player-defined emotes.
  • Rooms (ugh, you’ll hear more about rooms).

And I think one of my routers just crashed. Motherfucker.

Anyway, that’s probably enough for me to bite off for now, and should provide both some experience working with Mnesia and have some reference example to work on future prototypes.

No comments

Next Page »