Skip to content

API Reference

This documentation is automatically generated directly from PyToNingans Python source code, docstrings, type annotations, and method signatures using mkdocstrings.


Modpack Controller API

pytoningans.core.api.BaseModPack

Base class for shared modpack logic in pack.py. Provides shared state, lifecycle hooks, and context menu actions for all child entities.

Source code in src/pytoningans/core/api/modpack.py
class BaseModPack:
    """
    Base class for shared modpack logic in `pack.py`.
    Provides shared state, lifecycle hooks, and context menu actions for all child entities.
    """

    def __init__(self, pack_info: Any = None) -> None:
        self.pack_info: Any = pack_info
        self.shared_state: dict[str, Any] = {}

    def on_pack_loaded(self) -> None:
        """Called when the modpack manifest and controller are loaded into memory."""
        pass

    def on_entity_spawned(self, entity: IBaseEntity) -> None:
        """Called whenever any child entity belonging to this pack is spawned on screen."""
        pass

    def get_context_menu_actions(self, entity: IBaseEntity) -> list[PackMenuAction]:
        """
        Returns custom context menu action buttons to display when right-clicking
        an entity belonging to this pack.
        """
        return []

on_pack_loaded

on_pack_loaded()

Called when the modpack manifest and controller are loaded into memory.

Source code in src/pytoningans/core/api/modpack.py
def on_pack_loaded(self) -> None:
    """Called when the modpack manifest and controller are loaded into memory."""
    pass

on_entity_spawned

on_entity_spawned(entity)

Called whenever any child entity belonging to this pack is spawned on screen.

Source code in src/pytoningans/core/api/modpack.py
def on_entity_spawned(self, entity: IBaseEntity) -> None:
    """Called whenever any child entity belonging to this pack is spawned on screen."""
    pass

get_context_menu_actions

get_context_menu_actions(entity)

Returns custom context menu action buttons to display when right-clicking an entity belonging to this pack.

Source code in src/pytoningans/core/api/modpack.py
def get_context_menu_actions(self, entity: IBaseEntity) -> list[PackMenuAction]:
    """
    Returns custom context menu action buttons to display when right-clicking
    an entity belonging to this pack.
    """
    return []

pytoningans.core.api.PackMenuAction dataclass

Action button added to an entity's desktop context menu by its parent modpack.

Source code in src/pytoningans/core/api/modpack.py
@dataclass(slots=True, kw_only=True)
class PackMenuAction:
    """Action button added to an entity's desktop context menu by its parent modpack."""
    label: str
    callback: Callable[[], None]
    tooltip: str = ""

Entity & Component Protocols

pytoningans.core.api.IModInfo

Bases: Protocol

Metadata and runtime configuration for a loaded mod.

Source code in src/pytoningans/core/api/protocols.py
@runtime_checkable
class IModInfo(Protocol):
    """Metadata and runtime configuration for a loaded mod."""
    current_mod_name: str
    current_mod_folder: str
    entity_type: str
    max_health: int
    attack_damage: int
    attack_range: int
    jump_height: int
    move_speed: float
    regen_rate: float
    can_fly: bool
    can_climb_walls: bool
    can_move_windows: bool
    window_move_mode: str
    ignore_window_physics: bool
    behavior_type: BehaviorType
    attack_type: AttackType
    plain_dialogue: list[str]
    death_dialogue: list[str]
    death_animation: DeathAnimation
    auto_close_on_death: bool
    fade_in_on_spawn: bool
    instance_names: list[str]

pytoningans.core.api.IEntity

Bases: IBaseEntity, Protocol

Living desktop entity with health, AI, combat, and dialogue.

Source code in src/pytoningans/core/api/protocols.py
@runtime_checkable
class IEntity(IBaseEntity, Protocol):
    """Living desktop entity with health, AI, combat, and dialogue."""
    is_dead: bool
    current_health: int
    regen_rate: float
    target_pos: Optional[Pos2D]
    behavior_type: BehaviorType
    entity_manager: Optional[IEntityManager]
    held_item: Optional[IItem]

    def jump(self) -> None:
        """Causes the entity to jump upwards if grounded."""
        ...

    def take_damage(self, amount: int) -> None:
        """Inflicts damage on the entity, flashing tint effect and triggering death if depleted."""
        ...

    def heal(self, amount: int) -> None:
        """Restores health up to max health, updating health indicators and visuals."""
        ...

    def die(self) -> None:
        """Triggers the entity's death sequence and animations."""
        ...

    def revive(self) -> None:
        """Restores health to max and revives the entity to an idle state."""
        ...

    def force_talk(self) -> None:
        """Displays a random line from the mod's plain dialogue pool."""
        ...

    def say(self, text: str, duration_ms: int = 4000, is_death: bool = False) -> None:
        """Displays a speech bubble with the given text for duration_ms milliseconds."""
        ...

    def pick_up(self, item: IItem) -> bool:
        """Picks up an item if one is not already held."""
        ...

    def drop_item(self) -> Optional[IItem]:
        """Drops the currently held item."""
        ...

    def use_item(self) -> bool:
        """Uses the currently held item."""
        ...

jump

jump()

Causes the entity to jump upwards if grounded.

Source code in src/pytoningans/core/api/protocols.py
def jump(self) -> None:
    """Causes the entity to jump upwards if grounded."""
    ...

take_damage

take_damage(amount)

Inflicts damage on the entity, flashing tint effect and triggering death if depleted.

Source code in src/pytoningans/core/api/protocols.py
def take_damage(self, amount: int) -> None:
    """Inflicts damage on the entity, flashing tint effect and triggering death if depleted."""
    ...

heal

heal(amount)

Restores health up to max health, updating health indicators and visuals.

Source code in src/pytoningans/core/api/protocols.py
def heal(self, amount: int) -> None:
    """Restores health up to max health, updating health indicators and visuals."""
    ...

die

die()

Triggers the entity's death sequence and animations.

Source code in src/pytoningans/core/api/protocols.py
def die(self) -> None:
    """Triggers the entity's death sequence and animations."""
    ...

revive

revive()

Restores health to max and revives the entity to an idle state.

Source code in src/pytoningans/core/api/protocols.py
def revive(self) -> None:
    """Restores health to max and revives the entity to an idle state."""
    ...

force_talk

force_talk()

Displays a random line from the mod's plain dialogue pool.

Source code in src/pytoningans/core/api/protocols.py
def force_talk(self) -> None:
    """Displays a random line from the mod's plain dialogue pool."""
    ...

say

say(text, duration_ms=4000, is_death=False)

Displays a speech bubble with the given text for duration_ms milliseconds.

Source code in src/pytoningans/core/api/protocols.py
def say(self, text: str, duration_ms: int = 4000, is_death: bool = False) -> None:
    """Displays a speech bubble with the given text for duration_ms milliseconds."""
    ...

pick_up

pick_up(item)

Picks up an item if one is not already held.

Source code in src/pytoningans/core/api/protocols.py
def pick_up(self, item: IItem) -> bool:
    """Picks up an item if one is not already held."""
    ...

drop_item

drop_item()

Drops the currently held item.

Source code in src/pytoningans/core/api/protocols.py
def drop_item(self) -> Optional[IItem]:
    """Drops the currently held item."""
    ...

use_item

use_item()

Uses the currently held item.

Source code in src/pytoningans/core/api/protocols.py
def use_item(self) -> bool:
    """Uses the currently held item."""
    ...

pytoningans.core.api.BaseComponent

Base class for writing custom mod components in pure Python.

Source code in src/pytoningans/core/api/components.py
class BaseComponent:
    """Base class for writing custom mod components in pure Python."""
    name: str = "custom"

    def __init__(self, owner: Optional[IBaseEntity] = None) -> None:
        self.owner: Optional[IBaseEntity] = owner
        self.enabled: bool = True

    def on_attach(self) -> None:
        """Called immediately after being attached to an owner entity."""
        pass

    def update(self, dt: int) -> None:
        """Called every frame update with the delta time in milliseconds."""
        pass

    def on_detach(self) -> None:
        """Called when the component is removed or the owner is destroyed."""
        pass

on_attach

on_attach()

Called immediately after being attached to an owner entity.

Source code in src/pytoningans/core/api/components.py
def on_attach(self) -> None:
    """Called immediately after being attached to an owner entity."""
    pass

update

update(dt)

Called every frame update with the delta time in milliseconds.

Source code in src/pytoningans/core/api/components.py
def update(self, dt: int) -> None:
    """Called every frame update with the delta time in milliseconds."""
    pass

on_detach

on_detach()

Called when the component is removed or the owner is destroyed.

Source code in src/pytoningans/core/api/components.py
def on_detach(self) -> None:
    """Called when the component is removed or the owner is destroyed."""
    pass

Custom Behaviors & AI Hooks

pytoningans.core.api.BaseEntityBehavior

Inherit from this class in your entity's behavior.py. Override any of the hook methods below to implement custom AI logic, interactions, combat rules, or dialogue responses.

Source code in src/pytoningans/core/api/behaviors.py
class BaseEntityBehavior:
    """
    Inherit from this class in your entity's `behavior.py`.
    Override any of the hook methods below to implement custom AI logic, interactions,
    combat rules, or dialogue responses.
    """
    def on_spawn(self, entity: IEntity) -> None:
        """Called once when the entity is instantiated and placed in a world."""
        pass

    def on_update(self, entity: IEntity, dt: int) -> None:
        """Called every frame tick. Use for real-time timers and state monitoring."""
        pass

    def on_decision_tick(self, entity: IEntity) -> bool:
        """
        Called when the engine's AI brain evaluates a wander or action decision.
        Return True to override default engine movement/action behavior.
        """
        return False

    def on_interact(self, entity: IEntity, other_entity: IEntity) -> bool:
        """
        Called when this entity collides with or approaches another living entity.
        Return True to override the default social interaction.
        """
        return False

    def on_item_interact(self, entity: IEntity, item: IItem) -> bool:
        """
        Called when this entity collides with or touches an item on the ground.
        Return True to override default collision handling (e.g. automatically picking up).
        """
        return False

    def on_seek_item(self, entity: IEntity, available_items: list[IItem]) -> Optional[IItem] | bool:
        """
        Called when the entity evaluates seeking an item (e.g. survival or scavenging).
        - Return a specific IItem to actively pathfind towards it.
        - Return True to indicate custom seeking was handled (skips default search).
        - Return False or None to allow default survival seeking (e.g. seeking healing items when low on HP) to run.
        """
        return None

    def on_speak(self, entity: IEntity, text: str) -> None:
        """Called whenever this entity speaks dialogue via say() or force_talk()."""
        pass

    def on_damage(self, entity: IEntity, amount: int) -> None:
        """Called when the entity takes damage."""
        pass

    def on_death(self, entity: IEntity) -> None:
        """Called immediately after the entity's health drops to 0."""
        pass

    def on_revive(self, entity: IEntity) -> None:
        """Called when the entity is revived from death."""
        pass

    def on_attack(self, entity: IEntity, target: IEntity) -> bool:
        """
        Called when the entity initiates an attack against target.
        Return True to override engine combat resolution.
        """
        return False

    def on_state_change(self, entity: IEntity, old_state: str, new_state: str) -> None:
        """Called whenever the entity's state changes (e.g. idle -> moving)."""
        pass

    def on_hover_enter(self, entity: IEntity) -> None:
        """Called when the mouse cursor enters the entity's bounding area."""
        pass

    def on_hover_leave(self, entity: IEntity) -> None:
        """Called when the mouse cursor leaves the entity's bounding area."""
        pass

    def on_cursor_grabbed(self, entity: IEntity) -> None:
        """Called when this entity grabs control of the OS mouse cursor."""
        pass

    def on_cursor_released(self, entity: IEntity) -> None:
        """Called when this entity releases the OS mouse cursor."""
        pass

on_spawn

on_spawn(entity)

Called once when the entity is instantiated and placed in a world.

Source code in src/pytoningans/core/api/behaviors.py
def on_spawn(self, entity: IEntity) -> None:
    """Called once when the entity is instantiated and placed in a world."""
    pass

on_update

on_update(entity, dt)

Called every frame tick. Use for real-time timers and state monitoring.

Source code in src/pytoningans/core/api/behaviors.py
def on_update(self, entity: IEntity, dt: int) -> None:
    """Called every frame tick. Use for real-time timers and state monitoring."""
    pass

on_decision_tick

on_decision_tick(entity)

Called when the engine's AI brain evaluates a wander or action decision. Return True to override default engine movement/action behavior.

Source code in src/pytoningans/core/api/behaviors.py
def on_decision_tick(self, entity: IEntity) -> bool:
    """
    Called when the engine's AI brain evaluates a wander or action decision.
    Return True to override default engine movement/action behavior.
    """
    return False

on_interact

on_interact(entity, other_entity)

Called when this entity collides with or approaches another living entity. Return True to override the default social interaction.

Source code in src/pytoningans/core/api/behaviors.py
def on_interact(self, entity: IEntity, other_entity: IEntity) -> bool:
    """
    Called when this entity collides with or approaches another living entity.
    Return True to override the default social interaction.
    """
    return False

on_item_interact

on_item_interact(entity, item)

Called when this entity collides with or touches an item on the ground. Return True to override default collision handling (e.g. automatically picking up).

Source code in src/pytoningans/core/api/behaviors.py
def on_item_interact(self, entity: IEntity, item: IItem) -> bool:
    """
    Called when this entity collides with or touches an item on the ground.
    Return True to override default collision handling (e.g. automatically picking up).
    """
    return False

on_seek_item

on_seek_item(entity, available_items)

Called when the entity evaluates seeking an item (e.g. survival or scavenging). - Return a specific IItem to actively pathfind towards it. - Return True to indicate custom seeking was handled (skips default search). - Return False or None to allow default survival seeking (e.g. seeking healing items when low on HP) to run.

Source code in src/pytoningans/core/api/behaviors.py
def on_seek_item(self, entity: IEntity, available_items: list[IItem]) -> Optional[IItem] | bool:
    """
    Called when the entity evaluates seeking an item (e.g. survival or scavenging).
    - Return a specific IItem to actively pathfind towards it.
    - Return True to indicate custom seeking was handled (skips default search).
    - Return False or None to allow default survival seeking (e.g. seeking healing items when low on HP) to run.
    """
    return None

on_speak

on_speak(entity, text)

Called whenever this entity speaks dialogue via say() or force_talk().

Source code in src/pytoningans/core/api/behaviors.py
def on_speak(self, entity: IEntity, text: str) -> None:
    """Called whenever this entity speaks dialogue via say() or force_talk()."""
    pass

on_damage

on_damage(entity, amount)

Called when the entity takes damage.

Source code in src/pytoningans/core/api/behaviors.py
def on_damage(self, entity: IEntity, amount: int) -> None:
    """Called when the entity takes damage."""
    pass

on_death

on_death(entity)

Called immediately after the entity's health drops to 0.

Source code in src/pytoningans/core/api/behaviors.py
def on_death(self, entity: IEntity) -> None:
    """Called immediately after the entity's health drops to 0."""
    pass

on_revive

on_revive(entity)

Called when the entity is revived from death.

Source code in src/pytoningans/core/api/behaviors.py
def on_revive(self, entity: IEntity) -> None:
    """Called when the entity is revived from death."""
    pass

on_attack

on_attack(entity, target)

Called when the entity initiates an attack against target. Return True to override engine combat resolution.

Source code in src/pytoningans/core/api/behaviors.py
def on_attack(self, entity: IEntity, target: IEntity) -> bool:
    """
    Called when the entity initiates an attack against target.
    Return True to override engine combat resolution.
    """
    return False

on_state_change

on_state_change(entity, old_state, new_state)

Called whenever the entity's state changes (e.g. idle -> moving).

Source code in src/pytoningans/core/api/behaviors.py
def on_state_change(self, entity: IEntity, old_state: str, new_state: str) -> None:
    """Called whenever the entity's state changes (e.g. idle -> moving)."""
    pass

on_hover_enter

on_hover_enter(entity)

Called when the mouse cursor enters the entity's bounding area.

Source code in src/pytoningans/core/api/behaviors.py
def on_hover_enter(self, entity: IEntity) -> None:
    """Called when the mouse cursor enters the entity's bounding area."""
    pass

on_hover_leave

on_hover_leave(entity)

Called when the mouse cursor leaves the entity's bounding area.

Source code in src/pytoningans/core/api/behaviors.py
def on_hover_leave(self, entity: IEntity) -> None:
    """Called when the mouse cursor leaves the entity's bounding area."""
    pass

on_cursor_grabbed

on_cursor_grabbed(entity)

Called when this entity grabs control of the OS mouse cursor.

Source code in src/pytoningans/core/api/behaviors.py
def on_cursor_grabbed(self, entity: IEntity) -> None:
    """Called when this entity grabs control of the OS mouse cursor."""
    pass

on_cursor_released

on_cursor_released(entity)

Called when this entity releases the OS mouse cursor.

Source code in src/pytoningans/core/api/behaviors.py
def on_cursor_released(self, entity: IEntity) -> None:
    """Called when this entity releases the OS mouse cursor."""
    pass

Settings & Engine Configuration

pytoningans.core.settings.SettingsManager

Bases: QObject

Source code in src/pytoningans/core/settings.py
class SettingsManager(QObject):
    settings_changed = Signal()
    _instance: Optional[SettingsManager] = None

    def __init__(self) -> None:
        super().__init__()
        self.settings: AppSettings = AppSettings()
        self.load()

    @classmethod
    def get(cls) -> SettingsManager:
        if cls._instance is None:
            cls._instance = SettingsManager()
        return cls._instance

    def load(self) -> None:
        path: Path = get_settings_path()
        if path.exists():
            try:
                data: dict[str, Any] = json.loads(path.read_text(encoding="utf-8"))
                self.settings = AppSettings(
                    health_bar_mode=data.get("health_bar_mode", HealthBarMode.ON_DAMAGE),
                    show_damage_numbers=data.get("show_damage_numbers", True),
                    show_health_numbers=data.get("show_health_numbers", True),
                    enable_health_shake=data.get("enable_health_shake", True),
                    auto_hide_delay_ms=data.get("auto_hide_delay_ms", 3000),
                    enable_window_physics=data.get("enable_window_physics", True),
                    avoid_window_spawn=data.get("avoid_window_spawn", True),
                    spawn_area_mode=data.get("spawn_area_mode", "screen"),
                    enable_debug_mode=data.get("enable_debug_mode", False),
                    creator_name=data.get("creator_name", "Modder"),
                    creator_bio=data.get("creator_bio", ""),
                    creator_avatar_path=data.get("creator_avatar_path", ""),
                )
            except Exception as e:
                print(f"Warning: Failed to load settings from {path}: {e}")
                self.settings = AppSettings()
        else:
            self.settings = AppSettings()

    def save(self) -> None:
        path: Path = get_settings_path()
        try:
            path.write_text(json.dumps(asdict(self.settings), indent=2), encoding="utf-8")
        except Exception as e:
            print(f"Warning: Failed to save settings to {path}: {e}")

    def update_settings(
        self,
        health_bar_mode: Optional[str] = None,
        show_damage_numbers: Optional[bool] = None,
        show_health_numbers: Optional[bool] = None,
        enable_health_shake: Optional[bool] = None,
        auto_hide_delay_ms: Optional[int] = None,
        enable_window_physics: Optional[bool] = None,
        avoid_window_spawn: Optional[bool] = None,
        spawn_area_mode: Optional[str] = None,
        enable_debug_mode: Optional[bool] = None,
        creator_name: Optional[str] = None,
        creator_bio: Optional[str] = None,
        creator_avatar_path: Optional[str] = None,
    ) -> None:
        changed: bool = False
        if health_bar_mode is not None and self.settings.health_bar_mode != health_bar_mode:
            self.settings.health_bar_mode = health_bar_mode
            changed = True
        if show_damage_numbers is not None and self.settings.show_damage_numbers != show_damage_numbers:
            self.settings.show_damage_numbers = show_damage_numbers
            changed = True
        if show_health_numbers is not None and self.settings.show_health_numbers != show_health_numbers:
            self.settings.show_health_numbers = show_health_numbers
            changed = True
        if enable_health_shake is not None and self.settings.enable_health_shake != enable_health_shake:
            self.settings.enable_health_shake = enable_health_shake
            changed = True
        if auto_hide_delay_ms is not None and self.settings.auto_hide_delay_ms != auto_hide_delay_ms:
            self.settings.auto_hide_delay_ms = auto_hide_delay_ms
            changed = True
        if enable_window_physics is not None and self.settings.enable_window_physics != enable_window_physics:
            self.settings.enable_window_physics = enable_window_physics
            changed = True
        if avoid_window_spawn is not None and self.settings.avoid_window_spawn != avoid_window_spawn:
            self.settings.avoid_window_spawn = avoid_window_spawn
            changed = True
        if spawn_area_mode is not None and self.settings.spawn_area_mode != spawn_area_mode:
            self.settings.spawn_area_mode = spawn_area_mode
            changed = True
        if enable_debug_mode is not None and self.settings.enable_debug_mode != enable_debug_mode:
            self.settings.enable_debug_mode = enable_debug_mode
            changed = True
        if creator_name is not None and self.settings.creator_name != creator_name.strip():
            self.settings.creator_name = creator_name.strip()
            changed = True
        if creator_bio is not None and self.settings.creator_bio != creator_bio.strip():
            self.settings.creator_bio = creator_bio.strip()
            changed = True
        if creator_avatar_path is not None and self.settings.creator_avatar_path != creator_avatar_path.strip():
            self.settings.creator_avatar_path = creator_avatar_path.strip()
            changed = True

        if changed:
            self.save()
            self.settings_changed.emit()

    def reset_to_defaults(self) -> None:
        self.settings = AppSettings()
        self.save()
        self.settings_changed.emit()

pytoningans.core.settings.AppSettings dataclass

Global user preferences and application configuration settings.

Source code in src/pytoningans/core/settings.py
@dataclass(slots=True, kw_only=True)
class AppSettings:
    """Global user preferences and application configuration settings."""
    health_bar_mode: str = HealthBarMode.ON_DAMAGE
    show_damage_numbers: bool = True
    show_health_numbers: bool = True
    enable_health_shake: bool = True
    auto_hide_delay_ms: int = 3000
    enable_window_physics: bool = True
    avoid_window_spawn: bool = True
    spawn_area_mode: str = "screen"
    enable_debug_mode: bool = False
    creator_name: str = "Modder"
    creator_bio: str = ""
    creator_avatar_path: str = ""

pytoningans.core.settings.HealthBarMode

Bases: StrEnum

Source code in src/pytoningans/core/settings.py
@unique
class HealthBarMode(StrEnum):
    ON_DAMAGE = "on_damage"
    ALWAYS = "always"
    HIDDEN = "hidden"