#MUDPyE - (M)ulti-(U)ser (D)imension (Py)thon (E)ngine #Copyright (C) 2005 Corey Staten #This program is free software; you can redistribute it and/or #modify it under the terms of the GNU General Public License #as published by the Free Software Foundation; either version 2 #of the License, or (at your option) any later version. #This program is distributed in the hope that it will be useful, #but WITHOUT ANY WARRANTY; without even the implied warranty of #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #GNU General Public License for more details. #You should have received a copy of the GNU General Public License #along with this program; if not, write to the Free Software #Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #Send feedback/questions to MUDPyE@gmail.com import copy import mptraceback import types staticTypes = [types.LongType, types.IntType, types.FloatType, types.StringType, types.BooleanType, types.NoneType] class CallableNone(object): """Simulates None, but is callable(doing nothing).""" def __eq__(self, x): return x == None def __ge__(self, x): return x >= None def __le__(self, x): return x <= None def __gt__(self, x): return x > None def __lt__(self, x): return x < None def __ne__(self, x): return x != None def __call__(self, *args, **kwargs): return None callNone = CallableNone() class MudFunctionWrapper(object): """Wraps context functions to catch error source file.""" def __init__(self, func, srcContext): self.func = func self.srcContext = srcContext def __call__(self, *args, **kwargs): try: #print "Exec: %s - %s%s" % (self.srcContext["_srcType"], self.func.func_name, args) return self.func(*args, **kwargs) except: self.srcContext["mudWorld"].mudTraceback.append("* %s in %s: %s\r\n" % (self.func.func_name, self.srcContext["_srcType"], args)) raise def GenMudObjectRefType(genMudWorld): class MudObjectRef(object): """Class used to represent references to MUD objects.""" mudWorld = genMudWorld def __init__(self, ID): object.__setattr__(self, "objDict", None) object.__setattr__(self, "objID", ID) def __getattribute__(self, key): objDict = object.__getattribute__(self, "objDict") objID = object.__getattribute__(self, "objID") #Make sure the object is loaded. if objDict is None: objDict = MudObjectRef.mudWorld.objDB.GetObjDict(objID) if objDict is None: MudObjectRef.mudWorld.loggers["mud.scripterror"].error("Invalid reference to object [%s]." % objID) raise IOError, "Unable to load object %s, invalid reference." % objID object.__setattr__(self, "objDict", objDict) if objDict.has_key(key): returnVal = objDict[key] #If the value type isn't static(IE it can be changed), we need to dirty the object. if (type(returnVal) not in staticTypes) and (objID not in MudObjectRef.mudWorld.objDB.dirtyObjs): MudObjectRef.mudWorld.objDB.dirtyObjs.append(objID) #We need to lambdadize functions if they are returned, to simulate that they are bound to the object. if type(returnVal) is MudFunctionWrapper: return lambda *args: returnVal(self, *args) return returnVal #Next, check the source context. sourceContext = MudObjectRef.mudWorld.sourceDB.GetContext(objDict["_objType"]) if sourceContext.has_key(key): returnVal = sourceContext[key] #We need to lambdadize functions if they are returned, to simulate that they are bound to the object. if type(returnVal) is MudFunctionWrapper: return lambda *args, **kwargs: returnVal(self, *args, **kwargs) return returnVal #Value not found. raise AttributeError, "MudObject %s has no attribute %s." % (objID, key) def __setattr__(self, key, value): objDict = object.__getattribute__(self, "objDict") objID = object.__getattribute__(self, "objID") #Make sure the object is loaded. if objDict is None: objDict = MudObjectRef.mudWorld.objDB.GetObjDict(objID) if objDict is None: MudObjectRef.mudWorld.loggers["mud.scripterror"].error("Invalid reference to object [%s]." % objID) return None object.__setattr__(self, "objDict", objDict) objDict[key] = value if objID not in MudObjectRef.mudWorld.objDB.dirtyObjs: MudObjectRef.mudWorld.objDB.dirtyObjs.append(objID) def __delattr__(self, key): objDict = object.__getattribute__(self, "objDict") objID = object.__getattribute__(self, "objID") #Make sure the object is loaded. if objDict is None: objDict = MudObjectRef.mudWorld.objDB.GetObjDict(objID) if objDict is None: MudObjectRef.mudWorld.loggers["mud.scripterror"].error("Invalid reference to object [%s]." % objID) return None object.__setattr__(self, "objDict", objDict) del objDict[key] if objID not in MudObjectRef.mudWorld.objDB.dirtyObjs: MudObjectRef.mudWorld.objDB.dirtyObjs.append(objID) def __repr__(self): return "<MudObjectRef: %s>" % object.__getattribute__(self, "objID") def __str__(self): return "<MudObjectRef: %s>" % object.__getattribute__(self, "objID") return MudObjectRef def Ex(mudObjRef, funcName, *args, **kwargs): return ExAsType(mudObjRef, mudObjRef._objType, funcName, *args, **kwargs) def ExAsType(mudObjRef, objType, funcName, *args, **kwargs): """Executes function as objType. Generally used for calling functions in a parent context.""" found = False returnVal = None mudWorld = type(mudObjRef).mudWorld srcContext = mudWorld.sourceDB.GetContext(objType) if srcContext == None: type(mudObjRef).mudWorld.loggers["mud.scripterror"].warning("Attempt to execute function [%s] with non-existant object type [%s]." % (funcName, objType)) return (False, None) if (srcContext.has_key(funcName)) and callable(srcContext[funcName]): try: returnVal = srcContext[funcName](mudObjRef, *args, **kwargs) found = True except: mudWorld.loggers["mud.scripterror"].error("Error executing function [%s] on objType [%s]:\r\n%s" % (funcName, objType, mptraceback.mud_traceback(mudWorld))) return (found, returnVal) def ExParentToChild(mudObjRef, funcName, *args, **kwargs): """Executes function starting with the highest parent and working its way down. Note that this doesn't count levels, it fully backward explores the parent tree of the first item in the _parents list before moving on to the second.""" _RecursiveExParentToChild(mudObjRef, mudObjRef._objType, [], funcName, *args, **kwargs) def _RecursiveExParentToChild(mudObjRef, curType, exList, funcName, *args, **kwargs): """Recursive helper of ExParentToChild.""" curContext = type(mudObjRef).mudWorld.sourceDB.GetContext(curType) exList.append(curType) if curContext == None: type(mudObjRef).mudWorld.loggers["mud.scripterror"].error("Unable to load context [%s]." % curType) return for parent in curContext["_parents"]: if parent not in exList: _RecursiveExParentToChild(mudObjRef, parent, exList, funcName, *args, **kwargs) ExAsType(mudObjRef, curType, funcName, *args, **kwargs) def ExChildToParent(mudObjRef, funcName, *args, **kwargs): """Executes function starting with the child and working its way up through the parents. Note that this doesn't count levels, it fully backward explores the parent tree of the first item in the _parents list before moving on to the second.""" _RecursiveExChildToParent(mudObjRef, mudObjRef._objType, [], funcName, *args, **kwargs) def _RecursiveExChildToParent(mudObjRef, curType, exList, funcName, *args, **kwargs): """Recursive helper of ExChildToParent.""" ExAsType(mudObjRef, curType, funcName, *args, **kwargs) curContext = type(mudObjRef).mudWorld.sourceDB.GetContext(curType) exList.append(curType) if curContext == None: type(mudObjRef).mudWorld.loggers["mud.scripterror"].error("Unable to load context [%s]." % curType) return for parent in curContext["_parents"]: if parent not in exList: _RecursiveExChildToParent(mudObjRef, parent, exList, funcName, *args, **kwargs) def VersionUpdate(mudObjRef): """Handles updating objects when their versions are mismatched.""" versions = mudObjRef._versions _RecursiveVersionUpdate(mudObjRef, versions, [], mudObjRef._objType) def _RecursiveVersionUpdate(mudObjRef, versions, exList, curType): curContext = type(mudObjRef).mudWorld.sourceDB.GetContext(curType) exList.append(curType) if curContext == None: type(mudObjRef).mudWorld.loggers["mud.scripterror"].error("Unable to load context [%s]." % curType) return for parent in curContext["_parents"]: if parent not in exList: _RecursiveVersionUpdate(mudObjRef, versions, exList, parent) if not(versions.has_key(curType)): versions[curType] = curContext["_version"] elif (versions[curType] != curContext["_version"]): if (curContext.has_key("_Sys_VersionUpdate")) and callable(curContext["_Sys_VersionUpdate"]): newVersion = ExAsType(curType, mudObjRef, "_Sys_VersionUpdate", versions[curType]) else: type(mudObjRef).mudWorld.loggers["engine.db"].warning("Version mismatch with no VersionUpdate function: %s version (%d) to (%d)" % (curType, versions[curType], curContext["_version"]))