1
0
Fork 0

add function triggers to logic system

This commit is contained in:
Sean Sube 2024-05-04 17:57:24 -05:00
parent dc00a78b57
commit 4affcb893a
Signed by: ssube
GPG Key ID: 3EED7B957D362AF1
5 changed files with 57 additions and 25 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
adventure/custom_actions.py adventure/custom_*.py
worlds/ worlds/
__pycache__/ __pycache__/
.env .env

View File

@ -9,6 +9,13 @@ from adventure.models import Actor, Item, Room, World
logger = getLogger(__name__) logger = getLogger(__name__)
OPPOSITE_DIRECTIONS = {
"north": "south",
"south": "north",
"east": "west",
"west": "east",
}
def generate_room( def generate_room(
agent: Agent, world_theme: str, existing_rooms: List[str], callback agent: Agent, world_theme: str, existing_rooms: List[str], callback
@ -147,13 +154,14 @@ def generate_world(
existing_actors: List[str] = [] existing_actors: List[str] = []
existing_items: List[str] = [] existing_items: List[str] = []
existing_rooms: List[str] = []
# generate the rooms # generate the rooms
rooms = [] rooms = []
for i in range(room_count): for i in range(room_count):
existing_rooms = [room.name for room in rooms]
room = generate_room(agent, theme, existing_rooms, callback=callback) room = generate_room(agent, theme, existing_rooms, callback=callback)
rooms.append(room) rooms.append(room)
existing_rooms.append(room.name)
item_count = randint(0, 3) item_count = randint(0, 3)
callback(f"Generating {item_count} items for room: {room.name}") callback(f"Generating {item_count} items for room: {room.name}")
@ -198,13 +206,6 @@ def generate_world(
actor.items.append(item) actor.items.append(item)
existing_items.append(item.name) existing_items.append(item.name)
opposite_directions = {
"north": "south",
"south": "north",
"east": "west",
"west": "east",
}
# generate portals to link the rooms together # generate portals to link the rooms together
for room in rooms: for room in rooms:
directions = ["north", "south", "east", "west"] directions = ["north", "south", "east", "west"]
@ -213,7 +214,7 @@ def generate_world(
logger.debug(f"Room {room.name} already has a {direction} portal") logger.debug(f"Room {room.name} already has a {direction} portal")
continue continue
opposite_direction = opposite_directions[direction] opposite_direction = OPPOSITE_DIRECTIONS[direction]
if randint(0, 1): if randint(0, 1):
dest_room = choice([r for r in rooms if r.name != room.name]) dest_room = choice([r for r in rooms if r.name != room.name])
@ -233,7 +234,7 @@ def generate_world(
# create bidirectional links # create bidirectional links
room.portals[direction] = dest_room.name room.portals[direction] = dest_room.name
dest_room.portals[opposite_directions[direction]] = room.name dest_room.portals[OPPOSITE_DIRECTIONS[direction]] = room.name
# ensure actors act in a stable order # ensure actors act in a stable order
order = [actor.name for room in rooms for actor in room.actors] order = [actor.name for room in rooms for actor in room.actors]

View File

@ -1,4 +1,3 @@
from importlib import import_module
from json import load from json import load
from logging.config import dictConfig from logging.config import dictConfig
from os import environ, path from os import environ, path
@ -12,6 +11,7 @@ from packit.toolbox import Toolbox
from packit.utils import logger_with_colors from packit.utils import logger_with_colors
from adventure.context import set_current_broadcast from adventure.context import set_current_broadcast
from adventure.plugins import load_plugin
# Configure logging # Configure logging
LOG_PATH = "logging.json" LOG_PATH = "logging.json"
@ -209,6 +209,9 @@ def parse_args():
parser.add_argument( parser.add_argument(
"--max-rooms", type=int, help="The maximum number of rooms to generate" "--max-rooms", type=int, help="The maximum number of rooms to generate"
) )
parser.add_argument(
"--optional-actions", type=bool, help="Whether to include optional actions"
)
parser.add_argument( parser.add_argument(
"--server", type=str, help="The address on which to run the server" "--server", type=str, help="The address on which to run the server"
) )
@ -326,6 +329,16 @@ def main():
) )
extra_actions.extend(module_actions) extra_actions.extend(module_actions)
if args.optional_actions:
logger.info("Loading optional actions")
from adventure.optional_actions import init as init_optional_actions
optional_actions = init_optional_actions()
logger.info(
f"Loaded optional actions: {[action.__name__ for action in optional_actions]}"
)
extra_actions.extend(optional_actions)
# load extra systems # load extra systems
def snapshot_system(world: World, step: int) -> None: def snapshot_system(world: World, step: int) -> None:
logger.debug("Snapshotting world state") logger.debug("Snapshotting world state")
@ -356,12 +369,5 @@ def main():
) )
def load_plugin(name):
module_name, function_name = name.rsplit(":", 1)
plugin_module = import_module(module_name)
plugin_entry = getattr(plugin_module, function_name)
return plugin_entry()
if __name__ == "__main__": if __name__ == "__main__":
main() main()

12
adventure/plugins.py Normal file
View File

@ -0,0 +1,12 @@
from importlib import import_module
def load_plugin(name: str, override_function: str | None = None):
plugin_entry = get_plugin_function(name, override_function)
return plugin_entry()
def get_plugin_function(name: str, override_function: str | None = None):
module_name, function_name = name.rsplit(":", 1)
plugin_module = import_module(module_name)
return getattr(plugin_module, override_function or function_name)

View File

@ -5,7 +5,8 @@ from typing import Dict, List, Optional
from pydantic import Field from pydantic import Field
from yaml import Loader, load from yaml import Loader, load
from adventure.models import World, dataclass from adventure.models import Actor, Item, Room, World, dataclass
from adventure.plugins import get_plugin_function
logger = getLogger(__name__) logger = getLogger(__name__)
@ -22,6 +23,7 @@ class LogicRule:
chance: float = 1.0 chance: float = 1.0
remove: Optional[List[str]] = None remove: Optional[List[str]] = None
set: Optional[Dict[str, str]] = None set: Optional[Dict[str, str]] = None
trigger: Optional[List[str]] = None
@dataclass @dataclass
@ -32,10 +34,17 @@ class LogicTable:
with open("./worlds/logic.yaml") as file: with open("./worlds/logic.yaml") as file:
logic_rules = LogicTable(**load(file, Loader=Loader)) logic_rules = LogicTable(**load(file, Loader=Loader))
logic_triggers = {
rule: [get_plugin_function(trigger) for trigger in rule.trigger]
for rule in logic_rules.rules
if rule.trigger
}
def update_attributes( def update_attributes(
attributes: Dict[str, str], dataset: LogicTable entity: Room | Actor | Item,
attributes: Dict[str, str],
dataset: LogicTable,
) -> Dict[str, str]: ) -> Dict[str, str]:
for rule in dataset.rules: for rule in dataset.rules:
if rule.match.items() <= attributes.items(): if rule.match.items() <= attributes.items():
@ -52,18 +61,22 @@ def update_attributes(
for key in rule.remove or []: for key in rule.remove or []:
attributes.pop(key, None) attributes.pop(key, None)
if rule in logic_triggers:
for trigger in logic_triggers[rule]:
attributes = trigger(entity, attributes)
return attributes return attributes
def update_logic(world: World, step: int) -> None: def update_logic(world: World, step: int) -> None:
for room in world.rooms: for room in world.rooms:
room.attributes = update_attributes(room.attributes, logic_rules) room.attributes = update_attributes(room, room.attributes, logic_rules)
for actor in room.actors: for actor in room.actors:
actor.attributes = update_attributes(actor.attributes, logic_rules) actor.attributes = update_attributes(actor, actor.attributes, logic_rules)
for item in actor.items: for item in actor.items:
item.attributes = update_attributes(item.attributes, logic_rules) item.attributes = update_attributes(item, item.attributes, logic_rules)
for item in room.items: for item in room.items:
item.attributes = update_attributes(item.attributes, logic_rules) item.attributes = update_attributes(item, item.attributes, logic_rules)
logger.info("updated world attributes") logger.info("updated world attributes")