forked from github/server
eventbus WIP
This commit is contained in:
parent
efeeba13c2
commit
cc7172f812
|
@ -4,11 +4,13 @@
|
||||||
|
|
||||||
#include "common/iniparser/iniparser.c"
|
#include "common/iniparser/iniparser.c"
|
||||||
#include "common/util/attrib.c"
|
#include "common/util/attrib.c"
|
||||||
|
#include "common/util/argstack.c"
|
||||||
#include "common/util/base36.c"
|
#include "common/util/base36.c"
|
||||||
#include "common/util/crmessage.c"
|
#include "common/util/crmessage.c"
|
||||||
#include "common/util/cvector.c"
|
#include "common/util/cvector.c"
|
||||||
#include "common/util/dice.c"
|
#include "common/util/dice.c"
|
||||||
#include "common/util/event.c"
|
#include "common/util/event.c"
|
||||||
|
#include "common/util/eventbus.c"
|
||||||
#include "common/util/filereader.c"
|
#include "common/util/filereader.c"
|
||||||
#include "common/util/functions.c"
|
#include "common/util/functions.c"
|
||||||
#include "common/util/goodies.c"
|
#include "common/util/goodies.c"
|
||||||
|
|
|
@ -224,6 +224,14 @@
|
||||||
<Filter
|
<Filter
|
||||||
Name="util"
|
Name="util"
|
||||||
>
|
>
|
||||||
|
<File
|
||||||
|
RelativePath=".\util\argstack.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\util\argstack.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\util\attrib.c"
|
RelativePath=".\util\attrib.c"
|
||||||
>
|
>
|
||||||
|
@ -276,6 +284,14 @@
|
||||||
RelativePath=".\util\event.h"
|
RelativePath=".\util\event.h"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\util\eventbus.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\util\eventbus.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\util\filereader.c"
|
RelativePath=".\util\filereader.c"
|
||||||
>
|
>
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
#include "argstack.h"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#define ARGSTKSIZE 16
|
||||||
|
typedef struct arguments {
|
||||||
|
int n;
|
||||||
|
struct value {
|
||||||
|
int type;
|
||||||
|
union {
|
||||||
|
double number;
|
||||||
|
const char * str;
|
||||||
|
void * data;
|
||||||
|
} value;
|
||||||
|
} stack[ARGSTKSIZE];
|
||||||
|
} arguments;
|
||||||
|
|
||||||
|
void arg_init(struct arguments * arg) {
|
||||||
|
arg->n = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arg_done(struct arguments * arg) {
|
||||||
|
arg = arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arg_pushuserdata(struct arguments * arg, int type, void * data) {
|
||||||
|
assert(arg->n<ARGSTKSIZE);
|
||||||
|
arg->stack[arg->n].type = type;
|
||||||
|
arg->stack[arg->n].value.data = data;
|
||||||
|
++arg->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arg_pushstring(struct arguments * arg, const char * str) {
|
||||||
|
assert(arg->n<ARGSTKSIZE);
|
||||||
|
arg->stack[arg->n].type = ARG_TSTRING;
|
||||||
|
arg->stack[arg->n].value.str = str;
|
||||||
|
++arg->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void arg_pushnumber(struct arguments * arg, double number) {
|
||||||
|
assert(arg->n<ARGSTKSIZE);
|
||||||
|
arg->stack[arg->n].type = ARG_TSTRING;
|
||||||
|
arg->stack[arg->n].value.number = number;
|
||||||
|
++arg->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int arg_size(struct arguments * arg) {
|
||||||
|
return arg->n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void * arg_touserdata(struct arguments * arg, int idx, int type) {
|
||||||
|
assert(arg->n>idx && idx>=0);
|
||||||
|
assert(arg->stack[arg->n].type==type);
|
||||||
|
return arg->stack[arg->n].value.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
double arg_tonumber(struct arguments * arg, int idx) {
|
||||||
|
assert(arg->n>idx && idx>=0);
|
||||||
|
assert(arg->stack[arg->n].type==ARG_TNUMBER);
|
||||||
|
return arg->stack[arg->n].value.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * arg_tostring(struct arguments * arg, int idx) {
|
||||||
|
assert(arg->n>idx && idx>=0);
|
||||||
|
assert(arg->stack[arg->n].type==ARG_TSTRING);
|
||||||
|
return arg->stack[arg->n].value.str;
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
#ifndef UTIL_ARG_H
|
||||||
|
#define UTIL_ARG_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct arguments;
|
||||||
|
|
||||||
|
#define ARG_TNUMBER -1
|
||||||
|
#define ARG_TSTRING -2
|
||||||
|
|
||||||
|
void arg_init(struct arguments * arg);
|
||||||
|
void arg_done(struct arguments * arg);
|
||||||
|
|
||||||
|
void arg_push(struct arguments * arg, int type, void * data);
|
||||||
|
void arg_pushstring(struct arguments * arg, const char * str);
|
||||||
|
void arg_pushnumber(struct arguments * arg, double number);
|
||||||
|
|
||||||
|
int arg_size(struct arguments * arg);
|
||||||
|
void * arg_touserdata(struct arguments * arg, int idx, int type);
|
||||||
|
double arg_tonumber(struct arguments * arg, int idx);
|
||||||
|
const char * arg_tostring(struct arguments * arg, int idx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include <config.h>
|
||||||
|
#include "eventbus.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
** first iteration. it is slow, and a proof of the concept - the simplest
|
||||||
|
** thing that would work, a.k.a. should be refectored when required.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct listener {
|
||||||
|
struct listener * next;
|
||||||
|
event_handler callback;
|
||||||
|
event_arg_free destroy;
|
||||||
|
void * sender;
|
||||||
|
char * event;
|
||||||
|
void * arguments;
|
||||||
|
} listener;
|
||||||
|
|
||||||
|
static listener * listeners;
|
||||||
|
|
||||||
|
void
|
||||||
|
eventbus_fire(void * sender, const char * event, void * args)
|
||||||
|
{
|
||||||
|
listener * lst = listeners;
|
||||||
|
while (lst) {
|
||||||
|
int i = strcmp(lst->event, event);
|
||||||
|
if (i>0) break;
|
||||||
|
if (i==0) {
|
||||||
|
if (!lst->sender || lst->sender==sender) {
|
||||||
|
lst->callback(sender, event, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lst = lst->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eventbus_register(void * sender, const char * event, event_handler cb, event_arg_free arg_free, void * args)
|
||||||
|
{
|
||||||
|
listener * lst;
|
||||||
|
listener ** lstp = &listeners;
|
||||||
|
while (*lstp) {
|
||||||
|
lst = *lstp;
|
||||||
|
if (strcmp(lst->event, event)>=0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
lstp=&lst->next;
|
||||||
|
}
|
||||||
|
lst = malloc(sizeof(listener));
|
||||||
|
lst->sender = sender;
|
||||||
|
lst->arguments = args;
|
||||||
|
lst->callback = cb;
|
||||||
|
lst->destroy = arg_free;
|
||||||
|
lst->event = strdup(event);
|
||||||
|
lst->next = *lstp;
|
||||||
|
*lstp = lst;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* vi: set ts=2:
|
||||||
|
+-------------------+
|
||||||
|
| | Enno Rehling <enno@eressea.de>
|
||||||
|
| Eressea PBEM host | Katja Zedel <katze@felidae.kn-bremen.de>
|
||||||
|
| (c) 1998 - 2010 | Christian Schlittchen <corwin@amber.kn-bremen.de>
|
||||||
|
| |
|
||||||
|
+-------------------+
|
||||||
|
|
||||||
|
This program may not be used, modified or distributed
|
||||||
|
without prior permission by the authors of Eressea.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef H_UTIL_EVTBUS
|
||||||
|
#define H_UTIL_EVTBUS
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*event_handler)(void *, const char *, void *);
|
||||||
|
typedef void (*event_arg_free)(void *);
|
||||||
|
void eventbus_fire(void * sender, const char * event, void * args);
|
||||||
|
void eventbus_register(void * sender, const char * event, event_handler callback, event_arg_free arg_free, void * args);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -32,6 +32,21 @@ without prior permission by the authors of Eressea.
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_ext(attrib * a) {
|
init_ext(attrib * a) {
|
||||||
|
lua_State * L = (lua_State *)global.vm_state;
|
||||||
|
|
||||||
|
lua_pushstring(L, "callbacks");
|
||||||
|
lua_rawget(L, LUA_GLOBALSINDEX);
|
||||||
|
if (lua_istable(L, -1)) {
|
||||||
|
lua_pushstring(L, "attrib_init");
|
||||||
|
lua_rawget(L, LUA_GLOBALSINDEX);
|
||||||
|
if (lua_isfunction(L, -1)) {
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, a->data.i);
|
||||||
|
if (lua_pcall(L, 1, 0, 0)!=0) {
|
||||||
|
const char* error = lua_tostring(L, -1);
|
||||||
|
log_error(("attrib_init '%d': %s.\n", a->data.i, error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -993,6 +993,68 @@ int tolua_process_produce(lua_State* L) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct event_args {
|
||||||
|
int hfunction;
|
||||||
|
int hargs;
|
||||||
|
const char * sendertype;
|
||||||
|
} event_args;
|
||||||
|
|
||||||
|
static void args_free(void * udata)
|
||||||
|
{
|
||||||
|
free(udata);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void event_cb(void * sender, const char * event, void * udata) {
|
||||||
|
event_args * args = (event_args *)udata;
|
||||||
|
int nargs = 2;
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction);
|
||||||
|
if (sender && args->sendertype) {
|
||||||
|
tolua_pushusertype(L, sender, args->sendertype);
|
||||||
|
} else {
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
tolua_pushstring(L, event);
|
||||||
|
if (args->hargs) {
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, args->hfunction);
|
||||||
|
++nargs;
|
||||||
|
}
|
||||||
|
lua_pcall(L, nargs, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tolua_eventbus_register(lua_State * L)
|
||||||
|
{
|
||||||
|
/* parameters:
|
||||||
|
** 1: sender (usertype)
|
||||||
|
** 2: event (string)
|
||||||
|
** 3: handler (function)
|
||||||
|
** 4: arguments (any, *optional*)
|
||||||
|
*/
|
||||||
|
void * sender = tolua_tousertype(L, 1, 0);
|
||||||
|
const char * event = tolua_tostring(L, 2, 0);
|
||||||
|
event_args * args = malloc(sizeof(event_args));
|
||||||
|
|
||||||
|
args->sendertype = sender?tolua_typename(L, 1):NULL;
|
||||||
|
lua_pushvalue(L, 3);
|
||||||
|
args->hfunction = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
if (lua_type(L, 4)!=LUA_TNONE) {
|
||||||
|
lua_pushvalue(L, 4);
|
||||||
|
args->hargs = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
} else {
|
||||||
|
args->hargs = 0;
|
||||||
|
}
|
||||||
|
eventbus_register(sender, event, &event_cb, &args_free, args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
tolua_eventbus_fire(lua_State * L)
|
||||||
|
{
|
||||||
|
void * sender = tolua_tousertype(L, 1, 0);
|
||||||
|
const char * event = tolua_tostring(L, 2, 0);
|
||||||
|
eventbus_fire(sender, event, args);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
parse_inifile(lua_State* L, dictionary * d, const char * section)
|
parse_inifile(lua_State* L, dictionary * d, const char * section)
|
||||||
{
|
{
|
||||||
|
@ -1061,6 +1123,14 @@ tolua_eressea_open(lua_State* L)
|
||||||
}
|
}
|
||||||
tolua_endmodule(L);
|
tolua_endmodule(L);
|
||||||
|
|
||||||
|
tolua_module(L, TOLUA_CAST "eventbus", 1);
|
||||||
|
tolua_beginmodule(L, TOLUA_CAST "eventbus");
|
||||||
|
{
|
||||||
|
tolua_function(L, TOLUA_CAST "register", &tolua_eventbus_register);
|
||||||
|
tolua_function(L, TOLUA_CAST "fire", &tolua_eventbus_fire);
|
||||||
|
}
|
||||||
|
tolua_endmodule(L);
|
||||||
|
|
||||||
tolua_module(L, TOLUA_CAST "config", 1);
|
tolua_module(L, TOLUA_CAST "config", 1);
|
||||||
tolua_beginmodule(L, TOLUA_CAST "config");
|
tolua_beginmodule(L, TOLUA_CAST "config");
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<messages>
|
<messages>
|
||||||
|
<message name="alp_destroyed" section="events">
|
||||||
|
<type>
|
||||||
|
<arg name="region" type="region"/>
|
||||||
|
</type>
|
||||||
|
<text locale="de">Ein Alp starb in $region($region), ohne sein Ziel zu erreichen.</text>
|
||||||
|
<text locale="en">An alp died in $region($region) before reaching its target.</text>
|
||||||
|
</message>
|
||||||
<message name="nr_claims" section="nr">
|
<message name="nr_claims" section="nr">
|
||||||
<type>
|
<type>
|
||||||
<arg name="items" type="items"/>
|
<arg name="items" type="items"/>
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
callbacks = {}
|
||||||
|
|
||||||
|
callbacks["attrib_init"] = function(attr)
|
||||||
|
if attr.name ~= nil then
|
||||||
|
local init = callbacks["init_" .. attr.name]
|
||||||
|
if init ~=nil then
|
||||||
|
init(attr)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
callbacks = {}
|
||||||
|
|
||||||
function change_locales(localechange)
|
function change_locales(localechange)
|
||||||
for loc, flist in pairs(localechange) do
|
for loc, flist in pairs(localechange) do
|
||||||
for index, name in pairs(flist) do
|
for index, name in pairs(flist) do
|
||||||
|
|
|
@ -1,21 +1,37 @@
|
||||||
|
require "callbacks"
|
||||||
|
require "dumptable"
|
||||||
|
|
||||||
|
local function trigger_alp_destroyed(alp, event)
|
||||||
|
m = message.create("alp_destroyed")
|
||||||
|
m:set_region("region", alp.region)
|
||||||
|
m:send_faction(alp.faction)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function trigger_alp_dissolve(u, event, attr)
|
||||||
|
local alp = attr.alp
|
||||||
|
attr.alp.number = 0 -- kills the alp
|
||||||
|
end
|
||||||
|
|
||||||
|
local function init_alp(attr)
|
||||||
|
-- dumptable(attr)
|
||||||
|
eventbus.register(attr.alp, "destroy", trigger_alp_destroyed)
|
||||||
|
eventbus.register(attr.mage, "destroy", trigger_alp_dissolve, attr)
|
||||||
|
eventbus.register(attr.target, "destroy", trigger_alp_dissolve, attr)
|
||||||
|
end
|
||||||
|
|
||||||
|
callbacks["init_alp"] = init_alp
|
||||||
|
|
||||||
|
-- Spell: summon alp
|
||||||
function summon_alp(r, mage, level, force, params)
|
function summon_alp(r, mage, level, force, params)
|
||||||
local alp = unit.create(mage.faction, r, 1, "alp")
|
local alp = unit.create(mage.faction, r, 1, "alp")
|
||||||
local target = params[1]
|
local target = params[1]
|
||||||
alp:set_skill("stealth", 7)
|
alp:set_skill("stealth", 7)
|
||||||
alp.status = 5 -- FLEE
|
alp.status = 5 -- FLEE
|
||||||
a = attrib.create(alp, { type='alp', target=target })
|
attr = attrib.create(alp, { ['name'] = 'alp', ['target'] = target, ['alp'] = alp, ['mage'] = mage })
|
||||||
|
init_alp(attr)
|
||||||
|
msg = message.create("summon_alp_effect")
|
||||||
{
|
m:set_unit("mage", mage)
|
||||||
/* Wenn der Alp stirbt, den Magier nachrichtigen */
|
m:set_unit("alp", alp)
|
||||||
add_trigger(&alp->attribs, "destroy", trigger_unitmessage(mage,
|
m:set_unit("target", target)
|
||||||
"trigger_alp_destroy", MSG_EVENT, ML_INFO));
|
m:send_faction(mage.faction)
|
||||||
/* Wenn Opfer oder Magier nicht mehr existieren, dann stirbt der Alp */
|
|
||||||
add_trigger(&mage->attribs, "destroy", trigger_killunit(alp));
|
|
||||||
add_trigger(&opfer->attribs, "destroy", trigger_killunit(alp));
|
|
||||||
}
|
|
||||||
msg = msg_message("summon_alp_effect", "mage alp target", mage, alp, opfer);
|
|
||||||
r_addmessage(r, mage->faction, msg);
|
|
||||||
msg_release(msg);
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -25,8 +25,19 @@ end
|
||||||
|
|
||||||
module( "common", package.seeall, lunit.testcase )
|
module( "common", package.seeall, lunit.testcase )
|
||||||
|
|
||||||
|
function test_eventbus_fire()
|
||||||
|
local r = region.create(0, 0, "plain")
|
||||||
|
local f = faction.create("noreply@eressea.de", "human", "de")
|
||||||
|
local u = unit.create(f, r)
|
||||||
|
|
||||||
|
function compare_f(u, event, f)
|
||||||
|
assert_equal(u.faction, f)
|
||||||
|
end
|
||||||
|
eventbus.register(u, "weird", compare_f)
|
||||||
|
eventbus.fire(u, "weird", f)
|
||||||
|
end
|
||||||
|
|
||||||
function test_fleeing_units_can_be_transported()
|
function test_fleeing_units_can_be_transported()
|
||||||
free_game()
|
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local r1 = region.create(1, 0, "plain")
|
local r1 = region.create(1, 0, "plain")
|
||||||
local f1, f2 = two_factions()
|
local f1, f2 = two_factions()
|
||||||
|
@ -65,7 +76,6 @@ function test_plane()
|
||||||
end
|
end
|
||||||
|
|
||||||
function test_rename()
|
function test_rename()
|
||||||
free_game()
|
|
||||||
local r = region.create(0, 0, "plain")
|
local r = region.create(0, 0, "plain")
|
||||||
local f = faction.create("noreply@eressea.de", "human", "de")
|
local f = faction.create("noreply@eressea.de", "human", "de")
|
||||||
local u = unit.create(f, r)
|
local u = unit.create(f, r)
|
||||||
|
|
Loading…
Reference in New Issue