mirror of
https://github.com/evennia/evennia.git
synced 2026-04-03 06:27:17 +02:00
Reshuffling the Evennia package into the new template paradigm.
This commit is contained in:
parent
2846e64833
commit
2b3a32e447
371 changed files with 17250 additions and 304 deletions
|
|
@ -1,258 +0,0 @@
|
|||
"""
|
||||
Spawner
|
||||
|
||||
The spawner takes input files containing object definitions in
|
||||
dictionary forms. These use a prototype architechture to define
|
||||
unique objects without having to make a Typeclass for each.
|
||||
|
||||
The main function is spawn(*prototype), where the prototype
|
||||
is a dictionary like this:
|
||||
|
||||
GOBLIN = {
|
||||
"typeclass": "game.gamesrc.objects.objects.Monster",
|
||||
"key": "goblin grunt",
|
||||
"health": lambda: randint(20,30),
|
||||
"resists": ["cold", "poison"],
|
||||
"attacks": ["fists"],
|
||||
"weaknesses": ["fire", "light"]
|
||||
}
|
||||
|
||||
Possible keywords are:
|
||||
prototype - string parent prototype
|
||||
key - string, the main object identifier
|
||||
typeclass - string, if not set, will use settings.BASE_OBJECT_TYPECLASS
|
||||
location - this should be a valid object or #dbref
|
||||
home - valid object or #dbref
|
||||
destination - only valid for exits (object or dbref)
|
||||
|
||||
permissions - string or list of permission strings
|
||||
locks - a lock-string
|
||||
aliases - string or list of strings
|
||||
|
||||
ndb_<name> - value of a nattribute (ndb_ is stripped)
|
||||
any other keywords are interpreted as Attributes and their values.
|
||||
|
||||
Each value can also be a callable that takes no arguments. It should
|
||||
return the value to enter into the field and will be called every time
|
||||
the prototype is used to spawn an object.
|
||||
|
||||
By specifying a prototype, the child will inherit all prototype slots
|
||||
it does not explicitly define itself, while overloading those that it
|
||||
does specify.
|
||||
|
||||
GOBLIN_WIZARD = {
|
||||
"prototype": GOBLIN,
|
||||
"key": "goblin wizard",
|
||||
"spells": ["fire ball", "lighting bolt"]
|
||||
}
|
||||
|
||||
GOBLIN_ARCHER = {
|
||||
"prototype": GOBLIN,
|
||||
"key": "goblin archer",
|
||||
"attacks": ["short bow"]
|
||||
}
|
||||
|
||||
One can also have multiple prototypes. These are inherited from the
|
||||
left, with the ones further to the right taking precedence.
|
||||
|
||||
ARCHWIZARD = {
|
||||
"attack": ["archwizard staff", "eye of doom"]
|
||||
|
||||
GOBLIN_ARCHWIZARD = {
|
||||
"key" : "goblin archwizard"
|
||||
"prototype": (GOBLIN_WIZARD, ARCHWIZARD),
|
||||
}
|
||||
|
||||
The goblin archwizard will have some different attacks, but will
|
||||
otherwise have the same spells as a goblin wizard who in turn shares
|
||||
many traits with a normal goblin.
|
||||
|
||||
"""
|
||||
|
||||
import os, sys, copy
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'game.settings'
|
||||
|
||||
from django.conf import settings
|
||||
from random import randint
|
||||
from src.objects.models import ObjectDB
|
||||
from src.utils.utils import make_iter, all_from_module, dbid_to_obj
|
||||
|
||||
_CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
||||
|
||||
_handle_dbref = lambda inp: dbid_to_obj(inp, ObjectDB)
|
||||
|
||||
|
||||
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,
|
||||
including multiple inheritance. Use _validate_prototype
|
||||
before this, we don't check for infinite recursion here.
|
||||
"""
|
||||
if "prototype" in dic:
|
||||
# move backwards through the inheritance
|
||||
for prototype in make_iter(dic["prototype"]):
|
||||
# Build the prot dictionary in reverse order, overloading
|
||||
new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents)
|
||||
prot.update(new_prot)
|
||||
prot.update(dic)
|
||||
prot.pop("prototype", None) # we don't need this anymore
|
||||
return prot
|
||||
|
||||
def _batch_create_object(*objparams):
|
||||
"""
|
||||
This is a cut-down version of the create_object() function,
|
||||
optimized for speed. It does NOT check and convert various input
|
||||
so make sure the spawned Typeclass works before using this!
|
||||
|
||||
Input:
|
||||
objsparams - each argument should be a tuple of arguments for the respective
|
||||
creation/add handlers in the following order:
|
||||
(create, permissions, locks, aliases, nattributes, attributes)
|
||||
Returns:
|
||||
A list of created objects
|
||||
"""
|
||||
|
||||
# bulk create all objects in one go
|
||||
dbobjs = [ObjectDB(**objparam[0]) for objparam in objparams]
|
||||
# unfortunately this doesn't work since bulk_create don't creates pks;
|
||||
# the result are double objects at the next stage
|
||||
#dbobjs = _ObjectDB.objects.bulk_create(dbobjs)
|
||||
|
||||
objs = []
|
||||
for iobj, obj in enumerate(dbobjs):
|
||||
# call all setup hooks on each object
|
||||
objparam = objparams[iobj]
|
||||
# setup
|
||||
obj._createdict = {"pernmissions": objparam[1],
|
||||
"locks": objparam[2],
|
||||
"aliases": objparam[3],
|
||||
"attributes": objparam[4],
|
||||
"nattributes": objparam[5]}
|
||||
# this triggers all hooks
|
||||
obj.save()
|
||||
return objs
|
||||
|
||||
|
||||
def spawn(*prototypes, **kwargs):
|
||||
"""
|
||||
Spawn a number of prototyped objects. Each argument should be a
|
||||
prototype dictionary.
|
||||
|
||||
keyword args:
|
||||
prototype_modules - a python-path to a
|
||||
prototype module, or a list of such paths. These will be used
|
||||
to build the global protparents dictionary accessible by the
|
||||
input prototypes. If not given, it will instead look for 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
|
||||
(no object creation happens)
|
||||
"""
|
||||
|
||||
protparents = {}
|
||||
protmodules = make_iter(kwargs.get("prototype_modules", []))
|
||||
if not protmodules and hasattr(settings, "PROTOTYPE_MODULES"):
|
||||
protmodules = make_iter(settings.PROTOTYPE_MODULES)
|
||||
for prototype_module in protmodules:
|
||||
protparents.update(dict((key, val)
|
||||
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:
|
||||
# only return the parents
|
||||
return copy.deepcopy(protparents)
|
||||
|
||||
objsparams = []
|
||||
for prototype in prototypes:
|
||||
|
||||
_validate_prototype(None, prototype, protparents, [])
|
||||
prot = _get_prototype(prototype, {}, protparents)
|
||||
if not prot:
|
||||
continue
|
||||
|
||||
# extract the keyword args we need to create the object itself
|
||||
create_kwargs = {}
|
||||
create_kwargs["db_key"] = prot.pop("key", "Spawned Object %06i" % randint(1,100000))
|
||||
create_kwargs["db_location"] = _handle_dbref(prot.pop("location", None))
|
||||
create_kwargs["db_home"] = _handle_dbref(prot.pop("home", settings.DEFAULT_HOME))
|
||||
create_kwargs["db_destination"] = _handle_dbref(prot.pop("destination", None))
|
||||
create_kwargs["db_typeclass_path"] = prot.pop("typeclass", settings.BASE_OBJECT_TYPECLASS)
|
||||
|
||||
# extract calls to handlers
|
||||
permission_string = prot.pop("permissions", "")
|
||||
lock_string = prot.pop("locks", "")
|
||||
alias_string = prot.pop("aliases", "")
|
||||
|
||||
# extract ndb assignments
|
||||
nattributes = dict((key.split("_", 1)[1], value if callable(value) else value)
|
||||
for key, value in prot.items() if key.startswith("ndb_"))
|
||||
|
||||
# the rest are attributes
|
||||
attributes = dict((key, value() if callable(value) else value)
|
||||
for key, value in prot.items()
|
||||
if not (key in _CREATE_OBJECT_KWARGS or key in nattributes))
|
||||
|
||||
# pack for call into _batch_create_object
|
||||
objsparams.append( (create_kwargs, permission_string, lock_string,
|
||||
alias_string, nattributes, attributes) )
|
||||
|
||||
return _batch_create_object(*objsparams)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# testing
|
||||
|
||||
protparents = {
|
||||
"NOBODY": {},
|
||||
#"INFINITE" : {
|
||||
# "prototype":"INFINITE"
|
||||
#},
|
||||
"GOBLIN" : {
|
||||
"key": "goblin grunt",
|
||||
"health": lambda: randint(20,30),
|
||||
"resists": ["cold", "poison"],
|
||||
"attacks": ["fists"],
|
||||
"weaknesses": ["fire", "light"]
|
||||
},
|
||||
"GOBLIN_WIZARD" : {
|
||||
"prototype": "GOBLIN",
|
||||
"key": "goblin wizard",
|
||||
"spells": ["fire ball", "lighting bolt"]
|
||||
},
|
||||
"GOBLIN_ARCHER" : {
|
||||
"prototype": "GOBLIN",
|
||||
"key": "goblin archer",
|
||||
"attacks": ["short bow"]
|
||||
},
|
||||
"ARCHWIZARD" : {
|
||||
"attacks": ["archwizard staff"],
|
||||
},
|
||||
"GOBLIN_ARCHWIZARD" : {
|
||||
"key": "goblin archwizard",
|
||||
"prototype" : ("GOBLIN_WIZARD", "ARCHWIZARD")
|
||||
}
|
||||
}
|
||||
# test
|
||||
print [o.key for o in spawn(protparents["GOBLIN"], protparents["GOBLIN_ARCHWIZARD"], prototype_parents=protparents)]
|
||||
Loading…
Add table
Add a link
Reference in a new issue