Writing Modules In C
I'm editing this page right now... please don't change it till i'm done. I'll remove this when I finish. -Bak
The easiest way to write a module in C is to work off a template, as certain parts of all modules are identical. Here is a template that does nothing more than connect with the server:
Contents
Template Module
//Template Module #include "asss.h" // Interfaces local Imodman *mm; // The entry point: EXPORT int MM_template(int action, Imodman *mm_, Arena *arena) { int rv = MM_FAIL; // return value if (action == MM_LOAD) { mm = mm_; rv = MM_OK; } else if (action == MM_UNLOAD) { rv = MM_OK; } else if (action == MM_ATTACH) { rv = MM_OK; } else if (action == MM_DETACH) { rv = MM_OK; } return rv; }
This modules loading function is called MM_template, and it is to be saved int template.c. This will make our module name be template when we are interested in loading it into a server. This is a good place to make sure that your module compiles, and that it loads into a server.
Using Interfaces
Interfaces are your way of interacting with what happens in the game. Want to send a chat message to a player? You need an chat interface. Want to warp a player to (512,512)? You need a mapdata interface. Want to toggle a lvz object? You get the idea...
The first thing you need to do is add your interface as a global like variable (We already have one interface, the module manager). Let's make a chat interface, so we can send chat text for the rest of this tutorial. Let's add our interface definition in our interfaces section:
// Interfaces local Imodman *mm; local Ichat *chat;
Now that we have a place to store the interface, let's get the interface. This is done when our function is loading, in the MM_template function. Here's the new MM_template function:
// The entry point: EXPORT int MM_template(int action, Imodman *mm_, Arena *arena) { int rv = MM_FAIL; // return value if (action == MM_LOAD) { mm = mm_; chat = mm->GetInterface(I_CHAT,ALLARENAS); if (!chat) // check interfaces rv = MM_FAIL; else rv = MM_OK; } else if (action == MM_UNLOAD) { mm->ReleaseInterface(chat); rv = MM_OK; } else if (action == MM_ATTACH) { rv = MM_OK; } else if (action == MM_DETACH) { rv = MM_OK; } return rv; }
Here you can see use getting the interface from the module manager, checking if we actually got it (some servers chose to omit certain modules, so you could actually make a server without chat). You must also release the interface when the module unloads. If your module prevents the server from loading, chances are an interface it is using isn't loaded.
You can see exactly what each interface does, and what functions are available by each interface by viewing the appropriate header file. In chat.h we see the defintion for Ichat, which includes a function pointer to a function we'll use:
</pre> // Send a green arena message to a player. void (*SendMessage)(Player *p, const char *format, ...) ATTR_FORMAT(printf, 2, 3); </pre>
Okay, so where do we send this message? We can't really put it anywhere, since the only place our code has control is when the module is loading or unloading. We want to be able to do something like send the player a message whenever they change ships, or enter an ASSS Region. For something like this we need a callback.
Listening For Callbacks
Callbacks are your way of listening for events. These include, a player entering an arena, changing ship, entering / exiting an ASSS Region. We'll handle a simple one, players changing ships. Whenever a player changes their ship we will message them that they changed ships (using our Ichat interface). Each callback has a callback function, which will be called when an event occurs. We pass a pointer to this function when we declare our callback. Here's the new code:
// Interfaces local Imodman *mm; // Functions local void ShipChange(Player *p,int ship, int newfreq) { chat->SendMessage(p,"You have changed ships."); } // The entry point:<br> EXPORT int MM_template(int action, Imodman *mm_, Arena *arena)<br> { int rv = MM_FAIL; // return value if (action == MM_LOAD) { mm = mm_; chat = mm->GetInterface(I_CHAT,ALLARENAS); if (!chat) // check interfaces rv = MM_FAIL; else { m->RegCallback(CB_SHIPCHANGE, ShipChange, ALLARENAS); rv = MM_OK; } } else if (action == MM_UNLOAD) { mm->UnregCallback(CB_SHIPCHANGE, ShipChange, ALLARENAS); mm->ReleaseInterface(chat); rv = MM_OK; } else if (action == MM_ATTACH) { rv = MM_OK; } else if (action == MM_DETACH) { rv = MM_OK; } return rv; }
To get the function definition for your callback, you only have to look in the appropriate header file.