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/util/attrib.c"
|
||||
#include "common/util/argstack.c"
|
||||
#include "common/util/base36.c"
|
||||
#include "common/util/crmessage.c"
|
||||
#include "common/util/cvector.c"
|
||||
#include "common/util/dice.c"
|
||||
#include "common/util/event.c"
|
||||
#include "common/util/eventbus.c"
|
||||
#include "common/util/filereader.c"
|
||||
#include "common/util/functions.c"
|
||||
#include "common/util/goodies.c"
|
||||
|
|
|
@ -224,6 +224,14 @@
|
|||
<Filter
|
||||
Name="util"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\util\argstack.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\argstack.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\attrib.c"
|
||||
>
|
||||
|
@ -276,6 +284,14 @@
|
|||
RelativePath=".\util\event.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\eventbus.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\util\eventbus.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
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
|
||||
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
|
||||
|
|
|
@ -993,6 +993,68 @@ int tolua_process_produce(lua_State* L) {
|
|||
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
|
||||
parse_inifile(lua_State* L, dictionary * d, const char * section)
|
||||
{
|
||||
|
@ -1061,6 +1123,14 @@ tolua_eressea_open(lua_State* 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_beginmodule(L, TOLUA_CAST "config");
|
||||
{
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<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">
|
||||
<type>
|
||||
<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)
|
||||
for loc, flist in pairs(localechange) 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)
|
||||
local alp = unit.create(mage.faction, r, 1, "alp")
|
||||
local target = params[1]
|
||||
alp:set_skill("stealth", 7)
|
||||
alp.status = 5 -- FLEE
|
||||
a = attrib.create(alp, { type='alp', target=target })
|
||||
|
||||
|
||||
{
|
||||
/* Wenn der Alp stirbt, den Magier nachrichtigen */
|
||||
add_trigger(&alp->attribs, "destroy", trigger_unitmessage(mage,
|
||||
"trigger_alp_destroy", MSG_EVENT, ML_INFO));
|
||||
/* 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);
|
||||
|
||||
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)
|
||||
m:set_unit("alp", alp)
|
||||
m:set_unit("target", target)
|
||||
m:send_faction(mage.faction)
|
||||
end
|
||||
|
|
|
@ -25,8 +25,19 @@ end
|
|||
|
||||
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()
|
||||
free_game()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local r1 = region.create(1, 0, "plain")
|
||||
local f1, f2 = two_factions()
|
||||
|
@ -65,7 +76,6 @@ function test_plane()
|
|||
end
|
||||
|
||||
function test_rename()
|
||||
free_game()
|
||||
local r = region.create(0, 0, "plain")
|
||||
local f = faction.create("noreply@eressea.de", "human", "de")
|
||||
local u = unit.create(f, r)
|
||||
|
|
Loading…
Reference in New Issue