I received a private message today, in which someone asked for some more information about scripting. As there's actually not a lot documentation about how to write a script from scratch, I've decided to put an extra example here. (and the private messaging system doesn't allow messages with more than 5000 characters, which is the main reason why I put it here

).
The language which you use for your scripts is AngelScript. The syntax and default functions of the class are explained
here (in combination with the
wiki page).
The scripting implementation of the Rigs of Rods server is event-based, which means that you'll be able to execute code when certain events happen. The current available events on the server are: the server starts (
main), a new player joins the server (
playerAdded), a player leaves the server (
playerDeleted), a player says something in the chat (
playerChat), the client of a player sends a script message (
gameCmd) and a sixth event that just happens every 200 milliseconds (
frameStep).
At each of those events, you can execute code. Here's a very simple example that just shows a chat message to all players on the playerAdded event:
<< php >>
You can execute that script by simply putting it in a text file with extension .as, and specify the file as scriptfile in the server configuration.
The next step in our simple script would be to add the username to the message. We can do this using the
string server.getUserName(int uid) function:
<< php >>
That's still a very simple example. More complicated would be to hold statistics of usernames. We can do this by using a
dictionary object as global variable. A dictionary object can store information and retrieve it again, based on a name (so, like a dictionary). So we're just going to store a simple number ('int') for every username that joins the server, and every time that we see the username again, we increase the counter by 1. (so the first time that the user joins, the counter will be 1, the second time that the user joins, the counter will be 2, etc).
<< php >>
That's already quite a useful script

Just as example, I'll also add a chat command now, that will allow you to see how many times a certain player joined the server:
PHP Code:
// Create our dictionary as global variable
dictionary userStats();
// The main function, we don't need this at the moment, but the script won't work without it being defined
void main() {}
// This function will get called when a player joins the game
void playerAdded(int uid)
{
// Create a new variable holding the username
string name = server.getUserName(uid);
// Get the amount of times that we've seen this player before
int timesSeen;
if( not userStats.get(name, timesSeen) )
{
timesSeen = 0;
}
// As the player just joined, we have to increase our timesSeen counter by 1
timesSeen += 1;
// And we store the updated value of our counter
userStats.set(name, timesSeen);
// And instead of showing a global message, we'll now show a private message to this user.
// The message will be different, depending on whether this is the first time that this user joined the server.
if(timesSeen==1)
server.say("Welcome " + name + ", thank you for deciding to check out our server!", uid, FROM_HOST);
else
server.say("Welcome back " + name + ", this is the " + timesSeen + "th time that you joined our server :D", uid, FROM_HOST);
}
// The playerChat event that will happen at every chat message
int playerChat(int uid, string msg)
{
// Split the message on spaces
array<string>@ arguments = msg.split(" ");
// We need at least 1 argument in our message
if(arguments.length()>=1)
{
// We only need to do something if the first word in the message is the command (first word = argument 0)
if( arguments[0] == "!seen" )
{
// For this command, we'll need at least 2 arguments in the message (the command itself, and a uid)
if(arguments.length()<2)
{
server.say("!seen shows join statistics of a certain user.", uid, FROM_SERVER);
server.say("Usage: !seen <uid>", uid, FROM_SERVER);
server.say("Example: !seen 152", uid, FROM_SERVER);
}
else
{
// The second word should be the unique identifier of the user of whom we want to get the statistics of
int buid = parseInt(arguments[1]);
// Get the username that matches the unique identifier
string name = server.getUserName(buid);
// The getUserName function returns something empty when the requested uid is not online
if(name=="")
{
server.say("!seen shows join statistics of a certain user.", uid, FROM_SERVER);
server.say("Usage: !seen <uid>", uid, FROM_SERVER);
server.say("Example: !seen 152", uid, FROM_SERVER);
}
else
{
// Get the amount of times that we've seen the player before
int timesSeen;
if( not userStats.get(name, timesSeen) )
{
timesSeen = 0;
}
// And show it as output to the user that requested it
server.say("User " + name + " (" + buid + ") has been seen " + timesSeen + " times on this server.", uid, FROM_SERVER);
}
}
}
}
// You can change broadcasting levels using this function, but here, we'll change nothing by returning BROADCAST_AUTO
return BROADCAST_AUTO;
}
So, we now have user statistics that will allow you to find out which usernames are commonly used on your server. Using the localStorage.as file from the first post in this thread, we'll be able to keep the statistics stored across sessions. The localStorage object is very similar to the dictionary object, but the localStorage object can also load and save the data to a file.
PHP Code:
// Include the localStorage file
#include "localStorage.as"
// Create our dictionary as global variable
localStorage userStats("userJoinStatistics.asdata");
// The main function, we don't need this at the moment, but the script won't work without it being defined
void main() {}
// This function will get called when a player joins the game
void playerAdded(int uid)
{
// Create a new variable holding the username
string name = server.getUserName(uid);
// Get the amount of times that we've seen this player before
int timesSeen;
if( not userStats.get(name, timesSeen) )
{
timesSeen = 0;
}
// As the player just joined, we have to increase our timesSeen counter by 1
timesSeen += 1;
// And we store the updated value of our counter
userStats.set(name, timesSeen);
// Save the statistics
userStats.save();
// And instead of showing a global message, we'll now show a private message to this user.
// The message will be different, depending on whether this is the first time that this user joined the server.
if(timesSeen==1)
server.say("Welcome " + name + ", thank you for deciding to check out our server!", uid, FROM_HOST);
else
server.say("Welcome back " + name + ", this is the " + timesSeen + "th time that you joined our server :D", uid, FROM_HOST);
}
// The playerChat event that will happen at every chat message
int playerChat(int uid, string msg)
{
// Split the message on spaces
array<string>@ arguments = msg.split(" ");
// We need at least 1 argument in our message
if(arguments.length()>=1)
{
// We only need to do something if the first word in the message is the command (first word = argument 0)
if( arguments[0] == "!seen" )
{
// For this command, we'll need at least 2 arguments in the message (the command itself, and a uid)
if(arguments.length()<2)
{
server.say("!seen shows join statistics of a certain user.", uid, FROM_SERVER);
server.say("Usage: !seen <uid>", uid, FROM_SERVER);
server.say("Example: !seen 152", uid, FROM_SERVER);
}
else
{
// The second word should be the unique identifier of the user of whom we want to get the statistics of
int buid = parseInt(arguments[1]);
// Get the username that matches the unique identifier
string name = server.getUserName(buid);
// The getUserName function returns something empty when the requested uid is not online
if(name=="")
{
server.say("!seen shows join statistics of a certain user.", uid, FROM_SERVER);
server.say("Usage: !seen <uid>", uid, FROM_SERVER);
server.say("Example: !seen 152", uid, FROM_SERVER);
}
else
{
// Get the amount of times that we've seen the player before
int timesSeen;
if( not userStats.get(name, timesSeen) )
{
timesSeen = 0;
}
// And show it as output to the user that requested it
server.say("User " + name + " (" + buid + ") has been seen " + timesSeen + " times on this server.", uid, FROM_SERVER);
}
}
}
}
// You can change broadcasting levels using this function, but here, we'll change nothing by returning BROADCAST_AUTO
return BROADCAST_AUTO;
}
So, now you have a system that will keep track of usernames. Possible further additions that you can make:
- Allow the !seen command to search on names instead of unique identifiers.
- Add the relative time when a user was last seen.
- Keep track of how much time a user spends on the server.
- Allow the script to be used by multiple running servers (use the servername or server port to create seperate filenames for each server)
- ...
Just for the record (to keep this on topic

), here's the script rewritten as chat plugin for the script wrappers earlier in this thread:
- chatPlugin_joinStats.as
PHP Code:
#include "utils.as"
#include "chatManager.as"
void chatPlugin_joinStats_seenCommand(chatMessage@ cmd)
{
chatPlugin_joinStats@ obj;
cmd.argument.retrieve(@obj);
obj.callback_seenCommand(cmd);
}
class chatPlugin_joinStats
{
// Create our dictionary as global variable
localStorage@ userStats;
// A reference to the chat manager
chatManager@ chtmngr;
// internal flag
bool registered;
chatPlugin_joinStats(chatManager@ _chtmngr)
{
@chtmngr = @_chtmngr;
// Register the callbacks
chtmngr.addCommand("seen", @chatPlugin_joinStats_seenCommand, @any(@this), true, AUTH_ALL);
server.setCallback("playerAdded", "playerAdded", @this);
// Load the statistics file
@userStats = @localStorage("userJoinStatistics.asdata");
registered = true;
}
~chatPlugin_joinStats()
{
destroy();
}
void destroy()
{
if(registered)
{
chtmngr.removeCommand("seen");
server.deleteCallback("playerAdded", "playerAdded", @this);
registered = false;
}
}
// This function will get called when a player joins the game
void playerAdded(int uid)
{
// Create a new variable holding the username
string name = server.getUserName(uid);
// Get the amount of times that we've seen this player before
int timesSeen;
if( not userStats.get(name, timesSeen) )
{
timesSeen = 0;
}
// As the player just joined, we have to increase our timesSeen counter by 1
timesSeen += 1;
// And we store the updated value of our counter
userStats.set(name, timesSeen);
// Save the statistics
userStats.save();
// And instead of showing a global message, we'll now show a private message to this user.
// The message will be different, depending on whether this is the first time that this user joined the server.
if(timesSeen==1)
server.say("Welcome " + name + ", thank you for deciding to check out our server!", uid, FROM_HOST);
else
server.say("Welcome back " + name + ", this is the " + timesSeen + "th time that you joined our server :D", uid, FROM_HOST);
}
void callback_seenCommand(chatMessage@ cmsg)
{
// We need at least 1 argument and that argument needs to be a number
if(cmsg.emsgLen<2 || !isNumber(cmsg.emsg[1]))
{
cmsg.privateGameCommand.message("!seen shows join statistics of a certain user.", "information.png", 30000.0f, true);
cmsg.privateGameCommand.message("Usage: !seen <uid>", "information.png", 30000.0f, true);
cmsg.privateGameCommand.message("Example: !seen 152", "information.png", 30000.0f, true);
return;
}
// The second word should be the unique identifier of the user of whom we want to get the statistics of
int buid = parseInt(cmsg.emsg[1]);
// Get the username that matches the unique identifier
string name = server.getUserName(buid);
// The getUserName function returns something empty when the requested uid is not online
if(name=="")
{
cmsg.privateGameCommand.message("!seen shows join statistics of a certain user.", "information.png", 30000.0f, true);
cmsg.privateGameCommand.message("Usage: !seen <uid>", "information.png", 30000.0f, true);
cmsg.privateGameCommand.message("Example: !seen 152", "information.png", 30000.0f, true);
return;
}
// Get the amount of times that we've seen the player before
int timesSeen;
if(!userStats.get(name, timesSeen))
timesSeen = 0;
// And show it as output to the user that requested it
cmsg.privateGameCommand.message("User " + name + " (" + buid + ") has been seen " + timesSeen + " times on this server.", "chart_bar.png", 30000.0f, true);
}
}
- your script file
<< php >>
(also, I've just updated the attachment of the first post, as there was a small bug in the localStorage.as file (line 262)).