Difference between revisions of "Writing Modules In C"

From ASSS Wiki
Jump to: navigation, search
m
Line 1: Line 1:
 +
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:
 
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:
  
  
<pre>/*
+
== Template Module ==
Template Module
+
 
*/
+
<pre>
 +
//Template Module
 +
 
  
 
#include "asss.h"
 
#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;
 +
}
 +
</pre>
 +
 +
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:
 +
 +
<pre>
 
// Interfaces
 
// Interfaces
 
local Imodman *mm;
 
local Imodman *mm;
 +
local Ichat *chat;
 +
</pre>
  
 +
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:
 +
 +
<pre>
 
// The entry point:
 
// The entry point:
EXPORT int MM_testModule(int action, Imodman *mm_, Arena *arena)
+
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;
 +
}
 +
</pre>
 +
 
 +
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:
 +
 
 +
<pre>
 +
// 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)
 
if (action == MM_LOAD)
 
{
 
{
 
mm = mm_;
 
mm = mm_;
return MM_OK;
+
 
 +
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)
 
else if (action == MM_UNLOAD)
 
{
 
{
return MM_OK;
+
mm->UnregCallback(CB_SHIPCHANGE, ShipChange, ALLARENAS);
 +
mm->ReleaseInterface(chat);
 +
rv = MM_OK;
 
}
 
}
 
else if (action == MM_ATTACH)
 
else if (action == MM_ATTACH)
 
{
 
{
return MM_OK;
+
rv = MM_OK;
 
}
 
}
 
else if (action == MM_DETACH)
 
else if (action == MM_DETACH)
 
{
 
{
return MM_OK;
+
rv = MM_OK;
 
}
 
}
return MM_FAIL;
+
 
 +
return rv;
 
}
 
}
 +
 
</pre>
 
</pre>
 +
 +
To get the function definition for your callback, you only have to look in the appropriate header file.
 +
 +
== Iterating Through Every Player / Every Arena ==
 +
 +
== Declaring Arena / Player Data ==
 +
 +
== Adding Timers ==
 +
 +
== Adding Commands ==

Revision as of 17:24, 10 January 2005

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:


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.

Iterating Through Every Player / Every Arena

Declaring Arena / Player Data

Adding Timers

Adding Commands