成分¶
Contrib,ChrisLR,2021 年
使用元件/組合方法擴充套件typeclasses。
組成部分Contrib¶
這contrib 向Evennia 介紹了元件和成分。 每個「元件」類別代表將在 typeclass 例項上「啟用」的功能。 您可以在執行時在整個 typeclass 或單一物件上註冊這些元件。 它透過使用 Evennia 的 AttributeHandler 支援持久屬性和記憶體屬性。
優點¶
您可以在多個 typeclasses 之間重複使用某個功能,而無需繼承
您可以將每個功能清楚地組織到一個獨立的類別中。
您可以檢查物件是否支援某個功能,而無需檢查其例項。
缺點¶
它引入了額外的複雜性。
需要主機 typeclass 例項。
如何安裝¶
要啟用對 typeclass 的元件支援, 匯入並繼承ComponentHolderMixin,與此類似
from evennia.contrib.base_systems.components import ComponentHolderMixin
class Character(ComponentHolderMixin, DefaultCharacter):
# ...
元件需要繼承Component類,並且需要唯一的名稱。 元件可以繼承自其他元件,但必須指定另一個名稱。 您可以將相同的“槽”指派給兩個元件以獲得替代實作。
from evennia.contrib.base_systems.components import Component
class Health(Component):
name = "health"
class ItemHealth(Health):
name = "item_health"
slot = "health"
元件可以在類別層級定義 DBFields 或 NDBFields。 DBField 將使用字首鍵將其值儲存在主機的 DB 中。 NDBField 會將其值儲存在主機的 NDB 中並且不會保留。 使用的金鑰將為“component_name::field_name”。 他們在幕後使用AttributeProperty。
例子:
from evennia.contrib.base_systems.components import Component, DBField
class Health(Component):
health = DBField(default=1)
請注意,預設值是可選的,預設為“無”。
將元件新增至主機也會出現類似的名稱tag,其中「元件」作為類別。 名為 health 的元件將顯示為 key=”health,category=“components”。 這允許您透過使用 tag 搜尋來檢索具有特定元件的物件。
也可以使用 TagField 以相同的方式新增元件 Tags。 TagField 接受預設值,可用於儲存單一或多個tags。 新增元件時會自動新增預設值。 如果刪除元件,則元件 Tags 將從主機中清除。
例子:
from evennia.contrib.base_systems.components import Component, TagField
class Health(Component):
resistances = TagField()
vulnerability = TagField(default="fire", enforce_single=True)
本例中的「resistances」欄位可以設定多次,並且它將保留新增的tags。 本例中的「漏洞」欄位將用新欄位覆蓋先前的 tag。
每個typeclass使用ComponentHolderMixin可以宣告它的元件 透過 ComponentProperty 在班級中。 這些元件將始終出現在 typeclass 中。 您也可以傳遞 kwargs 來覆寫預設值 範例
from evennia.contrib.base_systems.components import ComponentHolderMixin
class Character(ComponentHolderMixin, DefaultCharacter):
health = ComponentProperty("health", hp=10, max_hp=50)
然後您可以使用character.components.health 來訪問它。 也存在縮寫形式 character.cmp.health。 character.health 也可以訪問,但僅限於 typeclasses 該元件定義在類別上。
或者,您可以在執行時新增這些元件。 您必須透過元件處理程式存取它們。 例子
character = self
vampirism = components.Vampirism.create(character)
character.components.add(vampirism)
...
vampirism = character.components.get("vampirism")
# Alternatively
vampirism = character.cmp.vampirism
請記住,必須匯入所有元件才能在清單中可見。 因此,我建議將它們重新組合到一個包中。 然後,您可以匯入該套件的 init 中的所有元件
由於 Evennia import typeclasses 以及 python 匯入的行為 我建議將元件包放在 typeclass 包內。 換句話說,在 typeclass 資料夾中建立一個名為 Components 的資料夾。 然後,在「typeclasses/init.py」檔案內將匯入新增至資料夾中,例如
from typeclasses import components
這樣可以確保匯入typeclasses時元件包也會被匯入。 您還需要匯入包自己的“typeclasses/components/init.py”檔案中的每個元件。 您只需要從那裡匯入每個模組/檔案,但匯入正確的類別是一個很好的做法。
from typeclasses.components.health import Health
from typeclasses.components import health
上面的兩個例子都可以工作。
已知問題¶
將可變預設值(例如列表)分配給 DBField 將在例項之間共用它。 為了避免這種情況,您必須在欄位上設定 autocreate=True,如下所示。
health = DBField(default=[], autocreate=True)
完整範例¶
from evennia.contrib.base_systems import components
# This is the Component class
class Health(components.Component):
name = "health"
# Stores the current and max values as Attributes on the host, defaulting to 100
current = components.DBField(default=100)
max = components.DBField(default=100)
def damage(self, value):
if self.current <= 0:
return
self.current -= value
if self.current > 0:
return
self.current = 0
self.on_death()
def heal(self, value):
hp = self.current
hp += value
if hp >= self.max_hp:
hp = self.max_hp
self.current = hp
@property
def is_dead(self):
return self.current <= 0
def on_death(self):
# Behavior is defined on the typeclass
self.host.on_death()
# This is how the Character inherits the mixin and registers the component 'health'
class Character(ComponentHolderMixin, DefaultCharacter):
health = ComponentProperty("health")
# This is an example of a command that checks for the component
class Attack(Command):
key = "attack"
aliases = ('melee', 'hit')
def at_pre_cmd(self):
caller = self.caller
targets = self.caller.search(args, quiet=True)
valid_target = None
for target in targets:
# Attempt to retrieve the component, None is obtained if it does not exist.
if target.components.health:
valid_target = target
if not valid_target:
caller.msg("You can't attack that!")
return True
此檔案頁面是從evennia\contrib\base_systems\components\README.md產生的。對此的更改
檔案將被覆蓋,因此請編輯該檔案而不是此檔案。