blob: e1fd51dbc513d4e40134d9ecd0e57973721d9d27 [file] [log] [blame]
// MorgenGrauen MUDlib
/** \file /secure/shadowmaster.c
* Objekt, welches eine Liste mit aktiven Shadows hat.
* Die simul_efun shadow() meldet das beschattende Objekt hier an. Nuetzlich,
* damit man als Magier endlich mal rauskriegen kann, welche Shadows es
* eigentlich gibt.
* \author Zesstra
* \date 07.08.2009
* \version $Id$
*/
/* Changelog:
*/
#pragma strong_types
#pragma no_clone
#pragma no_inherit
#pragma no_shadow
#pragma pedantic
#include <defines.h>
#include <wizlevels.h>
#define HOME(x) (__PATH__(0)+x)
/** shadows ist ein mapping, welches alle Schatten und ihre Opfer enthaelt.
*
* Struktur: Schatten als Schluessel (object) und Beschatteter (object) als
* Wert.
*/
private mapping shadows = ([]);
#ifndef DEBUG
#define DEBUG(x) if (find_player("zesstra"))\
tell_object(find_player("zesstra"),\
"SMDBG: "+x+"\n")
#endif
#define MEMORY "/secure/memory"
#define SHADOW_OK 1
#define SHADOW_ACCESS_DENIED -1
#define SHADOW_EXISTS -2
#define SHADOW_UNKNOWN -3
protected void create() {
mixed tmp;
seteuid(getuid());
if (mappingp(tmp=MEMORY->Load("Schatten"))) {
shadows = tmp;
DEBUG("Daten aus MEMORY geladen.\n");
}
else {
DEBUG("Keine Daten in MEMORY vorhanden - reinitialisiere.\n");
if (MEMORY->Save("Schatten", shadows) != 1)
raise_error("Konnte Daten nicht im Memory ablegen.\n");
}
}
/** Liefert einen String mit allen Schatten und beschatteten Objekten zurueck.
* @return string - Liste von Schatten und Opfern
*/
public void DumpShadows() {
if (extern_call() && !ELDER_SECURITY ) return 0;
string res = "";
foreach(object schatten, object opfer: shadows)
if (schatten && opfer)
res += sprintf("%O -> %O\n",schatten,opfer);
printf("Folgende Shadows sind bekannt: \n\n%s\n", res);
}
/** Findet zu einem beschatteten Objekt den zugehoerigen Schatten.
@param[in] object - ein beschattetes Objekt.
@return object - Den Schatten oder 0.
@sa FindShadowsObject(), QueryObject(), QueryInfo()
*/
public object FindShadow(object opfer) {
if (!objectp(opfer))
return 0;
foreach(object schatten, object victim: shadows) {
if (opfer == victim)
// Schatten gefunden.
return schatten;
}
return 0;
}
/** Findet zu einem Schatten das beschattete Objekt.
@param[in] object - ein beschattendes Objekt.
@return object - Das beschattete Objekt oder 0.
@sa FindShadow(), QueryObject(), QueryInfo()
*/
public object FindShadowedObject(object schatten) {
return shadows[schatten];
}
/** Gibt Schatten und Beschatteten zurueck, falls ob eines von beiden ist.
Ist ob ein Schatten oder ein beschattetes Objekt, wird ein Array aus
Objekten geliefert. Hierbei werden ggf. alle Objekte in der
Beschattungshierarchie geliefert, von der ob Bestandteil ist.
@param[in] object - ein Objekt.
@return object* - ({a, b, c, d}) oder 0.
@sa FindShadow(), FindShadowedObject, QueryInfo()
*/
public object* QueryObject(object ob) {
if (!objectp(ob)) return 0;
object *res = ({ob});
object sh = FindShadow(ob);
while(sh) {
// es gibt einen Schatten, also Kette nach oben verfolgen.
res = ({sh}) + res;
sh = FindShadow(sh);
}
object vic = FindShadowedObject(ob);
while(vic) {
// es gibt ein beschattetes Objekt, Kette nach unten verfolgen.
res = res + ({vic});
vic = FindShadowedObject(vic);
}
if (sizeof(res) < 2) {
// Offenbar wird ob weder beschattet noch beschattet selber.
// Moeglicherweise wurde jedoch durch wilde Zerstoerung die Hierarchie
// getrennt. Falls ob nen Schatten ist, laesst sich das reparieren. Falls
// ob beschattet wird, hilft eigentlich nur ein reset(). Den moechte ich
// hier aber nicht machen, weils u.U. teuer sein koennte.
if (query_shadowing(ob)) {
shadows[ob] = query_shadowing(ob);
// nochmal.
return QueryObject(ob);
}
// scheinbar nicht.
return 0;
}
return res;
}
/** Gibt einen String mit Infos ueber ob zurueck.
Ist ob ein beschattetes Objekt oder ein Schatten, wird ein beschreibender
String zurueckgeliefert (schatten -> beschattetes Objekt). Hierbei wird ggf.
die gesamte Beschattungshierarchie angegeben (a -> b -> c -> d).
@param[in] object - ein Objekt.
@return string - String mit Infos ueber ob.
@sa FindShadow(), FindShadowedObject(), QueryObject()
*/
public string QueryInfo(object ob) {
object *shs = QueryObject(ob);
if (!shs) return 0;
return CountUp(map(shs, #'object_name), " -> ", " -> ");
}
/** Registriert einen Schatten und sein Opfer.
Registriert den Schatten und sein Opfer. Sollte ausschliesslich durch die
simul_efun oder spare_simul_fun gerufen werden.
@sa UnregisterShadow()
*/
public int RegisterShadow(object schatten) {
object opfer;
//DEBUG(sprintf("[%O] %O\n", schatten, caller_stack()));
// Irgendein Sicherheitscheck ist eigentlich nicht noetig hier, da das Opfer
// ohnehin per efun ermittelt wird und kein Eintrag erfolgt, wenn kein
// beschattetes Objekt zu finden ist.
// das von schatten beschattete Objekt ermitteln
if (objectp(opfer=query_shadowing(schatten))) {
if (shadows[schatten] == opfer)
return SHADOW_EXISTS;
// Neueintrag oder ggf. auch Aendern.
shadows[schatten] = opfer;
//DEBUG(DumpShadows());
return SHADOW_OK;
}
return SHADOW_ACCESS_DENIED;
}
/** Traegt einen Schatten wieder aus.
Der Schatten wird wieder ausgetragen. Sollte ausschliesslich durch die
simul_efun oder spare_simul_fun gerufen werden.
Werden Schatten oder beschattete Objekte zerstoert ohne vorher die
Schattierung zu beenden, fuehrt dies zu Inkonsistenzen und zerbrochenen
Beschattungshierarchien.
@sa RegisterShadow(), UnregisterOpfer()
*/
public int UnregisterShadow(object caller) {
object schatten, opfer;
// Ein Sicherheitscheck fuer den Aufruf ist eigentlich nicht noetig, da ein
// Eintrag nur entfernt wird, wenn die Beschattung nachweislich beendet
// wurde.
//DEBUG(sprintf("[%O] %O\n", caller, caller_stack()));
if (!objectp(caller)) return SHADOW_UNKNOWN;
// Schatten und beschatteten aus den lokalen Daten ermitteln.
if (member(shadows, caller)) {
schatten = caller;
opfer = shadows[schatten];
}
else if (objectp(schatten = FindShadow(caller))) {
opfer = caller;
}
// wenn nicht bekannt, ist jetzt eh Ende.
if (!schatten) return SHADOW_UNKNOWN;
//DEBUG(sprintf("%O -> %O (%O, %O)\n",
// schatten, opfer, caller, query_shadowing(schatten)));
// Schattierung wirklich beendet? Wenn nicht -> Ende
if (opfer && query_shadowing(schatten) == opfer)
return SHADOW_ACCESS_DENIED;
// war schatten in einer Beschattungshierarchie?
object up = FindShadow(schatten);
if (up && query_shadowing(up) == opfer) {
shadows[up] = opfer; // Kette neu verlinken
}
// jetzt kann geloescht werden.
m_delete(shadows,schatten);
return SHADOW_OK;
}
public int ResetAll() {
if (!ARCH_SECURITY) return SHADOW_ACCESS_DENIED;
DEBUG("ResetAll() called.\n");
shadows = ([]);
if (MEMORY->Save("Schatten", shadows) != 1)
raise_error("Konnte Daten nicht im Memory ablegen.\n");
return SHADOW_OK;
}
/** Raeumt die Daten ueber die Schatten auf.
Zerstoeren sich beschattete Objekte, werden die Schatten nicht
ausgetragen, daher wird das von zeit zu zeit hier gemacht.
*/
public void reset() {
foreach(object schatten, object opfer: shadows) {
if (!objectp(opfer)) {
// war schatten evtl. in einer Hierarchie und beschattet jetzt was
// anderes?
if (query_shadowing(schatten))
shadows[schatten] = query_shadowing(schatten);
else
m_delete(shadows, schatten);
}
}
}