blob: 06592bfcb1aa813f1b0cf3d2bf7dd3c5c303ca68 [file] [log] [blame]
// MorgenGrauen MUDlib
//
// thing/properties.c -- most general class (property handling)
//
// $Id: properties.c 6951 2008-08-09 23:08:31Z Zesstra $
// Properties.c -- Propertyverwaltung
// (c) 1993 Hate@MorgenGrauen, Mateese@NightFall
// Idea and Code Flames and Destructions
// -> *grin* thats the point actually :)
//
// Ueberarbeitet von Jof am 12.06.1994
// Ueberarbeitet von Mandragon am 11.05.2003
#pragma strict_types
#pragma save_types
#pragma range_check
#pragma no_clone
#pragma pedantic
#define NEED_PROTOTYPES
#include "/sys/thing/properties.h"
#include "/secure/wizlevels.h"
// the mapping where the actual properties are stored. Direct initialization.
private nosave mapping *prop = ({ ([]), ([]), ([]), ([]) });
// the mapping that is used for saving
private mapping properties;
// security-flag
private nosave int closure_call;
// Initialisierung der Props. Kann leider momentan nicht private sein, weil
// Padreic son komisches Objekt hat, was die Funktion hier ruft.
// TODO: irgendwann mal private machen.
// TODO: Da props jetzt einfach bei der Deklaration initlisiert wird,
// eruebrigt sich diese Funktion eigentlich. Bis auf Padreics Objekt...
protected void InitializeProperties() {
prop = ({ ([]), ([]), ([]), ([]) });
return;
}
// Props nur dann initialisieren, wenn sie es noch nicht sind
protected void create() {
// Blueprints in /std benoetigenkeinen Reset ....
if (object_name()=="/std/thing/properties")
set_next_reset(-1);
}
protected void create_super() {
set_next_reset(-1);
}
// Welche externen Objekte duerfen zugreifen?
nomask private int allowed()
{
if ( (previous_object() && IS_ARCH(getuid(previous_object())) &&
this_interactive() && IS_ARCH(this_interactive())) ||
(previous_object() && getuid(previous_object()) == ROOTID &&
geteuid(previous_object()) == ROOTID) )
return 1;
return 0;
}
// Set() -- provides direct access to a property, no filters
public varargs mixed Set( string name, mixed Value, int Type, int extern )
{
if (!objectp(this_object()))
return 0;
// Properties, die SECURED oder PROTECTED sind, duerfen nur vom Objekt
// selber, EM+ oder ROOT veraendert werden
if ((prop[F_MODE][name]&(PROTECTED|SECURED))&&
(closure_call||extern||extern_call()) &&
previous_object() != this_object() && !allowed())
return -1;
// Das SECURED-Flag darf bei Properties nicht mehr geloescht werden
if ((prop[F_MODE][name]&SECURED)&&
(Type==F_MODE||Type==F_MODE_AD)&&(Value & SECURED))
return -2;
// Setzen duerfen das SECURED-Flag nur das Objekt selber, EM+ oder ROOT
if ((Type==F_MODE||Type==F_MODE_AS)&&(Value&SECURED)&&
(closure_call ||extern || extern_call()) &&
previous_object() != this_object() && !allowed() )
return -3;
switch(Type)
{
// Je nach Modus Flags veraendern
case F_MODE_AS: prop[F_MODE][name]|= Value;
return prop[F_MODE][name];
case F_MODE_AD: prop[F_MODE][name]&= ~Value;
if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
return prop[F_MODE][name];
case F_MODE: prop[F_MODE][name]^= Value;
if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
return prop[F_MODE][name];
case F_SET_METHOD:
// -1 als Setz-Methode: Nosetmethod setzen
if (Value == -1)
{
prop[F_SET_METHOD]-=([name]);
prop[F_MODE][name] |= NOSETMETHOD;
return 0;
}
// Kein break!
case F_QUERY_METHOD:
// Ungebundene Lambda_Closure? Binden!
if (closurep(Value)&&!query_closure_object(Value))
{
if (extern_call() &&
(getuid(previous_object()) != getuid()||
geteuid(previous_object()) != geteuid()))
return prop[Type][name];
Value = bind_lambda( Value,this_object());
}
// Kein break!
default:
if (!Value) prop[Type]-=([name]);
else prop[Type][name] = Value;
}
// Gesamtwert zurueckgeben
return prop[Type][name];
}
// Direktes Auslesen der Property ohne Filter ...
public varargs mixed Query( string name, int Type )
{
if (pointerp(prop)) return prop[Type][name];
return 0;
}
// Property setzen unter Verwendung evtl. vorhandener Zugriffsfunktionen
public mixed SetProp( string name, mixed Value )
{
closure func;
mixed result;
// nur fuer heute
if (!objectp(this_object()))
return 0;
// NOSETMETHOD: Darf nicht gesetzt werden
if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
// Set-Method abfragen, so vorhanden
if (func=prop[F_SET_METHOD][name])
{
int flag;
// Wert als Set-Method? gleich zurueckgeben
if (!closurep(func)) return func;
// An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
// Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
// Objekt existiert auch noch (sonst waere func == 0).
// closure_call setzen, falls noch nicht gesetzt
if ((flag=closure_call<time()))
closure_call = time()+59;
// Dann mal die Closure aufrufen. Bei Fehler selbige loeschen
if (catch(result=funcall(func, Value, name);publish))
{
prop[F_SET_METHOD]-=([name]);
}
// Wenn closure_call gesetzt wurde, wieder loeschen
if (flag) closure_call = 0;
// Und zurueckgeben
return result;
}
// _set_*-Methode vorhanden? falls ja, aufrufen.i
// TODO: Closurecache einfuehren und Funktionaufruf nur noch machen, wenn es
// die _set_* auch gibt?
if (call_resolved(&result,this_object(),"_set_"+name,Value ))
return result;
// Letzte Moeglichkeit: Muss eine 'normale' Property sein
return Set( name, Value, F_VALUE, extern_call() );
}
// Property auslesen unter Verwendung evtl. vorhandener Zugriffsfunktionen
public mixed QueryProp( string name )
{
closure func;
mixed result;
// nur fuer heute
if (!objectp(this_object()))
return;
// Query-Methode vorhanden?
if ( func = prop[F_QUERY_METHOD][name] )
{
int flag;
// Wert als Query-Method? Gleich zurueckgeben ...
if (!closurep(func)) return func;
// An dieser Stelle muss func eine Closure sein. Da Set() ungebundene
// Lambdas bindet, kann es auch nur eine gebundene Closure sein und das
// Objekt existiert auch noch (sonst waere func == 0).
// closure_call setzen, falls noch nicht gesetzt
if ((flag=closure_call<time()))
closure_call = time()+59;
// Dann Mal die Closure aufrufen. Bei Fehler selbige loeschen
if (catch(result=funcall(func);publish))
{
prop[F_QUERY_METHOD]-=([name]);
}
// Wenn closure_call gesetzt wurde, wieder loeschen
if (flag) closure_call = 0;
// Und zurueckgeben
return result;
}
// _query_*-Methode vorhanden? falls ja, aufrufen.
// TODO: Closurecache und nur rufen, wenn es _query_* auch gibt?
if (call_resolved(&result,this_object(),"_query_"+name))
return result;
// Hilft alles nichts. Es ist eine 'normale' Property ...
return prop[F_VALUE][name];
}
// Das gesamte Property-Mapping auf einen Schlag setzen
public void SetProperties( mapping props )
{
string *names;
int i, j, same_object;
// Kein Mapping? Schlecht ...
if(!mappingp(props)) return;
// Setzen wir selber?
same_object = (!closure_call &&
(!extern_call()||previous_object()==this_object()||
allowed()));
names = m_indices(props);
// Das SECURED-Flag darf nur durch das Objekt selber gesetzt werden:
// Alle SECURED-Flags aus props loeschen
if (!same_object)
{
j=sizeof(names);
while(j--) props[names[j], F_MODE] &= ~SECURED;
}
j=sizeof(names);
while(j--)
{
// Properties, die schon SECURED oder PROTECTED sind, duerfen
// nur vom Objekt selber manipuliert werden
if (same_object||!(prop[F_MODE][names[j]] & (PROTECTED|SECURED)) )
{
i=4;
while(i--)
{
if(props[names[j],i])
prop[i][names[j]] = props[names[j], i];
else
prop[i]-=([names[j]]);
}
}
}
return;
}
// Ein Mapping mit allen Properties zurueckgeben
public mapping QueryProperties()
{
mapping props;
int i, j;
string *names;
props = m_allocate( 0, 4 );
if (pointerp(prop))
{
i=4;
while(i--)
{
names = m_indices(prop[i]);
j=sizeof(names);
while(j--) props[names[j], i] = prop[i][names[j]];
}
}
return props;
}
// Die Properties als urspruengliches Array zurueckgeben
public mixed *__query_properties()
{
if ( pointerp(prop) )
return(deep_copy(prop));
else
return ({ ([]),([]),([]),([]) });
}
// mapping Properties setzen zum Speichern (per save_object())
// Aufruf nur aus simul_efun heraus
public void _set_save_data(mixed data) { properties = data; }
// mapping Properties zum Restoren zurueckgeben
public mixed _get_save_data() { return properties; }