Skip to content
mraccident edited this page May 9, 2011 · 5 revisions

Boostcraft Plugin Architecture

Boostcraft is strongly oriented around the use of plugins to augment, extend, or modify the behavior of the server. A plugin is a set of closely related event callbacks (or delegates) that are loosely coupled with the rest of the system.

Most of the server's game-level logic will be implemented in plugins or plugin-like modules -- the modules will differ from normal plugins only in that they are compiled into the base server for convenience. Plugins operate by connecting their delegates to various event slots which form the core of the Boostcraft system. Many events are raised by the receipt of client packets by Boostcraft's network layer, but plugins and other parts of the system can raise events as well. The firing and handling of events is the primary means of communication between components.

For reference see this badly illustrated diagram:

The section enclosed in the dashed bubble is the "core" of the system; the objects marked "Plugin" could represent either extension plugins or core components that are implemented as modules. Architectural details of the world state currently reside in the Cloud of Mystery.

Events

Event handling is implemented with boost::signals2 and boost::asio. signals2 provides managed, thread-safe callback slots and asio allows asynchronous processing of i/o events in multiple threads.

Plugin interface

In boostcraft each plugin is represented at runtime by an object of class Plugin. The Plugin class requires only a very simple interface:

  • An initialize method for setting up the plugin.
  • A destroy method for performing any needed finalization.
  • Methods for querying the plugin for information about itself, e.g., name and version info.

The particular plugin's implementation of initialize is responsible for registering whatever callbacks it needs to begin performing its task.

Python Plugins

The primary implementation of the Plugin interface will be PythonPlugin, an instance of which acts as the "glue" between Boostcraft and an extension written in Python. PythonPlugin::initialize runs the main .py file for the plugin and then calls a specially-named function in the module (possibly init).

From there it is a matter of the plugin's Python code interacting with the Boostcraft API. The details of this are still hazy, but the goal is to provide a clean, abstracted interface to the game world. "Abstracted" here means that irrelevant details like the existence of chunks, chunk generators, chunk servers, etc. do not bleed into the picture. A plugin should be able to request world.blockAt(x,z,y) and simply receive the block requested.

[Comment: the abstraction may need to be leaky at this point. What if
 (x,y) is nowhere near any loaded chunk? A chunk must be fetched, and
 possibly generated first. This would incur a small but non-negligible
 delay. While the individual plugin may not care if it has to wait an
 extra ten milliseconds for the call to world.block(x,y) to complete,
 other plugins might: we are still bound by the restriction that only
 one thread may be executing Python code at any time. Will a lengthy
 call to the C++ API block Python callbacks in other threads?
 
 This question should probably be addressed in general. I suppose it
 would be reasonable to implicitly release the intepreter lock during
 API calls that might not return instantly. It may be a good idea to
 handle such calls asynchronously -- is this possible? That is, can we
 suspend the state of a Python->C++ call, return from the C++ function
 *without* returning into Python, and then later (once the operation
 has completed) return to the Python code that made the call?

 TODO: find out exactly how calls from Python to C/C++ extensions work
 and to what extent we can manipulate them to "play nice" with multi-
 threading.]

Clone this wiki locally