Add replacable Trait classes
This commit is contained in:
parent
485ab5907c
commit
e0717fd07c
5 changed files with 183 additions and 115 deletions
|
|
@ -237,20 +237,59 @@ Examples:
|
||||||
```
|
```
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
from evennia.utils.dbserialize import _SaverDict
|
from evennia.utils.dbserialize import _SaverDict
|
||||||
from evennia.utils import logger
|
from evennia.utils import logger
|
||||||
from evennia.utils.utils import inherits_from
|
from evennia.utils.utils import inherits_from, class_from_module
|
||||||
|
|
||||||
|
|
||||||
|
# This way the user can easily supply their own. Each
|
||||||
|
# class should have a class-property `trait_type` to
|
||||||
|
# identify the Trait class. The default ones are "static",
|
||||||
|
# "counter" and "gauge".
|
||||||
|
|
||||||
STATIC_TYPE = "static"
|
_TRAIT_CLASS_PATHS = [
|
||||||
COUNTER_TYPE = "counter",
|
"evennia.contrib.traits.StaticTrait",
|
||||||
GAUGE_TYPE = "gauge"
|
"evennia.contrib.traits.CounterTrait",
|
||||||
|
"evennia.contrib.traits.GaugeTrait",
|
||||||
|
]
|
||||||
|
|
||||||
|
if hasattr(settings, "TRAIT_CLASS_PATHS"):
|
||||||
|
_TRAIT_CLASS_PATHS += settings.TRAIT_CLASS_PATHS
|
||||||
|
|
||||||
|
# delay trait-class import to avoid circular import
|
||||||
|
_TRAIT_CLASSES = None
|
||||||
|
|
||||||
|
|
||||||
TRAIT_TYPES = (STATIC_TYPE, COUNTER_TYPE, GAUGE_TYPE)
|
def _delayed_import_trait_classes():
|
||||||
RANGE_TRAITS = (COUNTER_TYPE, GAUGE_TYPE)
|
"""
|
||||||
|
Import classes based on the given paths. Note that
|
||||||
|
imports from settings are last in the list, so if they
|
||||||
|
have the same trait_type set, they will replace the
|
||||||
|
default.
|
||||||
|
"""
|
||||||
|
global _TRAIT_CLASSES
|
||||||
|
if _TRAIT_CLASSES is None:
|
||||||
|
_TRAIT_CLASSES = {}
|
||||||
|
for classpath in _TRAIT_CLASS_PATHS:
|
||||||
|
try:
|
||||||
|
cls = class_from_module(classpath)
|
||||||
|
except ImportError:
|
||||||
|
logger.log_trace(f"Could not import Trait from {classpath}.")
|
||||||
|
else:
|
||||||
|
if hasattr(cls, "trait_type"):
|
||||||
|
trait_type = cls.trait_type
|
||||||
|
else:
|
||||||
|
trait_type = str(cls.__name___).lower()
|
||||||
|
_TRAIT_CLASSES[trait_type] = cls
|
||||||
|
|
||||||
|
|
||||||
|
_GA = object.__getattribute__
|
||||||
|
_SA = object.__setattr__
|
||||||
|
|
||||||
|
# this is the default we offer in TraitHandler.add
|
||||||
|
DEFAULT_TRAIT_TYPE = "static"
|
||||||
|
|
||||||
|
|
||||||
class TraitException(Exception):
|
class TraitException(Exception):
|
||||||
|
|
@ -261,6 +300,7 @@ class TraitException(Exception):
|
||||||
msg (str): informative error message
|
msg (str): informative error message
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, msg):
|
def __init__(self, msg):
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
|
|
||||||
|
|
@ -270,7 +310,8 @@ class TraitHandler:
|
||||||
Factory class that instantiates Trait objects.
|
Factory class that instantiates Trait objects.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self, obj, db_attribute_key='traits', db_attribute_category="traits"):
|
|
||||||
|
def __init__(self, obj, db_attribute_key="traits", db_attribute_category="traits"):
|
||||||
"""
|
"""
|
||||||
Initialize the handler and set up its internal Attribute-based storage.
|
Initialize the handler and set up its internal Attribute-based storage.
|
||||||
|
|
||||||
|
|
@ -279,6 +320,9 @@ class TraitHandler:
|
||||||
db_attribute_key (str): Name of the DB attribute for trait data storage
|
db_attribute_key (str): Name of the DB attribute for trait data storage
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# load the available classes, if necessary
|
||||||
|
_delayed_import_trait_classes()
|
||||||
|
|
||||||
# Note that this retains the connection to the database, meaning every
|
# Note that this retains the connection to the database, meaning every
|
||||||
# update we do to .trait_data automatically syncs with database.
|
# update we do to .trait_data automatically syncs with database.
|
||||||
self.trait_data = obj.attributes.get(db_attribute_key, category=db_attribute_category)
|
self.trait_data = obj.attributes.get(db_attribute_key, category=db_attribute_category)
|
||||||
|
|
@ -294,8 +338,8 @@ class TraitHandler:
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
"""Returns error message if trait objects are assigned directly."""
|
"""Returns error message if trait objects are assigned directly."""
|
||||||
if key in ('trait_data', '_cache'):
|
if key in ("trait_data", "_cache"):
|
||||||
super().__setattr__(key, value)
|
_SA(self, key, value)
|
||||||
else:
|
else:
|
||||||
raise TraitException(
|
raise TraitException(
|
||||||
"Trait object not settable directly. Assign to one of "
|
"Trait object not settable directly. Assign to one of "
|
||||||
|
|
@ -306,13 +350,18 @@ class TraitHandler:
|
||||||
"""Returns error message if trait objects are assigned directly."""
|
"""Returns error message if trait objects are assigned directly."""
|
||||||
return self.__setattr__(key, value)
|
return self.__setattr__(key, value)
|
||||||
|
|
||||||
def __getattr__(self, trait):
|
def __getattr__(self, key):
|
||||||
"""Returns Trait instances accessed as attributes."""
|
"""Returns Trait instances accessed as attributes."""
|
||||||
return self.get(trait)
|
return self.get(key)
|
||||||
|
|
||||||
def __getitem__(self, trait):
|
def __getitem__(self, key):
|
||||||
"""Returns `Trait` instances accessed as dict keys."""
|
"""Returns `Trait` instances accessed as dict keys."""
|
||||||
return self.get(trait)
|
return self.get(key)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "TraitHandler ({num} Trait(s) stored): {keys}".format(
|
||||||
|
num=len(self), keys=", ".join(self.all)
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def all(self):
|
def all(self):
|
||||||
|
|
@ -325,7 +374,7 @@ class TraitHandler:
|
||||||
"""
|
"""
|
||||||
return list(self.trait_data.keys())
|
return list(self.trait_data.keys())
|
||||||
|
|
||||||
def get(self, trait):
|
def get(self, key):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
trait (str): key from the traits dict containing config data
|
trait (str): key from the traits dict containing config data
|
||||||
|
|
@ -336,14 +385,28 @@ class TraitHandler:
|
||||||
is not found in traits collection.
|
is not found in traits collection.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
trait = self._cache.get(trait)
|
trait = self._cache.get(key)
|
||||||
if trait is None and trait in self.trait_data:
|
if trait is None and key in self.trait_data:
|
||||||
trait = self.cache[trait] = Trait(self.trait_data[trait])
|
trait_type = self.trait_data[key]["trait_type"]
|
||||||
|
try:
|
||||||
|
trait_cls = _TRAIT_CLASSES[trait_type]
|
||||||
|
except KeyError:
|
||||||
|
raise TraitException("Trait class for {trait_type} could not be found.")
|
||||||
|
trait = self._cache[key] = trait_cls(self.trait_data[key])
|
||||||
return trait
|
return trait
|
||||||
|
|
||||||
def add(self, key, name=None, trait_type=STATIC_TYPE,
|
def add(
|
||||||
base=0, modifier=0, min_value=0, max_value=0,
|
self,
|
||||||
force=False, **extra_properties):
|
key,
|
||||||
|
name=None,
|
||||||
|
trait_type=DEFAULT_TRAIT_TYPE,
|
||||||
|
base=0,
|
||||||
|
modifier=0,
|
||||||
|
min_value=None,
|
||||||
|
max_value=None,
|
||||||
|
force=False,
|
||||||
|
**extra_properties,
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Create a new Trait and add it to the handler.
|
Create a new Trait and add it to the handler.
|
||||||
|
|
||||||
|
|
@ -369,13 +432,15 @@ class TraitHandler:
|
||||||
already exists (and `force` is unset).
|
already exists (and `force` is unset).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
# from evennia import set_trace;set_trace()
|
||||||
|
|
||||||
if key in self.trait_data:
|
if key in self.trait_data:
|
||||||
if force:
|
if force:
|
||||||
self.remove(key)
|
self.remove(key)
|
||||||
else:
|
else:
|
||||||
raise TraitException(f"Trait '{key}' already exists.")
|
raise TraitException(f"Trait '{key}' already exists.")
|
||||||
|
|
||||||
if trait_type not in TRAIT_TYPES:
|
if trait_type not in _TRAIT_CLASSES:
|
||||||
raise TraitException("Trait-type '{trait_type} is invalid.")
|
raise TraitException("Trait-type '{trait_type} is invalid.")
|
||||||
|
|
||||||
trait_kwargs = dict(
|
trait_kwargs = dict(
|
||||||
|
|
@ -385,7 +450,7 @@ class TraitHandler:
|
||||||
modifier=modifier,
|
modifier=modifier,
|
||||||
min_value=min_value,
|
min_value=min_value,
|
||||||
max_value=max_value,
|
max_value=max_value,
|
||||||
extra_properties=extra_properties
|
extra_properties=extra_properties,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.trait_data[key] = trait_kwargs
|
self.trait_data[key] = trait_kwargs
|
||||||
|
|
@ -402,7 +467,7 @@ class TraitHandler:
|
||||||
raise TraitException(f"Trait '{key}' not found.")
|
raise TraitException(f"Trait '{key}' not found.")
|
||||||
|
|
||||||
if key in self._cache:
|
if key in self._cache:
|
||||||
del self.cache[key]
|
del self._cache[key]
|
||||||
del self.trait_data[key]
|
del self.trait_data[key]
|
||||||
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
|
|
@ -415,6 +480,7 @@ class TraitHandler:
|
||||||
|
|
||||||
# Parent Trait class
|
# Parent Trait class
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
class Trait:
|
class Trait:
|
||||||
"""Represents an object or Character trait.
|
"""Represents an object or Character trait.
|
||||||
|
|
@ -423,8 +489,16 @@ class Trait:
|
||||||
See module docstring for configuration details.
|
See module docstring for configuration details.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_keys = set("name", "type", "base", "mod", "current",
|
_keys = (
|
||||||
"min", "max", "extra_properties")
|
"name",
|
||||||
|
"trait_type",
|
||||||
|
"base",
|
||||||
|
"modifier",
|
||||||
|
"current",
|
||||||
|
"min_value",
|
||||||
|
"max_value",
|
||||||
|
"extra_properties",
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, trait_data):
|
def __init__(self, trait_data):
|
||||||
"""
|
"""
|
||||||
|
|
@ -436,20 +510,16 @@ class Trait:
|
||||||
save itself the database when updating
|
save itself the database when updating
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if not all(key in trait_data for key in self.valid_keys):
|
|
||||||
raise TraitException(
|
|
||||||
f"Required keys missing from trait_data "
|
|
||||||
f"(input was {list(trait_data.keys())}, "
|
|
||||||
f"required are {self.valid_keys}).")
|
|
||||||
|
|
||||||
self._type = trait_data['trait_type']
|
self._type = trait_data["trait_type"]
|
||||||
self._data = trait_data
|
self._data = trait_data
|
||||||
self._locked = True
|
self._locked = True
|
||||||
|
|
||||||
if not isinstance(trait_data, _SaverDict):
|
if not isinstance(trait_data, _SaverDict):
|
||||||
logger.log_warn(
|
logger.log_warn(
|
||||||
f"Non-persistent Trait data (type(trait_data)) "
|
f"Non-persistent Trait data (type(trait_data)) "
|
||||||
f"loaded for {type(self).__name__}.")
|
f"loaded for {type(self).__name__}."
|
||||||
|
)
|
||||||
|
|
||||||
# Private helper members
|
# Private helper members
|
||||||
|
|
||||||
|
|
@ -458,7 +528,7 @@ class Trait:
|
||||||
if self._type in RANGE_TRAITS:
|
if self._type in RANGE_TRAITS:
|
||||||
if self.min is not None and value <= self.min:
|
if self.min is not None and value <= self.min:
|
||||||
return self.min
|
return self.min
|
||||||
if self._data['max'] == 'base' and value >= self.mod + self.base:
|
if self._data["max"] == "base" and value >= self.mod + self.base:
|
||||||
return self.mod + self.base
|
return self.mod + self.base
|
||||||
if self.max is not None and value >= self.max:
|
if self.max is not None and value >= self.max:
|
||||||
return self.max
|
return self.max
|
||||||
|
|
@ -474,15 +544,14 @@ class Trait:
|
||||||
"""Debug-friendly representation of this Trait."""
|
"""Debug-friendly representation of this Trait."""
|
||||||
return "{}({{{}}})".format(
|
return "{}({{{}}})".format(
|
||||||
type(self).__name__,
|
type(self).__name__,
|
||||||
', '.join(["'{}': {!r}".format(k, self._data[k])
|
", ".join(
|
||||||
for k in self._keys if k in self._data]))
|
["'{}': {!r}".format(k, self._data[k]) for k in self._keys if k in self._data]
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
status = "{actual:11}".format(actual=self.actual)
|
status = "{actual:11}".format(actual=self.actual)
|
||||||
return "{name:12} {status} ({mod:+3})".format(
|
return "{name:12} {status} ({mod:+3})".format(name=self.name, status=status, mod=self.mod)
|
||||||
name=self.name,
|
|
||||||
status=status,
|
|
||||||
mod=self.mod)
|
|
||||||
|
|
||||||
# Extra Properties - allow access to properties on Trait
|
# Extra Properties - allow access to properties on Trait
|
||||||
|
|
||||||
|
|
@ -504,12 +573,11 @@ class Trait:
|
||||||
def __getattr__(self, key):
|
def __getattr__(self, key):
|
||||||
"""Access extra parameters as attributes."""
|
"""Access extra parameters as attributes."""
|
||||||
try:
|
try:
|
||||||
return self._data['extra_properties'][key]
|
return self._data["extra_properties"][key]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
"{} '{}' has no attribute {!r}".format(
|
"{} '{}' has no attribute {!r}".format(type(self).__name__, self.name, key)
|
||||||
type(self).__name__, self.name, key
|
)
|
||||||
))
|
|
||||||
|
|
||||||
def __setattr__(self, key, value):
|
def __setattr__(self, key, value):
|
||||||
"""Set extra parameters as attributes.
|
"""Set extra parameters as attributes.
|
||||||
|
|
@ -526,16 +594,15 @@ class Trait:
|
||||||
raise AttributeError(f"Can't set attribute {key}.")
|
raise AttributeError(f"Can't set attribute {key}.")
|
||||||
propobj.fset(self, value)
|
propobj.fset(self, value)
|
||||||
else:
|
else:
|
||||||
if (self.__dict__.get('_locked', False) and
|
if self.__dict__.get("_locked", False) and key not in ("_keys",):
|
||||||
key not in ('_keys',)):
|
_GA(self, "_data")["extra_properties"][key] = value
|
||||||
self._data['extra_properties'][key] = value
|
|
||||||
else:
|
else:
|
||||||
super().__setattr__(key, value)
|
_SA(self, key, value)
|
||||||
|
|
||||||
def __delattr__(self, key):
|
def __delattr__(self, key):
|
||||||
"""Delete extra parameters as attributes."""
|
"""Delete extra parameters as attributes."""
|
||||||
if key in self._data['extra_parameters']:
|
if key in self._data["extra_properties"]:
|
||||||
del self._data['extra_parameters'][key]
|
del self._data["extra_properties"][key]
|
||||||
|
|
||||||
# Numeric operations
|
# Numeric operations
|
||||||
|
|
||||||
|
|
@ -630,7 +697,8 @@ class Trait:
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Display name for the trait."""
|
"""Display name for the trait."""
|
||||||
return self._data['name']
|
return self._data["name"]
|
||||||
|
|
||||||
key = name
|
key = name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -646,24 +714,24 @@ class Trait:
|
||||||
The setter for this property will enforce any range bounds set
|
The setter for this property will enforce any range bounds set
|
||||||
on this `Trait`.
|
on this `Trait`.
|
||||||
"""
|
"""
|
||||||
return self._data['base']
|
return self._data["base"]
|
||||||
|
|
||||||
@base.setter
|
@base.setter
|
||||||
def base(self, amount):
|
def base(self, amount):
|
||||||
if self._data.get('max', None) == 'base':
|
if self._data.get("max", None) == "base":
|
||||||
self._data['base'] = amount
|
self._data["base"] = amount
|
||||||
if type(amount) in (int, float):
|
if type(amount) in (int, float):
|
||||||
self._data['base'] = self._enforce_bounds(amount)
|
self._data["base"] = self._enforce_bounds(amount)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mod(self):
|
def mod(self):
|
||||||
"""The trait's modifier."""
|
"""The trait's modifier."""
|
||||||
return self._data['modifier']
|
return self._data["modifier"]
|
||||||
|
|
||||||
@mod.setter
|
@mod.setter
|
||||||
def mod(self, amount):
|
def mod(self, amount):
|
||||||
if type(amount) in (int, float):
|
if type(amount) in (int, float):
|
||||||
self._data['modifier'] = amount
|
self._data["modifier"] = amount
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min(self):
|
def min(self):
|
||||||
|
|
@ -675,7 +743,7 @@ class Trait:
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max(self):
|
def max(self):
|
||||||
return self._data['max_value']
|
return self._data["max_value"]
|
||||||
|
|
||||||
@max.setter
|
@max.setter
|
||||||
def max(self, value):
|
def max(self, value):
|
||||||
|
|
@ -684,7 +752,7 @@ class Trait:
|
||||||
@property
|
@property
|
||||||
def current(self):
|
def current(self):
|
||||||
"""The `current` value of the `Trait`."""
|
"""The `current` value of the `Trait`."""
|
||||||
return self._data.get('current', self.base)
|
return self._data.get("current", self.base)
|
||||||
|
|
||||||
@current.setter
|
@current.setter
|
||||||
def current(self, value):
|
def current(self, value):
|
||||||
|
|
@ -693,7 +761,7 @@ class Trait:
|
||||||
@property
|
@property
|
||||||
def extra(self):
|
def extra(self):
|
||||||
"""Returns a list containing available extra data keys."""
|
"""Returns a list containing available extra data keys."""
|
||||||
return self._data['extra'].keys()
|
return self._data["extra"].keys()
|
||||||
|
|
||||||
def reset_mod(self):
|
def reset_mod(self):
|
||||||
"""Clears any mod value to 0."""
|
"""Clears any mod value to 0."""
|
||||||
|
|
@ -710,11 +778,15 @@ class Trait:
|
||||||
|
|
||||||
# Implementation of the respective Trait types
|
# Implementation of the respective Trait types
|
||||||
|
|
||||||
|
|
||||||
class StaticTrait(Trait):
|
class StaticTrait(Trait):
|
||||||
"""
|
"""
|
||||||
Static Trait.
|
Static Trait.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
trait_type = "static"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def min(self):
|
def min(self):
|
||||||
raise TraitException(f"Static Trait {self.key} has no minimum value.")
|
raise TraitException(f"Static Trait {self.key} has no minimum value.")
|
||||||
|
|
@ -733,17 +805,16 @@ class StaticTrait(Trait):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current(self):
|
def current(self):
|
||||||
"""The `current` value of the `Trait`."""
|
"""The `current` value of the `Trait`. This is the same as base for a Static Trait."""
|
||||||
return super().current
|
return self.base
|
||||||
|
|
||||||
@current.setter
|
@current.setter
|
||||||
def current(self, value):
|
def current(self, value):
|
||||||
raise TraitException(
|
"""Current == base for Static Traits."""
|
||||||
f"Cannot set 'current' property on static Trait {self.key}.")
|
self.base = self.current = value
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
raise TraitException(
|
raise TraitException(f"Cannot reset static Trait {self.key}.")
|
||||||
f"Cannot reset static Trait {self.key}.")
|
|
||||||
|
|
||||||
|
|
||||||
class CounterTrait(Trait):
|
class CounterTrait(Trait):
|
||||||
|
|
@ -751,6 +822,9 @@ class CounterTrait(Trait):
|
||||||
Counter Trait.
|
Counter Trait.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
trait_type = "counter"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def actual(self):
|
def actual(self):
|
||||||
"The actual value of the Trait"
|
"The actual value of the Trait"
|
||||||
|
|
@ -764,13 +838,13 @@ class CounterTrait(Trait):
|
||||||
@min.setter
|
@min.setter
|
||||||
def min(self, amount):
|
def min(self, amount):
|
||||||
if amount is None:
|
if amount is None:
|
||||||
self._data['min'] = amount
|
self._data["min"] = amount
|
||||||
elif type(amount) in (int, float):
|
elif type(amount) in (int, float):
|
||||||
self._data['min'] = amount if amount < self.base else self.base
|
self._data["min"] = amount if amount < self.base else self.base
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max(self):
|
def max(self):
|
||||||
if self._data['max_value'] == 'base':
|
if self._data["max_value"] == "base":
|
||||||
return self._mod_base()
|
return self._mod_base()
|
||||||
return super().max
|
return super().max
|
||||||
|
|
||||||
|
|
@ -783,16 +857,16 @@ class CounterTrait(Trait):
|
||||||
When set this way, the property returns the value of the
|
When set this way, the property returns the value of the
|
||||||
`mod`+`base` properties.
|
`mod`+`base` properties.
|
||||||
"""
|
"""
|
||||||
if self._data['max_value'] == 'base':
|
if self._data["max_value"] == "base":
|
||||||
return self._mod_base()
|
return self._mod_base()
|
||||||
return super().max
|
return super().max
|
||||||
|
|
||||||
@max.setter
|
@max.setter
|
||||||
def max(self, value):
|
def max(self, value):
|
||||||
if value == 'base' or value is None:
|
if value == "base" or value is None:
|
||||||
self._data['max_value'] = value
|
self._data["max_value"] = value
|
||||||
elif type(value) in (int, float):
|
elif type(value) in (int, float):
|
||||||
self._data['max_value'] = value if value > self.base else self.base
|
self._data["max_value"] = value if value > self.base else self.base
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def current(self):
|
def current(self):
|
||||||
|
|
@ -802,10 +876,9 @@ class CounterTrait(Trait):
|
||||||
@current.setter
|
@current.setter
|
||||||
def current(self, value):
|
def current(self, value):
|
||||||
if type(value) in (int, float):
|
if type(value) in (int, float):
|
||||||
self._data['current'] = self._enforce_bounds(value)
|
self._data["current"] = self._enforce_bounds(value)
|
||||||
else:
|
else:
|
||||||
raise AttributeError(
|
raise AttributeError("'current' property is read-only on static 'Trait'.")
|
||||||
"'current' property is read-only on static 'Trait'.")
|
|
||||||
|
|
||||||
def percent(self):
|
def percent(self):
|
||||||
"""Returns the value formatted as a percentage."""
|
"""Returns the value formatted as a percentage."""
|
||||||
|
|
@ -822,14 +895,12 @@ class GaugeTrait(CounterTrait):
|
||||||
Gauge Trait.
|
Gauge Trait.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
trait_type = "gauge"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
status = "{actual:4} / {base:4}".format(
|
status = "{actual:4} / {base:4}".format(actual=self.actual, base=self.base)
|
||||||
actual=self.actual,
|
return "{name:12} {status} ({mod:+3})".format(name=self.name, status=status, mod=self.mod)
|
||||||
base=self.base)
|
|
||||||
return "{name:12} {status} ({mod:+3})".format(
|
|
||||||
name=self.name,
|
|
||||||
status=status,
|
|
||||||
mod=self.mod)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def actual(self):
|
def actual(self):
|
||||||
|
|
@ -844,8 +915,8 @@ class GaugeTrait(CounterTrait):
|
||||||
@mod.setter
|
@mod.setter
|
||||||
def mod(self, amount):
|
def mod(self, amount):
|
||||||
if type(amount) in (int, float):
|
if type(amount) in (int, float):
|
||||||
self._data['modifier'] = amount
|
self._data["modifier"] = amount
|
||||||
delta = amount - self._data['modifier']
|
delta = amount - self._data["modifier"]
|
||||||
if delta >= 0:
|
if delta >= 0:
|
||||||
# apply increases to current
|
# apply increases to current
|
||||||
self.current = self._enforce_bounds(self.current + delta)
|
self.current = self._enforce_bounds(self.current + delta)
|
||||||
|
|
@ -856,7 +927,7 @@ class GaugeTrait(CounterTrait):
|
||||||
@property
|
@property
|
||||||
def current(self):
|
def current(self):
|
||||||
"""The `current` value of the `Trait`."""
|
"""The `current` value of the `Trait`."""
|
||||||
return self._data.get('current', self._mod_base())
|
return self._data.get("current", self._mod_base())
|
||||||
|
|
||||||
@current.setter
|
@current.setter
|
||||||
def current(self, value):
|
def current(self, value):
|
||||||
|
|
@ -869,5 +940,4 @@ class GaugeTrait(CounterTrait):
|
||||||
Will honor the upper bound if set.
|
Will honor the upper bound if set.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.current = \
|
self.current = self._enforce_bounds(self.current + self._mod_base())
|
||||||
self._enforce_bounds(self.current + self._mod_base())
|
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@ if TELNET_ENABLED:
|
||||||
# Start telnet game connections
|
# Start telnet game connections
|
||||||
|
|
||||||
from evennia.server.portal import telnet
|
from evennia.server.portal import telnet
|
||||||
|
|
||||||
_telnet_protocol = class_from_module(settings.TELNET_PROTOCOL_CLASS)
|
_telnet_protocol = class_from_module(settings.TELNET_PROTOCOL_CLASS)
|
||||||
|
|
||||||
for interface in TELNET_INTERFACES:
|
for interface in TELNET_INTERFACES:
|
||||||
|
|
@ -285,6 +286,7 @@ if SSL_ENABLED:
|
||||||
# Start Telnet+SSL game connection (requires PyOpenSSL).
|
# Start Telnet+SSL game connection (requires PyOpenSSL).
|
||||||
|
|
||||||
from evennia.server.portal import telnet_ssl
|
from evennia.server.portal import telnet_ssl
|
||||||
|
|
||||||
_ssl_protocol = class_from_module(settings.SSL_PROTOCOL_CLASS)
|
_ssl_protocol = class_from_module(settings.SSL_PROTOCOL_CLASS)
|
||||||
|
|
||||||
for interface in SSL_INTERFACES:
|
for interface in SSL_INTERFACES:
|
||||||
|
|
@ -319,6 +321,7 @@ if SSH_ENABLED:
|
||||||
# evennia/game if necessary.
|
# evennia/game if necessary.
|
||||||
|
|
||||||
from evennia.server.portal import ssh
|
from evennia.server.portal import ssh
|
||||||
|
|
||||||
_ssh_protocol = class_from_module(settings.SSH_PROTOCOL_CLASS)
|
_ssh_protocol = class_from_module(settings.SSH_PROTOCOL_CLASS)
|
||||||
|
|
||||||
for interface in SSH_INTERFACES:
|
for interface in SSH_INTERFACES:
|
||||||
|
|
@ -328,11 +331,7 @@ if SSH_ENABLED:
|
||||||
for port in SSH_PORTS:
|
for port in SSH_PORTS:
|
||||||
pstring = "%s:%s" % (ifacestr, port)
|
pstring = "%s:%s" % (ifacestr, port)
|
||||||
factory = ssh.makeFactory(
|
factory = ssh.makeFactory(
|
||||||
{
|
{"protocolFactory": _ssh_protocol, "protocolArgs": (), "sessions": PORTAL_SESSIONS,}
|
||||||
"protocolFactory": _ssh_protocol,
|
|
||||||
"protocolArgs": (),
|
|
||||||
"sessions": PORTAL_SESSIONS,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
factory.noisy = False
|
factory.noisy = False
|
||||||
ssh_service = internet.TCPServer(port, factory, interface=interface)
|
ssh_service = internet.TCPServer(port, factory, interface=interface)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ _HTTP_WARNING = bytes(
|
||||||
_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
|
_BASE_SESSION_CLASS = class_from_module(settings.BASE_SESSION_CLASS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TelnetServerFactory(protocol.ServerFactory):
|
class TelnetServerFactory(protocol.ServerFactory):
|
||||||
"This is only to name this better in logs"
|
"This is only to name this better in logs"
|
||||||
noisy = False
|
noisy = False
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ from evennia.utils.utils import (
|
||||||
make_iter,
|
make_iter,
|
||||||
delay,
|
delay,
|
||||||
callables_from_module,
|
callables_from_module,
|
||||||
class_from_module
|
class_from_module,
|
||||||
)
|
)
|
||||||
from evennia.server.portal import amp
|
from evennia.server.portal import amp
|
||||||
from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT
|
from evennia.server.signals import SIGNAL_ACCOUNT_POST_LOGIN, SIGNAL_ACCOUNT_POST_LOGOUT
|
||||||
|
|
|
||||||
|
|
@ -972,7 +972,7 @@ REST_FRAMEWORK = {
|
||||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
|
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
|
||||||
"PAGE_SIZE": 25,
|
"PAGE_SIZE": 25,
|
||||||
# require logged in users to call API so that access checks can work on them
|
# require logged in users to call API so that access checks can work on them
|
||||||
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated", ],
|
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated",],
|
||||||
# These are the different ways people can authenticate for API requests - via
|
# These are the different ways people can authenticate for API requests - via
|
||||||
# session or with user/password. Other ways are possible, such as via tokens
|
# session or with user/password. Other ways are possible, such as via tokens
|
||||||
# or oauth, but require additional dependencies.
|
# or oauth, but require additional dependencies.
|
||||||
|
|
@ -1040,28 +1040,28 @@ PORTAL_SESSION_HANDLER_CLASS = "evennia.server.portal.portalsessionhandler.Porta
|
||||||
# so the additions have somewhere to go. These must be simple things that
|
# so the additions have somewhere to go. These must be simple things that
|
||||||
# can be pickled - stuff you could serialize to JSON is best.
|
# can be pickled - stuff you could serialize to JSON is best.
|
||||||
SESSION_SYNC_ATTRS = (
|
SESSION_SYNC_ATTRS = (
|
||||||
"protocol_key",
|
"protocol_key",
|
||||||
"address",
|
"address",
|
||||||
"suid",
|
"suid",
|
||||||
"sessid",
|
"sessid",
|
||||||
"uid",
|
"uid",
|
||||||
"csessid",
|
"csessid",
|
||||||
"uname",
|
"uname",
|
||||||
"logged_in",
|
"logged_in",
|
||||||
"puid",
|
"puid",
|
||||||
"conn_time",
|
"conn_time",
|
||||||
"cmd_last",
|
"cmd_last",
|
||||||
"cmd_last_visible",
|
"cmd_last_visible",
|
||||||
"cmd_total",
|
"cmd_total",
|
||||||
"protocol_flags",
|
"protocol_flags",
|
||||||
"server_data",
|
"server_data",
|
||||||
"cmdset_storage_string"
|
"cmdset_storage_string",
|
||||||
)
|
)
|
||||||
|
|
||||||
# The following are used for the communications between the Portal and Server.
|
# The following are used for the communications between the Portal and Server.
|
||||||
# Very dragons territory.
|
# Very dragons territory.
|
||||||
AMP_SERVER_PROTOCOL_CLASS = 'evennia.server.portal.amp_server.AMPServerProtocol'
|
AMP_SERVER_PROTOCOL_CLASS = "evennia.server.portal.amp_server.AMPServerProtocol"
|
||||||
AMP_CLIENT_PROTOCOL_CLASS = 'evennia.server.amp_client.AMPServerClientProtocol'
|
AMP_CLIENT_PROTOCOL_CLASS = "evennia.server.amp_client.AMPServerClientProtocol"
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue