Made spawner prototype verification more strict. Resolves #556.
This commit is contained in:
parent
18a0606de6
commit
a075e07e55
1 changed files with 32 additions and 10 deletions
|
|
@ -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),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue