MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame^] | 1 | // MorgenGrauen MUDlib |
| 2 | /** \file /secure/shadowmaster.c |
| 3 | * Objekt, welches eine Liste mit aktiven Shadows hat. |
| 4 | * Die simul_efun shadow() meldet das beschattende Objekt hier an. Nuetzlich, |
| 5 | * damit man als Magier endlich mal rauskriegen kann, welche Shadows es |
| 6 | * eigentlich gibt. |
| 7 | * \author Zesstra |
| 8 | * \date 07.08.2009 |
| 9 | * \version $Id$ |
| 10 | */ |
| 11 | /* Changelog: |
| 12 | */ |
| 13 | #pragma strong_types |
| 14 | #pragma no_clone |
| 15 | #pragma no_inherit |
| 16 | #pragma no_shadow |
| 17 | #pragma pedantic |
| 18 | |
| 19 | #include <defines.h> |
| 20 | #include <wizlevels.h> |
| 21 | |
| 22 | #define HOME(x) (__PATH__(0)+x) |
| 23 | |
| 24 | /** shadows ist ein mapping, welches alle Schatten und ihre Opfer enthaelt. |
| 25 | * |
| 26 | * Struktur: Schatten als Schluessel (object) und Beschatteter (object) als |
| 27 | * Wert. |
| 28 | */ |
| 29 | private mapping shadows = ([]); |
| 30 | |
| 31 | #ifndef DEBUG |
| 32 | #define DEBUG(x) if (find_player("zesstra"))\ |
| 33 | tell_object(find_player("zesstra"),\ |
| 34 | "SMDBG: "+x+"\n") |
| 35 | #endif |
| 36 | |
| 37 | #define MEMORY "/secure/memory" |
| 38 | |
| 39 | #define SHADOW_OK 1 |
| 40 | #define SHADOW_ACCESS_DENIED -1 |
| 41 | #define SHADOW_EXISTS -2 |
| 42 | #define SHADOW_UNKNOWN -3 |
| 43 | |
| 44 | protected void create() { |
| 45 | mixed tmp; |
| 46 | seteuid(getuid()); |
| 47 | if (mappingp(tmp=MEMORY->Load("Schatten"))) { |
| 48 | shadows = tmp; |
| 49 | DEBUG("Daten aus MEMORY geladen.\n"); |
| 50 | } |
| 51 | else { |
| 52 | DEBUG("Keine Daten in MEMORY vorhanden - reinitialisiere.\n"); |
| 53 | if (MEMORY->Save("Schatten", shadows) != 1) |
| 54 | raise_error("Konnte Daten nicht im Memory ablegen.\n"); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | /** Liefert einen String mit allen Schatten und beschatteten Objekten zurueck. |
| 59 | * @return string - Liste von Schatten und Opfern |
| 60 | */ |
| 61 | public void DumpShadows() { |
| 62 | if (extern_call() && !ELDER_SECURITY ) return 0; |
| 63 | |
| 64 | string res = ""; |
| 65 | foreach(object schatten, object opfer: shadows) |
| 66 | if (schatten && opfer) |
| 67 | res += sprintf("%O -> %O\n",schatten,opfer); |
| 68 | |
| 69 | printf("Folgende Shadows sind bekannt: \n\n%s\n", res); |
| 70 | } |
| 71 | |
| 72 | /** Findet zu einem beschatteten Objekt den zugehoerigen Schatten. |
| 73 | @param[in] object - ein beschattetes Objekt. |
| 74 | @return object - Den Schatten oder 0. |
| 75 | @sa FindShadowsObject(), QueryObject(), QueryInfo() |
| 76 | */ |
| 77 | public object FindShadow(object opfer) { |
| 78 | if (!objectp(opfer)) |
| 79 | return 0; |
| 80 | |
| 81 | foreach(object schatten, object victim: shadows) { |
| 82 | if (opfer == victim) |
| 83 | // Schatten gefunden. |
| 84 | return schatten; |
| 85 | } |
| 86 | return 0; |
| 87 | } |
| 88 | |
| 89 | /** Findet zu einem Schatten das beschattete Objekt. |
| 90 | @param[in] object - ein beschattendes Objekt. |
| 91 | @return object - Das beschattete Objekt oder 0. |
| 92 | @sa FindShadow(), QueryObject(), QueryInfo() |
| 93 | */ |
| 94 | public object FindShadowedObject(object schatten) { |
| 95 | return shadows[schatten]; |
| 96 | } |
| 97 | |
| 98 | /** Gibt Schatten und Beschatteten zurueck, falls ob eines von beiden ist. |
| 99 | Ist ob ein Schatten oder ein beschattetes Objekt, wird ein Array aus |
| 100 | Objekten geliefert. Hierbei werden ggf. alle Objekte in der |
| 101 | Beschattungshierarchie geliefert, von der ob Bestandteil ist. |
| 102 | @param[in] object - ein Objekt. |
| 103 | @return object* - ({a, b, c, d}) oder 0. |
| 104 | @sa FindShadow(), FindShadowedObject, QueryInfo() |
| 105 | */ |
| 106 | public object* QueryObject(object ob) { |
| 107 | |
| 108 | if (!objectp(ob)) return 0; |
| 109 | |
| 110 | object *res = ({ob}); |
| 111 | object sh = FindShadow(ob); |
| 112 | |
| 113 | while(sh) { |
| 114 | // es gibt einen Schatten, also Kette nach oben verfolgen. |
| 115 | res = ({sh}) + res; |
| 116 | sh = FindShadow(sh); |
| 117 | } |
| 118 | |
| 119 | object vic = FindShadowedObject(ob); |
| 120 | while(vic) { |
| 121 | // es gibt ein beschattetes Objekt, Kette nach unten verfolgen. |
| 122 | res = res + ({vic}); |
| 123 | vic = FindShadowedObject(vic); |
| 124 | } |
| 125 | |
| 126 | if (sizeof(res) < 2) { |
| 127 | // Offenbar wird ob weder beschattet noch beschattet selber. |
| 128 | // Moeglicherweise wurde jedoch durch wilde Zerstoerung die Hierarchie |
| 129 | // getrennt. Falls ob nen Schatten ist, laesst sich das reparieren. Falls |
| 130 | // ob beschattet wird, hilft eigentlich nur ein reset(). Den moechte ich |
| 131 | // hier aber nicht machen, weils u.U. teuer sein koennte. |
| 132 | if (query_shadowing(ob)) { |
| 133 | shadows[ob] = query_shadowing(ob); |
| 134 | // nochmal. |
| 135 | return QueryObject(ob); |
| 136 | } |
| 137 | // scheinbar nicht. |
| 138 | return 0; |
| 139 | } |
| 140 | |
| 141 | return res; |
| 142 | } |
| 143 | |
| 144 | /** Gibt einen String mit Infos ueber ob zurueck. |
| 145 | Ist ob ein beschattetes Objekt oder ein Schatten, wird ein beschreibender |
| 146 | String zurueckgeliefert (schatten -> beschattetes Objekt). Hierbei wird ggf. |
| 147 | die gesamte Beschattungshierarchie angegeben (a -> b -> c -> d). |
| 148 | @param[in] object - ein Objekt. |
| 149 | @return string - String mit Infos ueber ob. |
| 150 | @sa FindShadow(), FindShadowedObject(), QueryObject() |
| 151 | */ |
| 152 | public string QueryInfo(object ob) { |
| 153 | object *shs = QueryObject(ob); |
| 154 | if (!shs) return 0; |
| 155 | |
| 156 | return CountUp(map(shs, #'object_name), " -> ", " -> "); |
| 157 | } |
| 158 | |
| 159 | /** Registriert einen Schatten und sein Opfer. |
| 160 | Registriert den Schatten und sein Opfer. Sollte ausschliesslich durch die |
| 161 | simul_efun oder spare_simul_fun gerufen werden. |
| 162 | @sa UnregisterShadow() |
| 163 | */ |
| 164 | public int RegisterShadow(object schatten) { |
| 165 | object opfer; |
| 166 | |
| 167 | //DEBUG(sprintf("[%O] %O\n", schatten, caller_stack())); |
| 168 | |
| 169 | // Irgendein Sicherheitscheck ist eigentlich nicht noetig hier, da das Opfer |
| 170 | // ohnehin per efun ermittelt wird und kein Eintrag erfolgt, wenn kein |
| 171 | // beschattetes Objekt zu finden ist. |
| 172 | |
| 173 | // das von schatten beschattete Objekt ermitteln |
| 174 | if (objectp(opfer=query_shadowing(schatten))) { |
| 175 | if (shadows[schatten] == opfer) |
| 176 | return SHADOW_EXISTS; |
| 177 | |
| 178 | // Neueintrag oder ggf. auch Aendern. |
| 179 | shadows[schatten] = opfer; |
| 180 | //DEBUG(DumpShadows()); |
| 181 | return SHADOW_OK; |
| 182 | } |
| 183 | return SHADOW_ACCESS_DENIED; |
| 184 | } |
| 185 | |
| 186 | /** Traegt einen Schatten wieder aus. |
| 187 | Der Schatten wird wieder ausgetragen. Sollte ausschliesslich durch die |
| 188 | simul_efun oder spare_simul_fun gerufen werden. |
| 189 | Werden Schatten oder beschattete Objekte zerstoert ohne vorher die |
| 190 | Schattierung zu beenden, fuehrt dies zu Inkonsistenzen und zerbrochenen |
| 191 | Beschattungshierarchien. |
| 192 | @sa RegisterShadow(), UnregisterOpfer() |
| 193 | */ |
| 194 | public int UnregisterShadow(object caller) { |
| 195 | object schatten, opfer; |
| 196 | |
| 197 | // Ein Sicherheitscheck fuer den Aufruf ist eigentlich nicht noetig, da ein |
| 198 | // Eintrag nur entfernt wird, wenn die Beschattung nachweislich beendet |
| 199 | // wurde. |
| 200 | |
| 201 | //DEBUG(sprintf("[%O] %O\n", caller, caller_stack())); |
| 202 | if (!objectp(caller)) return SHADOW_UNKNOWN; |
| 203 | |
| 204 | // Schatten und beschatteten aus den lokalen Daten ermitteln. |
| 205 | if (member(shadows, caller)) { |
| 206 | schatten = caller; |
| 207 | opfer = shadows[schatten]; |
| 208 | } |
| 209 | else if (objectp(schatten = FindShadow(caller))) { |
| 210 | opfer = caller; |
| 211 | } |
| 212 | // wenn nicht bekannt, ist jetzt eh Ende. |
| 213 | if (!schatten) return SHADOW_UNKNOWN; |
| 214 | |
| 215 | //DEBUG(sprintf("%O -> %O (%O, %O)\n", |
| 216 | // schatten, opfer, caller, query_shadowing(schatten))); |
| 217 | |
| 218 | // Schattierung wirklich beendet? Wenn nicht -> Ende |
| 219 | if (opfer && query_shadowing(schatten) == opfer) |
| 220 | return SHADOW_ACCESS_DENIED; |
| 221 | |
| 222 | // war schatten in einer Beschattungshierarchie? |
| 223 | object up = FindShadow(schatten); |
| 224 | if (up && query_shadowing(up) == opfer) { |
| 225 | shadows[up] = opfer; // Kette neu verlinken |
| 226 | } |
| 227 | |
| 228 | // jetzt kann geloescht werden. |
| 229 | m_delete(shadows,schatten); |
| 230 | return SHADOW_OK; |
| 231 | } |
| 232 | |
| 233 | public int ResetAll() { |
| 234 | if (!ARCH_SECURITY) return SHADOW_ACCESS_DENIED; |
| 235 | |
| 236 | DEBUG("ResetAll() called.\n"); |
| 237 | |
| 238 | shadows = ([]); |
| 239 | |
| 240 | if (MEMORY->Save("Schatten", shadows) != 1) |
| 241 | raise_error("Konnte Daten nicht im Memory ablegen.\n"); |
| 242 | |
| 243 | return SHADOW_OK; |
| 244 | } |
| 245 | |
| 246 | /** Raeumt die Daten ueber die Schatten auf. |
| 247 | Zerstoeren sich beschattete Objekte, werden die Schatten nicht |
| 248 | ausgetragen, daher wird das von zeit zu zeit hier gemacht. |
| 249 | */ |
| 250 | public void reset() { |
| 251 | foreach(object schatten, object opfer: shadows) { |
| 252 | if (!objectp(opfer)) { |
| 253 | // war schatten evtl. in einer Hierarchie und beschattet jetzt was |
| 254 | // anderes? |
| 255 | if (query_shadowing(schatten)) |
| 256 | shadows[schatten] = query_shadowing(schatten); |
| 257 | else |
| 258 | m_delete(shadows, schatten); |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | |