Made spawner prototype verification more strict. Resolves #556.

This commit is contained in:
Griatch 2014-08-31 12:32:58 +02:00
parent 18a0606de6
commit a075e07e55

View file

@ -84,27 +84,39 @@ _CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
_handle_dbref = lambda inp: handle_dbref(inp, ObjectDB) _handle_dbref = lambda inp: handle_dbref(inp, ObjectDB)
def _get_prototype(dic, prot, protparents, visited): def _validate_prototype(key, prototype, protparents, visited):
"Run validation on a prototype, checking for inifinite regress"
assert isinstance(prototype, dict)
if id(prototype) in visited:
raise RuntimeError("%s has infinite nesting of prototypes." % key or prototype)
visited.append(id(prototype))
protstrings = prototype.get("prototype")
if protstrings:
for protstring in make_iter(protstrings):
if key is not None and protstring == key:
raise RuntimeError("%s tries to prototype itself." % key or prototype)
protparent = protparents.get(protstring)
if not protparent:
raise RuntimeError("%s's prototype '%s' was not found." % (key or prototype, protstring))
_validate_prototype(protstring, protparent, protparents, visited)
def _get_prototype(dic, prot, protparents):
""" """
Recursively traverse a prototype dictionary, Recursively traverse a prototype dictionary,
including multiple inheritance and self-reference including multiple inheritance. Use _validate_prototype
detection before this, we don't check for infinite recursion here.
""" """
visited.append(id(dic))
if "prototype" in dic: if "prototype" in dic:
# move backwards through the inheritance # move backwards through the inheritance
for prototype in make_iter(dic["prototype"]): for prototype in make_iter(dic["prototype"]):
if id(prototype) in visited:
# a loop was detected. Don't self-reference.
continue
# Build the prot dictionary in reverse order, overloading # Build the prot dictionary in reverse order, overloading
new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents, visited) new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents)
prot.update(new_prot) prot.update(new_prot)
prot.update(dic) prot.update(dic)
prot.pop("prototype", None) # we don't need this anymore prot.pop("prototype", None) # we don't need this anymore
return prot return prot
def _batch_create_object(*objparams): def _batch_create_object(*objparams):
""" """
This is a cut-down version of the create_object() function, This is a cut-down version of the create_object() function,
@ -167,6 +179,8 @@ def spawn(*prototypes, **kwargs):
to build the global protparents dictionary accessible by the to build the global protparents dictionary accessible by the
input prototypes. If not given, it will instead look for modules input prototypes. If not given, it will instead look for modules
defined by settings.PROTOTYPE_MODULES. defined by settings.PROTOTYPE_MODULES.
prototype_parents - a dictionary holding a custom prototype-parent dictionary. Will
overload same-named prototypes from prototype_modules.
return_prototypes - only return a list of the prototype-parents return_prototypes - only return a list of the prototype-parents
(no object creation happens) (no object creation happens)
""" """
@ -178,6 +192,10 @@ def spawn(*prototypes, **kwargs):
for prototype_module in protmodules: for prototype_module in protmodules:
protparents.update(dict((key, val) protparents.update(dict((key, val)
for key, val in all_from_module(prototype_module).items() if isinstance(val, dict))) for key, val in all_from_module(prototype_module).items() if isinstance(val, dict)))
#overload module's protparents with specifically given protparents
protparents.update(kwargs.get("prototype_parents", {}))
for key, prototype in protparents.items():
_validate_prototype(key, prototype, protparents, [])
if "return_prototypes" in kwargs: if "return_prototypes" in kwargs:
# only return the parents # only return the parents
@ -186,7 +204,8 @@ def spawn(*prototypes, **kwargs):
objsparams = [] objsparams = []
for prototype in prototypes: for prototype in prototypes:
prot = _get_prototype(prototype, {}, protparents, []) _validate_prototype(None, prototype, protparents, [])
prot = _get_prototype(prototype, {}, protparents)
if not prot: if not prot:
continue continue
@ -224,6 +243,9 @@ if __name__ == "__main__":
protparents = { protparents = {
"NOBODY": {}, "NOBODY": {},
#"INFINITE" : {
# "prototype":"INFINITE"
#},
"GOBLIN" : { "GOBLIN" : {
"key": "goblin grunt", "key": "goblin grunt",
"health": lambda: randint(20,30), "health": lambda: randint(20,30),