Custom attributes for players and plugins

This commit is contained in:
Ben 2020-05-17 03:21:34 +01:00
parent ef2e32c473
commit 4288248864
7 changed files with 108 additions and 1 deletions

View File

@ -722,6 +722,34 @@ COMMENT ON TABLE penguin_permission IS 'Penguin permissions';
COMMENT ON COLUMN penguin_permission.penguin_id IS 'Penguin ID'; COMMENT ON COLUMN penguin_permission.penguin_id IS 'Penguin ID';
COMMENT ON COLUMN penguin_permission.permission_id IS 'Penguin permission ID'; COMMENT ON COLUMN penguin_permission.permission_id IS 'Penguin permission ID';
DROP TABLE IF EXISTS penguin_attribute;
CREATE TABLE penguin_attribute (
name TEXT NOT NULL,
penguin_id INT NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (name, penguin_id),
CONSTRAINT penguin_attribute_ibfk_1 FOREIGN KEY (penguin_id) REFERENCES penguin(id) ON DELETE CASCADE ON UPDATE CASCADE
);
COMMENT ON TABLE penguin_attribute IS 'Custom penguin attributes';
COMMENT ON COLUMN penguin_attribute.name IS 'Attribute unique identifier';
COMMENT ON COLUMN penguin_attribute.penguin_id IS 'Penguin ID';
COMMENT ON COLUMN penguin_attribute.value IS 'Value of attribute';
DROP TABLE IF EXISTS plugin_attribute;
CREATE TABLE plugin_attribute (
name TEXT NOT NULL,
plugin_name TEXT NOT NULL,
value TEXT NOT NULL,
PRIMARY KEY (name, plugin_name)
);
COMMENT ON TABLE plugin_attribute IS 'Custom plugin attributes';
COMMENT ON COLUMN plugin_attribute.name IS 'Attribute unique identifier';
COMMENT ON COLUMN plugin_attribute.plugin_name IS 'Name of plugin attribute belongs to';
COMMENT ON COLUMN plugin_attribute.value IS 'Value of attribute';
DROP TABLE IF EXISTS report; DROP TABLE IF EXISTS report;
CREATE TABLE report ( CREATE TABLE report (

View File

@ -114,6 +114,12 @@ class PenguinStringCompiler(OrderedDict):
return getattr(p, attribute_name) or 0 return getattr(p, attribute_name) or 0
return attribute_method return attribute_method
@classmethod
def custom_attribute_by_name(cls, attribute_name):
async def attribute_method(p):
return p.get_custom_attribute(attribute_name, 0)
return attribute_method
@classmethod @classmethod
def setup_default_builder(cls, string_builder): def setup_default_builder(cls, string_builder):
string_builder.update({ string_builder.update({

View File

@ -84,6 +84,7 @@ class Penguin(db.Model):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.inventory = None self.inventory = None
self.permissions = None self.permissions = None
self.attributes = None
self.igloos = None self.igloos = None
self.igloo_rooms = None self.igloo_rooms = None
self.furniture = None self.furniture = None

30
houdini/data/plugin.py Normal file
View File

@ -0,0 +1,30 @@
from houdini.data import db, AbstractDataCollection
class PluginAttribute(db.Model):
__tablename__ = 'plugin_attribute'
plugin_name = db.Column(db.Text, primary_key=True, nullable=False)
name = db.Column(db.Text, primary_key=True, nullable=False)
value = db.Column(db.Text)
class PenguinAttribute(db.Model):
__tablename__ = 'penguin_attribute'
penguin_id = db.Column(db.ForeignKey('penguin.id', ondelete='CASCADE', onupdate='CASCADE'), primary_key=True,
nullable=False)
name = db.Column(db.Text, primary_key=True, nullable=False)
value = db.Column(db.Text)
class PenguinAttributeCollection(AbstractDataCollection):
__model__ = PenguinAttribute
__indexby__ = 'name'
__filterby__ = 'penguin_id'
class PluginAttributeCollection(AbstractDataCollection):
__model__ = PluginAttribute
__indexby__ = 'name'
__filterby__ = 'plugin_name'

View File

@ -4,6 +4,7 @@ import time
from houdini import handlers from houdini import handlers
from houdini.data.item import Item, ItemCollection, PenguinItemCollection from houdini.data.item import Item, ItemCollection, PenguinItemCollection
from houdini.data.permission import PenguinPermissionCollection from houdini.data.permission import PenguinPermissionCollection
from houdini.data.plugin import PenguinAttributeCollection
from houdini.handlers import Priority, XMLPacket, XTPacket from houdini.handlers import Priority, XMLPacket, XTPacket
@ -45,6 +46,7 @@ async def items_load(server):
async def load_inventory(p): async def load_inventory(p):
p.inventory = await PenguinItemCollection.get_collection(p.id) p.inventory = await PenguinItemCollection.get_collection(p.id)
p.permissions = await PenguinPermissionCollection.get_collection(p.id) p.permissions = await PenguinPermissionCollection.get_collection(p.id)
p.attributes = await PenguinAttributeCollection.get_collection(p.id)
if p.color is not None and p.color not in p.inventory: if p.color is not None and p.color not in p.inventory:
await p.inventory.insert(item_id=p.color) await p.inventory.insert(item_id=p.color)

View File

@ -263,8 +263,28 @@ class Penguin(Spheniscidae, penguin.Penguin):
async def add_permission(self, permission): async def add_permission(self, permission):
if permission not in self.permissions: if permission not in self.permissions:
await self.permissions.insert(name=permission) await self.permissions.insert(name=permission)
def get_custom_attribute(self, name, default=None):
penguin_attribute = self.attributes.get(name, default)
if penguin_attribute == default:
return default
return penguin_attribute.value
self.logger.info(f'{self.username} was assigned permission \'{permission}\'') async def set_custom_attribute(self, name, value):
if name not in self.attributes:
await self.attributes.insert(name=name, value=value)
else:
attribute = self.attributes[name]
await attribute.update(value=value).apply()
self.logger.info(f'{self.username} set custom attribute \'{name}\' to \'{value}\'')
return True
async def delete_custom_attribute(self, name):
if name in self.attributes:
await self.attributes.delete(name)
self.logger.info(f'{self.username} deleted attribute \'{name}\'')
return True return True

View File

@ -2,6 +2,7 @@ import inspect
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from houdini import _AbstractManager, get_package_modules from houdini import _AbstractManager, get_package_modules
from houdini.data.plugin import PluginAttributeCollection
class IPlugin(ABC): class IPlugin(ABC):
@ -28,9 +29,27 @@ class IPlugin(ABC):
async def ready(self): async def ready(self):
"""Called when the plugin is ready to function.""" """Called when the plugin is ready to function."""
def get_attribute(self, name, default=None):
plugin_attribute = self.attributes.get(name, default)
if plugin_attribute == default:
return default
return plugin_attribute.value
async def set_attribute(self, name, value):
if name not in self.attributes:
await self.attributes.insert(name=name, value=value)
else:
plugin_attribute = self.attributes.get(name)
await plugin_attribute.update(value=value).apply()
async def delete_attribute(self, name):
if name in self.attributes:
await self.attributes.delete(name)
@abstractmethod @abstractmethod
def __init__(self, server): def __init__(self, server):
self.server = server self.server = server
self.attributes = None
class PluginManager(_AbstractManager): class PluginManager(_AbstractManager):
@ -58,6 +77,7 @@ class PluginManager(_AbstractManager):
await self.server.xml_listeners.load(plugin_object) await self.server.xml_listeners.load(plugin_object)
await self.server.dummy_event_listeners.load(plugin_object) await self.server.dummy_event_listeners.load(plugin_object)
plugin_object.attributes = await PluginAttributeCollection.get_collection(plugin_index)
await plugin_object.ready() await plugin_object.ready()