diff options
| author | 2025-10-25 00:30:48 +0800 | |
|---|---|---|
| committer | 2025-10-25 00:30:48 +0800 | |
| commit | cbc653ffd0ea9abf4360623dc7a7651e1a49cc61 (patch) | |
| tree | ea3c396148158077bae3e77eaa9341f8c1990636 /examples/plugins | |
| parent | 08299b37dfda86e56e4f2b442f68ccd2da7a82e3 (diff) | |
| download | conventional_role_play-cbc653ffd0ea9abf4360623dc7a7651e1a49cc61.tar.gz conventional_role_play-cbc653ffd0ea9abf4360623dc7a7651e1a49cc61.zip | |
feat: Implement plugin system with combat tracker and dice analyzer
- Added `plugin_system_demo.py` to demonstrate basic plugin usage, processing, and analysis.
- Created `CombatTrackerPlugin` for tracking combat statistics including damage and healing.
- Developed `DiceAnalyzerPlugin` for analyzing dice rolls and calculating success rates.
- Introduced `renderer_demo.py` for rendering output in HTML, Markdown, and JSON formats.
- Implemented `rule_system_demo.py` to showcase rule engine capabilities with various examples.
- Established core rule engine functionality in `rules.py` with support for conditions and actions.
- Enhanced base plugin structure in `base.py` to support different plugin types (Processor, Renderer, Analyzer).
- Added custom exception handling in `exceptions.py` for better error management.
- Configured logging setup in `logging_config.py` for improved logging capabilities.
- Created unit tests in `test_rust_core.py` to validate core functionalities and performance.
Diffstat (limited to 'examples/plugins')
| -rw-r--r-- | examples/plugins/combat_tracker_plugin.py | 96 | ||||
| -rw-r--r-- | examples/plugins/dice_analyzer_plugin.py | 90 |
2 files changed, 186 insertions, 0 deletions
diff --git a/examples/plugins/combat_tracker_plugin.py b/examples/plugins/combat_tracker_plugin.py new file mode 100644 index 0000000..a12bc9e --- /dev/null +++ b/examples/plugins/combat_tracker_plugin.py @@ -0,0 +1,96 @@ +import sys +import os +from pathlib import Path +import re +from typing import Any, Dict, List + +sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) + +from conventionalrp.plugins.base import ProcessorPlugin + + +class CombatTrackerPlugin(ProcessorPlugin): + """战斗数据追踪插件""" + + def __init__(self): + super().__init__("CombatTracker", "1.0.0") + self.damage_pattern = re.compile(r'(\d+)\s*点?(伤害|damage|dmg)', re.IGNORECASE) + self.heal_pattern = re.compile(r'(\d+)\s*点?(治疗|healing|heal)', re.IGNORECASE) + + def initialize(self, config: Dict[str, Any] | None = None): + self.config = config or {} + self.total_damage = 0 + self.total_healing = 0 + self.character_stats = {} + self.logger.info("CombatTrackerPlugin initialized") + + def process_token(self, token: Dict[str, Any]) -> Dict[str, Any]: + content = token.get("content", "") + speaker = token.get("speaker", "Unknown") + + damage_match = self.damage_pattern.search(content) + if damage_match: + damage = int(damage_match.group(1)) + self.total_damage += damage + + if speaker not in self.character_stats: + self.character_stats[speaker] = {"damage_dealt": 0, "healing_done": 0} + self.character_stats[speaker]["damage_dealt"] += damage + + token["combat_data"] = { + "type": "damage", + "amount": damage, + "total_damage": self.total_damage, + } + + heal_match = self.heal_pattern.search(content) + if heal_match: + healing = int(heal_match.group(1)) + self.total_healing += healing + + if speaker not in self.character_stats: + self.character_stats[speaker] = {"damage_dealt": 0, "healing_done": 0} + self.character_stats[speaker]["healing_done"] += healing + + token["combat_data"] = { + "type": "healing", + "amount": healing, + "total_healing": self.total_healing, + } + + return token + + def get_combat_summary(self) -> Dict[str, Any]: + return { + "total_damage": self.total_damage, + "total_healing": self.total_healing, + "net_damage": self.total_damage - self.total_healing, + "character_stats": self.character_stats, + } + + def reset_stats(self): + self.total_damage = 0 + self.total_healing = 0 + self.character_stats.clear() + self.logger.info("Combat stats reset") + + +if __name__ == "__main__": + plugin = CombatTrackerPlugin() + plugin.initialize() + + test_tokens = [ + {"type": "dialogue", "speaker": "战士", "content": "我攻击兽人,造成12点伤害"}, + {"type": "dialogue", "speaker": "法师", "content": "火球术命中,造成28点伤害"}, + {"type": "dialogue", "speaker": "牧师", "content": "治疗术,恢复15点生命值"}, + {"type": "dialogue", "speaker": "战士", "content": "再次攻击,造成8点伤害"}, + ] + + for token in test_tokens: + processed = plugin.process_token(token) + if "combat_data" in processed: + print(f" {processed['speaker']}: {processed['combat_data']}") + + summary = plugin.get_combat_summary() + for key, value in summary.items(): + print(f" {key}: {value}") diff --git a/examples/plugins/dice_analyzer_plugin.py b/examples/plugins/dice_analyzer_plugin.py new file mode 100644 index 0000000..3ab2fb9 --- /dev/null +++ b/examples/plugins/dice_analyzer_plugin.py @@ -0,0 +1,90 @@ +import sys +import os +from pathlib import Path +import re +from typing import Any, Dict, List + +sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src")) + +from conventionalrp.plugins.base import AnalyzerPlugin + + +class DiceAnalyzerPlugin(AnalyzerPlugin): + """骰子投掷数据分析插件""" + def __init__(self): + super().__init__("DiceAnalyzer", "1.0.0") + self.dice_pattern = re.compile(r'd(\d+)') + + def initialize(self, config: Dict[str, Any] | None = None): + self.config = config or {} + self.logger.info("DiceAnalyzerPlugin initialized") + + def analyze(self, data: Any) -> Dict[str, Any]: + if not isinstance(data, list): + return {"error": "Input must be a list of tokens"} + + total_rolls = 0 + dice_types = {} + success_count = 0 + failure_count = 0 + critical_hits = 0 + critical_fails = 0 + + for token in data: + if not isinstance(token, dict): + continue + + token_type = token.get("type", "") + content = token.get("content", "") + + if token_type == "dice": + total_rolls += 1 + + match = self.dice_pattern.search(content) + if match: + dice_type = f"d{match.group(1)}" + dice_types[dice_type] = dice_types.get(dice_type, 0) + 1 + + if token_type == "success": + success_count += 1 + elif token_type == "failure": + failure_count += 1 + + if "critical" in content.lower(): + if "success" in token_type or "成功" in content: + critical_hits += 1 + elif "failure" in token_type or "失败" in content: + critical_fails += 1 + + result = { + "total_rolls": total_rolls, + "dice_types": dice_types, + "success_count": success_count, + "failure_count": failure_count, + "critical_hits": critical_hits, + "critical_fails": critical_fails, + "success_rate": success_count / total_rolls if total_rolls > 0 else 0, + "critical_rate": (critical_hits + critical_fails) / total_rolls if total_rolls > 0 else 0, + } + + self.logger.info(f"Analyzed {total_rolls} dice rolls") + return result + + +if __name__ == "__main__": + plugin = DiceAnalyzerPlugin() + plugin.initialize() + + test_data = [ + {"type": "dice", "content": "d20=15"}, + {"type": "success", "content": "检定成功"}, + {"type": "dice", "content": "d6=4"}, + {"type": "dice", "content": "d20=20"}, + {"type": "success", "content": "大成功!Critical hit!"}, + {"type": "dice", "content": "d20=1"}, + {"type": "failure", "content": "大失败..."}, + ] + + result = plugin.analyze(test_data) + for key, value in result.items(): + print(f" {key}: {value}") |
