#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"]))