SRVPro Plguins
SRVPro also support plugins for extending its functions. Developing plugins for SRVPro is highly welcomed.
How to use a plugin
All installed plugins should be put in ./plugins
directory. A plugin could be a single js
file, or an entire Node package.
If the plugin to install is a...
- Single JS file: Just simply place the
js
file into./plugins
. - Node package: Clone the entire repository into
./plugins
directory. You may have to follow the instructions of the plugin's documents.
Sample plugins
Here are some sample plugins. All the plugins listed here were written in Node packages by Nanahira, and licensed under AGPL v3.
You may directly install those plugins into your server, or take those plugins as reference to make your own SRVPro plugins.
- https://github.com/purerosefallen/srvpro-coolq A QQ bot for SRVPro room list or card testing, using CoolQ HTTP SDK.
- https://github.com/purerosefallen/srvpro-pre-compat A plugin for compating pre-release cards, allowing players with official cards or pre-release cards have no trouble dueling with each other.
- https://github.com/purerosefallen/srvpro-side-restrict An SRVPro plguin, restricting changing side. This may be useful for specific tournaments.
Making your own plguins
Making a plugin for SRVPro is very simple. You may make up an entire Node package, or write a single js
file.
Entry point
If you are developing a plugin as a Node package, make sure the package.json
is inside your repository, in which the value of main
should be the entry point.
Global variables
You may access those global variables provided by SRVPro for your convenience.
-
_
The underscore library. -
log
The bunyan logger. -
moment
The moment library. -
import_datas
An array for storing all fields imported to the new client when the client reconnects. If you inserted custom fields for client you have to insert it here. eg.
import_datas.push("is_using_pre_release");
-
setting_save(settings)
Save a setting into JSON file. The JSON filename is decided by thefile
field of that setting. -
setting_change(settings, path, val)
Change a value of thepath
field toval
insettings
, and save it withsetting_save
.
When making changes for the 6 variables below, remember to save them with setting_save
.
-
settings
The object for storing settings, which would be loaded from./config/config.json
. -
tips
The object which would be loaded from./config/tips.json
. -
dialogues
The object which would be loaded from./config/dialogues.json
. -
badwords
The object which would be loaded from./config/badwords.json
. -
duel_log
The object which would be loaded from./config/duel_log.json
. -
chat_color
The object which would be loaded from./config/chat_color.json
. -
lflists
An array storing names of the banlists loaded fromlflist.conf
.-
lflist[].date
The date of the banlist inmoment
format. -
lflist[].tcg
A boolean deciding whether this banlist is a TCG banlist.
-
-
redisdb
The Redis object for Cloud Replay. -
windbots
The object for WindBot, which would be loaded frombots.json
. -
real_windbot_server_ip
A string showing the windbot server's real IP address. -
long_resolve_cards
An object loaded from./data/long_resolve_cards.json
, showing the cards whose effects requires a lot of animations to resolve, used in the Heartbeat detection module. -
ygopro
The ygopro object, handling the interact with YGOPro.-
ygopro.i18ns
The object for storing lines in different languages, loaded from./data/i18n.json
. If you add custom lines in plugins, you need to insert it here. eg.
ygopro.i18ns["en-us"].pre_release_compat_hint = "It seems like you're a duelist with pre-release cards. The pre-release compat mode is turned on."; ygopro.i18ns["zh-cn"].pre_release_compat_hint = "看起来你是使用先行卡数据的用户,已开启先行卡兼容模式。";
-
ygopro.proto_structs
Loaded from./data/proto_structs.json
. -
ygopro.constants
Loaded from./data/constants.json
. -
ygopro.stoc_follows
All STOC handling functions in SRVPro. -
ygopro.stoc_follows_before
All STOC handling functions provided by plugins, which would be executed beforestoc_follows
. -
ygopro.stoc_follows_after
All STOC handling functions provided by plugins, which would be executed afterstoc_follows
. -
ygopro.ctos_follows
ygopro.ctos_follows_before
ygopro.ctos_follows_after
Refer above, but it handles CTOS messages. -
ygopro.stoc_follow(proto, synchronous, callback)
Set the handling function of STOC_proto
tocallback
. Ifsynchronous
is set totrue
and the function returnstrue
, the message would not be sent or handled. Not recommended in plugins, otherwise it would overwrite the system STOC handling functions, making SRVPro not working properly. -
ygopro.stoc_follow_before(proto, synchronous, callback)
Add a handling functioncallback
for STOC_proto
, which would run before the system STOC handling function. Ifsynchronous
is set totrue
and the function returnstrue
, the message would not be sent or handled. -
ygopro.stoc_follow_after(proto, synchronous, callback)
Add a handling functioncallback
for STOC_proto
, which would run after the system STOC handling function. Ifsynchronous
is set totrue
and the function returnstrue
, the message would not be sent or handled. -
ygopro.ctos_follows(proto, synchronous, callback)
ygopro.ctos_follow_before(proto, synchronous, callback)
ygopro.ctos_follow_after(proto, synchronous, callback)
Refer above, but it handles CTOS messages. -
ygopro.stoc_send(socket, proto, info)
Send a STOC message inproto
tosocket
. Theinfo
could be a struct object (Refer tostructs.json
for the formats), orbuffer
for sending a custom message. -
ygopro.ctos_send(socket, proto, info)
Send a CTOS message inproto
tosocket
. Theinfo
could be a struct object (Refer tostructs.json
for the formats), orbuffer
for sending a custom message. -
ygopro.stoc_send_chat(client, msg, player = 8)
Send a chat messagemsg
toclient
. The upvalueplayer
decides the message color. eg.
ygopro.stoc_send_chat(client, "${pre_release_compat_hint}", ygopro.constants.COLORS.BABYBLUE);
The part in format
${...}
would be replaced with the strings inygopro.i18n
, for supporting different languages.-
ygopro.stoc_send_chat_to_room
Refer toygopro.stoc_send_chat
, but it sends the message to the whole room. -
ygopro.stoc_die(client, msg)
Only can be called in the handling functions ofSTOC_JOIN_GAME
. Sends an error messagemsg
to player and disconnects the player.
-
-
roomlist
The module for WebSocket room list. -
pg_client
An instance of PG Client. -
challonge
The Challonge module.-
challonge.participants._index
challonge.matches._index
A cached version ofchallonge.*.index
, avoiding sending too many requests to the Challonge platform.
-
-
refresh_challonge_cache
Clear the cache ofchallonge.participants._index
andchallonge.matches._index
. Must be called when updating the scores on Challonge. -
memory_usage
THe percentage of the server memory used. -
Cloud_replay_ids
All available cloud replay IDs. -
ROOM_all
An array storing all rooms. May be useful for roomlist-related plguins. Be aware that there would be null elements.
STOC and CTOS
Instead of ygopro.ctos_follow
and ygopro.stoc_follow
, plugins should use functions like ygopro.ctos_follow_before
and ygopro.ctos_follow_after
instead. The functions end with _before
would be handled before ygopro.ctos_follow
, and the functions end with _after
would be handled after it.
Here is an example from the plugin srvpro-deck-restrict
.
ygopro.ctos_follow_after("UPDATE_DECK", true, (buffer, info, client, server, datas) => {
var room = ROOM_all[client.rid];
if (!room || room.duel_stage === ygopro.constants.DUEL_STAGE.BEGIN) {
return false;
}
for (var code of list) {
if (client.side.indexOf(code) !== -1) {
ygopro.stoc_send_chat_to_room(room, "${invalid_side_rule}", ygopro.constants.COLORS.RED);
ygopro.stoc_send(client, 'ERROR_MSG', {
msg: 3,
code: 0
});
return true;
}
}
});
This handling function would run after SRVPro resolves CTOS_UPDATE_DECK
Those functions also accepts a boolean return value. If it returns true, this message would not be handled anymore and would be blocked. Take the example above, if it returns true, the deck would not be sent to YGOPro, and it sends an error message to the player telling them that they put invalid cards in the side deck.
Making changes on buffers
You may also directly change the contents inside the messages. Operating directly on buffers is not an easy way. So we need structs to do so. Making changes on buffers could be performed in those steps.
- Get the needed struct definition from
ygopro.structs
. The struct definitions available are insidestructs.json
, while the struct definition needed for each protos are inproto_structs.json
.
var struct = ygopro.structs["any_structs"];
- Set the passed buffer for the struct.
struct._setBuff(buffer);
- Make changes on the structs with
struct.set
. You may perform this step multiple times to replace all fields you want.
struct.set("key", value);
- Re-define the
buffer
upvalue with the replaced buffer, to make the code below operates on the new buffer instead of the old buffer.
buffer = struct.buffer;
Here is an example from the plugin srvpro-pre-compat
, which replaces all the pre-release card codes into official card codes by operating on buffers.
ygopro.ctos_follow_after("UPDATE_DECK", false, (buffer, info, client, server, datas) => {
var room = ROOM_all[client.rid];
if (!room) {
return;
}
var found = false;
var buff_main_new = [];
var buff_side_new = [];
for (var code of client.main) {
var code_ = code;
if (room.list_pre_to_official[code]) {
code_ = room.list_pre_to_official[code];
found = true;
}
buff_main_new.push(code_);
}
for (var code of client.side) {
var code_ = code;
if (room.list_pre_to_official[code]) {
code_ = room.list_pre_to_official[code];
found = true;
}
buff_side_new.push(code_);
}
if (found) {
var compat_deckbuf = buff_main_new.concat(buff_side_new);
var struct = ygopro.structs["deck"];
struct._setBuff(buffer);
struct.set("mainc", buff_main_new.length);
struct.set("sidec", buff_side_new.length);
struct.set("deckbuf", compat_deckbuf);
buffer = struct.buffer;
}
if (room.duel_stage == ygopro.constants.DUEL_STAGE.BEGIN) {
client.is_using_pre_release = found || client.vpass == "COMPAT";
if (client.is_using_pre_release) {
ygopro.stoc_send_chat(client, "${pre_release_compat_hint}", ygopro.constants.COLORS.BABYBLUE);
}
}
});