Alfastreet manufactures gambling devices, among others, multi-player casino games such as single-wheel multi-client roulette, multi-client keno, etc.
I designed and coded the platform library for the next generation of multi-player games, intended to be running on LINUX based computers.
“Alfalfa”, the platform library I developed included the following features:
Encapsulated GUI system
Included with the library was a compiler for PSD (Photoshop Document) files. Each PSD file represented a single GUI box object, and together with an optional script, it was compiled into a series of rle-compressed images and an encapsulated GUI box object file. Unless the behavior was altered by the additional script, each layer in the PSD file would map to a single GUI control. An additional functionality of the compiler was its ability to generate raster fonts from TrueType, also based on definition provided by the script, incorporating such fonts into the GUI box object. Thus, each GUI box was at once a layered screen composed of GUI controls, but also a library of fonts, colors, typefaces and special effects. Since parenthood between GUI boxes was supported, features like skinning, multiple language variants and similar, became trivial. Also, the procedure of data exchange between the artist / GUI designer, and the programer, was greatly simplified.
All GUI related objects were then presented to the high level programmer as encapsulated objects. An example is given for GUI layer, a component of GUI box that represents either a single layer in the box, or a group of layers:
struct tGUILayer {
tPChar name();
GUI_layer type();
int id();
int layers();
tGUILayer* layer(int sublayer);
bool shown();
float x();
float y();
int z();
GUI_align alignX();
//...
tGUIBrush* brush();
GUI_blend blend();
float opacity();
GUI_select select();
int slide();
void move(float dx, float dy);
//...
void restore_xy();
void restore_brush();
void restore_blend();
//...
void run(tGUIFX* fx);
void run(const char* fx_template_name);
tGUIFX* running_first();
int propI(const char* prop);
float propF(const char* prop);
tPChar propS(const char* prop);
bool pack(tPacket* dst);
bool unpack(tPacket* src);
tEventPipe* pipe();
void set_pipe(tEventPipe* pipe);
};
Effects were scriptable, and plugins could be coded to extend the functionality. Effects included things like moving GUI controls around, or making a scrolling text appear inside a control, etc. Such approach offloads the burden of propagation of timed events from the main application.
I coded two renderers for Alfalfa GUI: a software renderer that supported features like alpha-blending and antialiased line rendering, and a hardware accelerated OpenGL renderer.
Persistence of objects
Every object supported by the library (even tPacket itself) may be stored into a tPacket object. tPacket object may then be sent through a tChannel to a different tProcess, saved into a file or some other persistent media.
This made it trivial to capture, for example, the current state of GUI and send it over to another process, reconstructing it there to mirror the state of the original.
Intermodular communication
I developed a system of pipes, queues and events. As the software in question needs resilience to be of industrial quality, all communication inside a process was to use the same mechanism as communication between processes. This would make logging and debugging much easier.
Interprocess communication
The intermodular communication was extended to support sending packets or events across to another process. This was done using a TCP/IP based protocol that supported up to 255 nodes within a private network of servers and clients. A single multiplayer game would therefore be organised as a small network with a fixed or variable number of clients and even servers.
State machine
An extension to the library was a state machine language, used to define and declare state machines that responded to events. An example of the language is given here:
BEGIN_MACHINE_EX( hopper, tDeviceMachine)
MACHINE_STATE( ST_INIT)
MACHINE_STATE( ST_ERROR)
MACHINE_STATE( ST_DISCONNECTING)
MACHINE_STATE( ST_DONE)
MACHINE_STATE( ST_READY)
MACHINE_STATE( ST_BUSY)
MACHINE_HANDLER( on_INIT)
MACHINE_HANDLER( on_READY)
MACHINE_HANDLER( on_BUSY)
MACHINE_HANDLER( on_ERROR)
MACHINE_HANDLER( on_DISCONNECTING)
MACHINE_HANDLER( on_DONE)
MACHINE_HANDLER( on_PAYOUT)
MACHINE_HANDLER( on_BUSY_PAYOUT)
MACHINE_FUNCTION( void loop())
END_MACHINE
BEGIN_STATE(hopper, ST_INIT)
BEGIN_STATE_MAP
MAP_TRANSITION( ON_CONNECT, ST_READY)
MAP_TRANSITION( ON_DISCONNECT, ST_INIT)
MAP_TRANSITION( ON_ERROR, ST_INIT)
MAP_TRANSITION( ON_QUIT, ST_INIT)
END_STATE_MAP
STATE_SWITCHIN( on_INIT)
END_STATE
The idea that I used here was specific in that only one file is used to actually declare and define all necessary classes, structures and functions to support a state machine class. Then this same file was included in (following the given example) both “hopper.h” and “hopper.cpp”, removing all the redundant duplication that often comes with meta programming.
Prototype
To demonstrate the capabilities of the library, I also created a fully working prototype for the TaiSai game. An actual 8-player machine was built, with a working wheel and a game server to support it. The only feature that was missing was the actual handling of accounting-related hardware, such as coin and bill acceptors, and the accounting itself.