mirror of
git://git.psyced.org/git/psyced
synced 2024-08-15 03:25:10 +00:00
let the past begone in cvs land. welcome to igit igit!
This commit is contained in:
commit
4e601cf1c7
509 changed files with 77963 additions and 0 deletions
373
world/net/group/master.c
Normal file
373
world/net/group/master.c
Normal file
|
@ -0,0 +1,373 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: master.c,v 1.142 2008/02/24 16:36:59 lynx Exp $
|
||||
//
|
||||
// this is a simpler version of group/master, and it is actually in use
|
||||
// [actual as in effectively, not current, which is the german meaning]
|
||||
//
|
||||
// part of the implementation of PSYC multicasting.. send stuff back where
|
||||
// the _enter came from, send just one copy no matter how many have entered
|
||||
// from there. the group/slave will take care of the other side.
|
||||
//
|
||||
// group/master and group/slave are used for smaller size rooms, where each
|
||||
// person present should be visible. if you need a large scale multicast
|
||||
// solution, build up a link network using place/master and place/slave.
|
||||
//
|
||||
// see http://about.psyc.eu/Routing for the big picture on routing.
|
||||
//
|
||||
// should we rename the directories into net/context/master and slave, since a
|
||||
// context sounds more abstract than a group? i wouldn't say that a user's
|
||||
// context delivering presence subscriptions is a "group", but it certainly
|
||||
// is a "context."
|
||||
|
||||
#include <net.h>
|
||||
#include <person.h>
|
||||
#include <status.h>
|
||||
#include <url.h>
|
||||
|
||||
#ifdef CONTEXT_STATE // {{{
|
||||
# define HEADER_ONLY
|
||||
# include "../state.c"
|
||||
# undef HEADER_ONLY
|
||||
#endif // }}}
|
||||
|
||||
inherit NET_PATH "entity";
|
||||
|
||||
#ifdef HISTORY_COUNT
|
||||
int _ccount; // persistent!
|
||||
#endif
|
||||
|
||||
// these data structures are allocated for every single place and user
|
||||
// as route is used by all of them to do presence or general smarticasting.
|
||||
#ifdef PERSISTENT_MASTERS
|
||||
mapping _routes;
|
||||
#else
|
||||
volatile mapping _routes, _u;
|
||||
#endif
|
||||
|
||||
#ifdef CONTEXT_STATE // {{{
|
||||
volatile mapping _costate, _cmemory;
|
||||
volatile mapping ctemp, cunused;
|
||||
#endif // }}}
|
||||
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
int revision; // persistent revision counter
|
||||
#endif
|
||||
|
||||
stoned();
|
||||
|
||||
// used by /routes and /reload
|
||||
routes(recover) {
|
||||
if (recover) {
|
||||
PT(("%O recovering routes %O\n", ME, recover))
|
||||
ASSERT("routes() recovering", mappingp(recover), recover)
|
||||
_routes = recover;
|
||||
}
|
||||
return _routes;
|
||||
}
|
||||
|
||||
create() {
|
||||
_routes = ([ ]);
|
||||
#ifdef HISTORY_COUNT
|
||||
_ccount = 0;
|
||||
#endif
|
||||
#ifdef CONTEXT_STATE // {{{
|
||||
_costate = ([ ]);
|
||||
ctemp = ([ ]);
|
||||
_cmemory = m_allocate(0, 2);
|
||||
#endif // }}}
|
||||
::create();
|
||||
}
|
||||
|
||||
// der castmsg muss irgendwie anders.. sonst kriegen wir den state nicht hin.
|
||||
castmsg(source, mc, data, vars) {
|
||||
mixed route;
|
||||
mixed noa; // Nickname of local user Or Amount of people on route
|
||||
// in TIDILY mode should be Mapping of people on route
|
||||
#ifdef FORK // {{{
|
||||
string buf;
|
||||
|
||||
// as ldmud isn't a threading enviroment there shouldn't be a chance of
|
||||
// psycd getting destructed while we're residing in this function.
|
||||
// so we're ensuring its existence only once.
|
||||
#endif // }}}
|
||||
|
||||
P2(("%O castmsg(%O,%O,%O..) for %O\n", ME, source,mc,data, _routes))
|
||||
D3(P2(("%O vars = %O\n", ME, vars)))
|
||||
// _context is an MMP variable, so we use it internally with objectp
|
||||
vars["_context"] = ME;
|
||||
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
vars["_number_revision"] = revision;
|
||||
#endif
|
||||
|
||||
// in theory.. m_delete(vars, "_source") but not necessary
|
||||
m_delete(vars, "_target");
|
||||
#ifdef HISTORY_COUNT
|
||||
vars["_count"] = _ccount++; // wraps at MAXINT.. right? hehe
|
||||
#endif
|
||||
|
||||
foreach (route, noa : _routes) {
|
||||
#if defined(TIDILY) && defined(MEMBERS_BY_SOURCE)
|
||||
P3(("place:each(%O,t=%O,s=%O,mc=%O,d=%O,v=%O)\n",
|
||||
mappingp(noa) ? sizeof(noa) : noa, route, source, mc,
|
||||
data, vars))
|
||||
#else
|
||||
P3(("place:each(%O,t=%O,s=%O,mc=%O,d=%O,v=%O)\n",
|
||||
noa, route, source, mc, data, vars))
|
||||
#endif
|
||||
// if (route == source) return; // skip sender
|
||||
if (!route) {
|
||||
if (stringp(noa)) {
|
||||
// object has been destructed
|
||||
// maybe there's a new one
|
||||
if (route = find_person(noa)) {
|
||||
#ifndef PERSISTENT_MASTERS
|
||||
#ifdef MEMBERS_BY_NICK
|
||||
_u[noa] = route;
|
||||
#else
|
||||
_u[route] = noa;
|
||||
#endif
|
||||
#else
|
||||
P1(("%O lost route to %O\n", ME, noa))
|
||||
#endif
|
||||
} else {
|
||||
// why source? that's silly!
|
||||
call_out(#'stoned, 1, source, noa);
|
||||
continue; // oops! why was this a return; !???
|
||||
}
|
||||
} else { // if (mappingp/intp(noa)) // noa contains (_amount_)members
|
||||
monitor_report("_failure_destruct_circuit",
|
||||
psyctext("[_nick_place] detected the loss "
|
||||
"of a circuit with [_amount_members] "
|
||||
"members.",
|
||||
([ "_nick_place" : MYNICK,
|
||||
#if defined(TIDILY) && defined(MEMBERS_BY_SOURCE)
|
||||
"_amount_members" : sizeof(noa),
|
||||
#else
|
||||
"_amount_members" : noa,
|
||||
#endif
|
||||
])));
|
||||
m_delete(_routes, route);
|
||||
}
|
||||
}
|
||||
P4(("group/master sees vars as %O\n", vars))
|
||||
// btw, fippo, could you please resume what happens if we
|
||||
// try not to copy(vars) ? i like docs in the middle of source
|
||||
// that give me a reason not to break it ;)
|
||||
if (objectp(route)) {
|
||||
route -> msg(source, mc, data, copy(vars));
|
||||
} else {
|
||||
// gateways to other schemes please make their own
|
||||
// copy of the vars if they need to mess with them.
|
||||
sendmsg(route, mc, data, vars, source);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if 0 //def PERSISTENT_MASTERS
|
||||
protected load(file) {
|
||||
::load(file);
|
||||
DT(if (sizeof(_routes))
|
||||
PP(("Found routes in %O: %O\n", ME, _routes || "nothing"));)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(TIDILY) && defined(MEMBERS_BY_SOURCE)
|
||||
# define RM(SOURCE, ORIGIN) \
|
||||
m_delete(_routes[ORIGIN], SOURCE); \
|
||||
unless (sizeof(_routes[ORIGIN])) m_delete(_routes, ORIGIN);
|
||||
#else
|
||||
# define RM(SOURCE, ORIGIN) \
|
||||
if (_routes[ORIGIN]) \
|
||||
unless (--_routes[ORIGIN]) m_delete(_routes, ORIGIN);
|
||||
#endif
|
||||
|
||||
remove_member(source, origin) {
|
||||
mixed t;
|
||||
P2(("%O remove_member(%O, %O)\n", ME, source, origin))
|
||||
if (origin && (
|
||||
#if 1 //defined(TIDILY) && defined(MEMBERS_BY_SOURCE)
|
||||
stringp(t = origin) ||
|
||||
#endif
|
||||
t = origin->qOrigin())
|
||||
#ifdef FORK
|
||||
&& t += "/$cslave"
|
||||
#endif
|
||||
&& member(_routes, t)) {
|
||||
RM(source, t);
|
||||
} else if (member(_routes, source)) {
|
||||
// local object or xmpp user
|
||||
m_delete(_routes, source);
|
||||
} else if (stringp(source)) {
|
||||
// guessing route from hostname of psyc address
|
||||
// try to avoid using remove_member() without origin
|
||||
// but this becomes necessary when we want to
|
||||
// remove an object or route manually
|
||||
mixed u;
|
||||
|
||||
if (u = find_target_handler(source)) {
|
||||
t = u->qOrigin();
|
||||
RM(source, t);
|
||||
P1((
|
||||
"%O guessing origin %O for %O, successful? routes are %O\n",
|
||||
ME, t, source, _routes))
|
||||
} else {
|
||||
t = 0;
|
||||
if (u = parse_uniform(source)) t = u[URoot];
|
||||
unless (t) t = source;
|
||||
/*
|
||||
<fippo> das hier geschah, als ich bei frischgestartetem server mit einem remote
|
||||
jabberisten die freundschaft zum user#fippo entfernte:
|
||||
EXCEPTION at line 185 of net/group/master.c in object net/psyc/user#fippo:
|
||||
Bad arg 1 to m_delete(): got 'number', expected 'mapping'.
|
||||
<lynX> die datenstruktur war nicht initialisiert? da muss doch vorher schon
|
||||
an anderer stelle was schiefgelaufen sein...?
|
||||
*/
|
||||
RM(source, t);
|
||||
P1((
|
||||
"%O parsing origin %O from %O, successful? routes are %O\n",
|
||||
ME, t, source, _routes))
|
||||
}
|
||||
} else {
|
||||
// happens when doing /unfr. must be a bug in user.c
|
||||
P0(("%O encountered unnecessary remove of %O from %O\n",
|
||||
ME, source, _routes))
|
||||
}
|
||||
}
|
||||
|
||||
insert_member(source, origin) {
|
||||
mixed t;
|
||||
P2(("%O insert_member(%O, %O)\n", ME, source, origin))
|
||||
if (objectp(origin) && (t = origin->qOrigin())) {
|
||||
#ifdef FORK
|
||||
t = t + "/$cslave";
|
||||
#endif
|
||||
#if defined(TIDILY) && defined(MEMBERS_BY_SOURCE)
|
||||
unless (member(_routes, t)) _routes[t] = m_allocate(1, 0);
|
||||
m_add(_routes[t], source);
|
||||
#else
|
||||
_routes[t]++;
|
||||
#endif
|
||||
} else if (stringp(origin)) {
|
||||
#ifdef FORK
|
||||
origin = origin + "/$cslave";
|
||||
#endif
|
||||
#if defined(TIDILY) && defined(MEMBERS_BY_SOURCE)
|
||||
unless (member(_routes, origin)) _routes[origin] = m_allocate(1, 0);
|
||||
m_add(_routes[origin], source);
|
||||
#else
|
||||
_routes[origin]++;
|
||||
#endif
|
||||
} else {
|
||||
#ifdef PERSISTENT_MASTERS
|
||||
_routes[source] = 1; // gimme the nick
|
||||
#else
|
||||
_routes[source] = 1; // castmsg expects the nick here. duh.
|
||||
// should we do that for objectp(source)?
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
// would be nice to do it here, but that's not correct
|
||||
//revision += 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
// code duplicaton is faster than others
|
||||
#ifdef CONTEXT_STATE // {{{
|
||||
//
|
||||
// <lynX> code duplication is okay for enhanced efficiency, but please not
|
||||
// by mouse pasting. use #include "shared_code.i" please. TODO.
|
||||
// you can even ifdef small differences of the two versions!
|
||||
//
|
||||
int outstate(string target, string key, mixed value, int hascontext) {
|
||||
int mod;
|
||||
|
||||
unless (hascontext)
|
||||
return ::outstate(target, key, value, hascontext);
|
||||
|
||||
if (key[0] == '_') {
|
||||
mod = ':';
|
||||
} else {
|
||||
mod = key[0];
|
||||
key = key[1..];
|
||||
}
|
||||
|
||||
unless (ctemp) ctemp = ([ ]);
|
||||
|
||||
unless (cunused) cunused = copy(_costate);
|
||||
m_delete(cunused, key);
|
||||
|
||||
switch(mod) {
|
||||
case ':':
|
||||
if (_cmemory[key, 1] == -1) break;
|
||||
if (member(_cmemory, key)) {
|
||||
if (_cmemory[key] == value) {
|
||||
if (_cmemory[key, 1] == STATE_MAX2) {
|
||||
break;
|
||||
}
|
||||
if (_cmemory[key, 1] == STATE_MIN2) {
|
||||
ctemp["="+key] = value;
|
||||
_costate[key] = value;
|
||||
return 0;
|
||||
}
|
||||
_cmemory[key, 1]++;
|
||||
} else if (_cmemory[key, 1] - 1 == STATE_MIN2) {
|
||||
ctemp["="+key] = "";
|
||||
m_add(_cmemory, key, value, 1);
|
||||
} else if (_cmemory[key, 1] <= STATE_MIN2) {
|
||||
m_add(_cmemory, key, value, 1);
|
||||
} else _cmemory[key, 1]--;
|
||||
} else m_add(_cmemory, key, value, 1);
|
||||
break;
|
||||
case '=':
|
||||
if ("" == value) {
|
||||
m_delete(_costate, key);
|
||||
break;
|
||||
}
|
||||
if (member(_costate, key) && _costate[key] == value) {
|
||||
return 0;
|
||||
}
|
||||
m_add(_cmemory, key, value, -1);
|
||||
_costate[key] = value;
|
||||
break;
|
||||
case '+':
|
||||
_augment(_costate, key, value);
|
||||
break;
|
||||
case '-':
|
||||
_diminish(_costate, key, value);
|
||||
break;
|
||||
default:
|
||||
raise_error("Illegal variable modifier in '" + key +
|
||||
"' encountered in group/master:outstate.\n");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
mapping state(string target, int hascontext) {
|
||||
mapping t2 = ([ ]), t;
|
||||
|
||||
unless (hascontext) return ::state(target, hascontext);
|
||||
|
||||
if (cunused) {
|
||||
foreach (string key : cunused) {
|
||||
t2[":" + key] = "";
|
||||
}
|
||||
|
||||
cunused = 0;
|
||||
}
|
||||
|
||||
t = ctemp;
|
||||
ctemp = ([ ]);
|
||||
|
||||
// rock hard optimization
|
||||
unless (sizeof(t))
|
||||
return t2;
|
||||
unless (sizeof(t2))
|
||||
return t;
|
||||
return t2 + t;
|
||||
}
|
||||
|
||||
#endif // }}}
|
263
world/net/group/slave.c
Normal file
263
world/net/group/slave.c
Normal file
|
@ -0,0 +1,263 @@
|
|||
// vim:foldmethod=marker:syntax=lpc:noexpandtab
|
||||
// $Id: slave.c,v 1.58 2008/03/21 12:35:40 lynx Exp $
|
||||
//
|
||||
// generic context slave as described in a posting to psyc-dev years ago.
|
||||
// it receives the single copy of a message sent out by the group master
|
||||
// and fans it out to local recipients. that's why local recipients need
|
||||
// to create and join this manager when they enter a room.
|
||||
//
|
||||
#include <net.h>
|
||||
#include <presence.h>
|
||||
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
# define PARANOID_PERSISTENT_SLAVES
|
||||
# include <url.h>
|
||||
inherit NET_PATH "storage";
|
||||
|
||||
private volatile string _file;
|
||||
|
||||
private string *_save_members;
|
||||
private string _name;
|
||||
private int _revision = -1;
|
||||
#endif
|
||||
|
||||
#ifdef CONTEXT_STATE
|
||||
private volatile mapping cast_state;
|
||||
private volatile mapping temp_state;
|
||||
inherit NET_PATH "state";
|
||||
#endif
|
||||
|
||||
private volatile mapping _members;
|
||||
|
||||
void create() {
|
||||
unless(mappingp(_members)) _members = ([ ]);
|
||||
#ifdef CONTEXT_STATE
|
||||
unless(mappingp(cast_state)) cast_state = ([ ]);
|
||||
unless(mappingp(temp_state)) temp_state = ([ ]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
varargs void load(string context, array(mixed) u) {
|
||||
string dir = DATA_PATH "slaves/";
|
||||
string entity;
|
||||
|
||||
unless (u) u = parse_uniform(context);
|
||||
dir += u[UHost];
|
||||
if (u[UPort]) dir += "-"+ u[UPort];
|
||||
mkdir(dir); // make sure that directory exists
|
||||
_name = context;
|
||||
entity = u[UUser] || u[UResource];
|
||||
_file = dir +"/"+ (entity? sha1(entity): "_");
|
||||
::load(_file);
|
||||
foreach (string m : _save_members) {
|
||||
object o = summon_person(m[1..]);
|
||||
_members[o] = m;
|
||||
}
|
||||
P4(("loaded cslave %O with %O\n", _name, _members))
|
||||
}
|
||||
|
||||
protected save() {
|
||||
P4(("cslave:save() %O\n", _members))
|
||||
unless (_file) return;
|
||||
if (sizeof(_members) == 0) {
|
||||
rm(_file);
|
||||
_revision = -1;
|
||||
// FIXME: could clean up directory if it is empty
|
||||
} else {
|
||||
_save_members = m_values(_members);
|
||||
::save(_file);
|
||||
}
|
||||
}
|
||||
|
||||
# ifndef PARANOID_PERSISTENT_SLAVES
|
||||
remove() {
|
||||
if (_file) save(_file);
|
||||
}
|
||||
|
||||
reset() {
|
||||
if (_file) save(_file);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
void insert_member(mixed member, mixed origin, mixed data) {
|
||||
P4(("%O enters cslave\n", member))
|
||||
// we use the values from the members mapping as counters
|
||||
// for their individual psyc-state
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
_members[member] = member->psycName();
|
||||
#else
|
||||
_members[member] = 0;
|
||||
#endif
|
||||
#ifdef CONTEXT_STATE
|
||||
if (stringp(member)) {
|
||||
mapping v = ([ ]);
|
||||
|
||||
// this is not how we do it
|
||||
// foreach(string key, mixed value : cast_state)
|
||||
// v["="+key] = value;
|
||||
// no var ops embedded in sendmsg.
|
||||
|
||||
sendmsg(member, 0, 0, v + ([ "_context" : ME , "_target" : member ]));
|
||||
}
|
||||
#endif
|
||||
#ifdef PARANOID_PERSISTENT_SLAVES
|
||||
// paranoid slaves
|
||||
save();
|
||||
#endif
|
||||
}
|
||||
|
||||
void remove_member(mixed member, mixed origin) {
|
||||
PT(("%O leaves context slave\n", member))
|
||||
m_delete(_members, member);
|
||||
|
||||
#ifdef PARANOID_PERSISTENT_SLAVES
|
||||
save();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FORK
|
||||
msg(source, method, data, mapping vars) {
|
||||
#else
|
||||
castmsg(source, method, data, mapping vars) {
|
||||
#endif
|
||||
/*
|
||||
* implement group manager logic
|
||||
* and fan out everything else?
|
||||
* fan out could happen here and group manager handled by
|
||||
* higher level objects
|
||||
*/
|
||||
mixed o;
|
||||
#ifdef XMPPERIMENTAL
|
||||
PT(("%O group slave _routes is %O\n", ME, _members))
|
||||
#else
|
||||
P3(("%O group slave msg(%O, %O, ...)\n", ME, source, method))
|
||||
#endif
|
||||
#ifdef CACHE_PRESENCE
|
||||
// before lynX starts complaining:
|
||||
// we could cache the presenity value here
|
||||
if (vars["_degree_availability"])
|
||||
persistent_presence(source, vars["_degree_availability"]);
|
||||
//, vars["_degree_mood"]);
|
||||
# if 0 // else? why should we have presence without _degree_availability ?
|
||||
else switch(method) {
|
||||
case "_notice_presence_here":
|
||||
persistent_presence(source, AVAILABILITY_HERE);
|
||||
break;
|
||||
case "_notice_presence_here_busy":
|
||||
persistent_presence(source, AVAILABILITY_BUSY);
|
||||
break;
|
||||
case "_notice_presence_away":
|
||||
case "_notice_presence_away_manual":
|
||||
case "_notice_presence_away_automatic":
|
||||
persistent_presence(source, AVAILABILITY_AWAY);
|
||||
break;
|
||||
case "_notice_presence_absent_vacation":
|
||||
persistent_presence(source, AVAILABILITY_VACATION);
|
||||
break;
|
||||
case "_notice_presence_absent":
|
||||
persistent_presence(source, AVAILABILITY_OFFLINE);
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PERSISTENT_SLAVES
|
||||
/* the lazy update strategy */
|
||||
if (vars["_number_revision"] && !intp(vars["_number_revision"]))
|
||||
vars["_number_revision"] = to_int(vars["_number_revision"]);
|
||||
if (vars["_number_revision"] && _revision != vars["_number_revision"]) {
|
||||
int delta;
|
||||
/* initialize */
|
||||
if (_revision == -1) {
|
||||
_revision = vars["_number_revision"];
|
||||
} else {
|
||||
delta = vars["_number_revision"] - _revision;
|
||||
/* counter increment */
|
||||
if (delta == 1) {
|
||||
_revision = vars["_number_revision"];
|
||||
} else if (delta > 1 || delta < 1) {
|
||||
P0(("warning: %O revision mismatch! have %O, master has %O, delta is %d\n",
|
||||
_name, _revision, vars["_number_revision"], delta))
|
||||
monitor_report("_failure_slave_revision",
|
||||
object_name(ME) +" · "+ sprintf("revision mismatch with delta %d", delta));
|
||||
|
||||
// TODO
|
||||
// for now, we just log and accept those
|
||||
_revision = vars["_number_revision"];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vars["_number_revision"] > 0) {
|
||||
PT(("%O (%s) counter revision is %O\n", ME, method, vars["_number_revision"]))
|
||||
}
|
||||
m_delete(vars, "_number_revision");
|
||||
#endif
|
||||
foreach(o : _members) {
|
||||
if (objectp(o))
|
||||
#ifdef CONTEXT_STATE
|
||||
// may need copy(vars) also
|
||||
o -> msg(source, method, data, cast_state + vars );
|
||||
else
|
||||
sendmsg(o, method, data, vars + temp_state, source);
|
||||
#else
|
||||
o -> msg(source, method, data, copy(vars));
|
||||
else
|
||||
sendmsg(o, method, data, vars, source);
|
||||
#endif
|
||||
/* if one or more of our local users have joined this
|
||||
* place, we trust the place and allow it to use us as
|
||||
* a relay for people who are topologically close to us.
|
||||
* that's how remote users may end up in this structure, too.
|
||||
*/
|
||||
}
|
||||
#ifdef CONTEXT_STATE
|
||||
temp_state = ([ ]);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONTEXT_STATE // {{{
|
||||
// This won't work ... we have to have _one_ single cast-state
|
||||
// which is synced with objects entering the context..
|
||||
//
|
||||
// TODO
|
||||
|
||||
void Reset(mixed source) {
|
||||
cast_state = ([ ]);
|
||||
foreach(mixed o : _members) {
|
||||
unless (objectp(o))
|
||||
sendmsg(o, 0, 0, ([ "_count" : _members[o] = 0 ]), source);
|
||||
}
|
||||
}
|
||||
|
||||
void Assign(mixed source, string key, mixed value) {
|
||||
|
||||
// we have to check here for source == our context
|
||||
// + we expect msg to be called between state-changes from different
|
||||
// packets to reset temp_state
|
||||
|
||||
if (stringp(value) && value == "" )
|
||||
m_delete(cast_state, key);
|
||||
else
|
||||
cast_state[key] = value;
|
||||
|
||||
temp_state["="+key] = value;
|
||||
}
|
||||
|
||||
void Augment(mixed source, string key, mixed value) {
|
||||
_augment(cast_state, key, value);
|
||||
_augment(temp_state, "+"+key, value);
|
||||
}
|
||||
|
||||
void Diminish(mixed source, string key, mixed value) {
|
||||
int i;
|
||||
|
||||
_diminish(cast_state, key, value);
|
||||
if (member(temp_state, "-"+key)) {
|
||||
PT(("PANIC! Received list-diminish as a list!"))
|
||||
} else temp_state["-"+key] = value;
|
||||
}
|
||||
|
||||
#endif // }}}
|
Loading…
Add table
Add a link
Reference in a new issue