Subscribe to the RSS Feed

Paradox - a statement or proposition that seems self-contradictory or absurd but in reality expresses a possible truth.

:: BINARY PARADOX ::

Stepping stone to the /dev/null in the sky

LPC Ghetto AOP

I’ve decided to post some more unusual content. In terms of obscurity this material ranks quite high. You won’t be finding jobs requesting LPC experience on Monster or Dice.

A little bit of background is probably in order… LPC is the scripting language exposed by the LDMud driver. It is the language in which LP muds are written. In order to keep this introduction terse I won’t be going into the concepts of a MUD, but rest assured it’s easy to find additional information (See: google).

LPC is an interesting language. It has C-style syntax with more python-style scripting abilities. Closures intermix with traditional for loops. It is “object oriented” so long as you have a very broad and flexible idea of “object orientation”.

Please note that I’ve deliberately left out code samples for this posting. It’s simple enough to implement yourself and I’d prefer if certain functionality remain unique on my home MUDs. If you have implementation specific questions ask me. If you’re still struggling I would likely share the code on a personal level. Anyway, enough background, onto the task at hand!

A problem was recently posed to me: _“If I wanted to selectively block the evaluation of add_action() functions based on
certain criteria known only at run-time, how would I go about it?”. This question itself was raised by the inability of the coder in question to use the traditional add_action _“filter“ created by

add_action("handlerFunction", "", AA_SHORT);

It appeared as though add_action handlers attached by an item in a player’s inventory would be executed before the “handlerFunction” defined in the filter created by the player object. So out the window was the idea of having a filter function check to see if query_verb() was equal to an action in an item we wanted to block (i.e. drink, eat, enable, whatever).

After some deliberation the coder in question and I were able to begin forming the idea of a “guardian” function. Drawing on concepts from Aspect Oriented Programming like the idea of “before advice” we decided to try interjecting a function before the real deal that would be able to evaluate whether or not the actual function call would be performed.

Naturally LPC is lacking in any sort of AOP abilities so we had to design a hack using closures as function pointers. The main problem appeared to be how we could interject our guardian function before the real function linked by add_action() in the most transparent backwards compatible way.

The problem of interjection spawned two implementations:

  1. abstracting add_action at the lib level
  2. masking add_action with a simulated efun.

Abstracting add_action at the lib level was the easiest solution. One could create a function (let’s call it add_operation for now) that offered an identical method signature to add_action. That is, it would appear to behave in the exact same manner as add_action and the two definitions could easily be replaced by a script without issue.

Add_operation would only appear to work as add_action however. In reality when it was passed a verb and a function to associate it would do something different. Instead of actually linking the two it would first store the verb and the desired function in a mapping (dictionary to you Python-types). Once that was done it would link the provided verb to the guardian function NOT the real function that it stored in the mapping.

This is where things get interesting. At this point we have made a note in our mapping of what the real function to be called for a specific verb is, while simultaneously adding a real mapping from that verb to a guardian function. We have successfully interjected the guardian.

The guardian can now determine what verb is being potentially guarded with query_verb(). With that knowledge in hand once it has determined if the action is to be “guarded” (based on any number of criteria such as player statuses, health points, environmental conditions, etc) or not it can lookup the real function to call and invoke it normally.

This abstraction solution is clean, but it unfortunately requires that MUD quality control enforces using add_operation for every action that should potentially be blocked by any number of circumstances (such as blindness, stun, limblessness, etc). It also means adding the change to any old code that is already using add_action. A herculean task for an old established MUD.

Our second solution (masking add_action with a simulated efun) has the benefit of being completely transparent. The entire lib would be switched over at once, and any future coders could continue to use add_action as naturally comes to them.

By creating a simulated efun with the signature of add_action we can implement our guard function hooking for add_action itself, calling efun::add_action when it’s time to link the target verb with the guardian function. If you wanted to be especially clever you could extend the signature of add_action to allow for an optional int flag indicating whether it should be guarded or not (I would default it to “guarded”). The simul could then consider this flag and optionally invoke efun:add_action to link the verb with the real action outright and skip the guarding process.

In the end, it is totally possible to transparently have add_actions’s only evaluate fully when certain conditions are met. This technique allows a great deal of control to the lib in terms of selectively enabling or disabling the functionality of rooms, items, weapons, etc. It’s usefulness is only as good as the mind of the lib coder utilizing it.

I think it would be an especially interesting thought excercise to overload the signature of add_action to the point where it can accept a closure pointer to an arbitrary guardian function. If this were achievable then you could easily introduce any number of closures to act as “before advice” for a given action instead of limiting all actions to be guarded by one function.


Transmissions:

Begin Transmission:

Add your thoughts, preview and then submit

Please note, your comment will not appear until after it has been moderated & approved. Sorry!


Hidden


Textile Help

You may also be interested in...