feat: initial commit

This commit is contained in:
2026-06-23 20:29:02 +08:00
commit ea8f6066c4
217 changed files with 60754 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
"""
Core Engine Validators
物理校验模块,处理元叙事开关和物理连贯性验证。
"""
from .fourth_wall_validator import (
FourthWallValidator,
FourthWallState,
ValidationMode,
PhysicalRule,
ValidationRule,
ValidationIssue,
get_validator,
enable_meta_mode,
disable_meta_mode,
is_meta_mode,
)
__all__ = [
"FourthWallValidator",
"FourthWallState",
"ValidationMode",
"PhysicalRule",
"ValidationRule",
"ValidationIssue",
"get_validator",
"enable_meta_mode",
"disable_meta_mode",
"is_meta_mode",
]
@@ -0,0 +1,395 @@
"""
Fourth Wall Validator (第四面墙校验器)
当元叙事开关开启时,关闭物理连贯性校验,
允许"反规则"写法:梦境、意识流、打破第四面墙等。
当开关关闭时,恢复标准物理校验。
"""
from dataclasses import dataclass, field
from typing import List, Optional, Dict, Any
from enum import Enum
import json
class ValidationMode(Enum):
NORMAL = "normal" # 标准物理校验
META = "meta" # 元叙事模式,跳过物理校验
class PhysicalRule(Enum):
"""物理校验规则类型"""
REALM_CONSISTENCY = "realm_consistency" # 境界一致性
TIME_CONTINUITY = "time_continuity" # 时间连续性
LOCATION_COHERENCE = "location_coherence" # 地点连贯性
POWER_BALANCE = "power_balance" # 战力平衡
CAUSALITY = "causality" # 因果关系
@dataclass
class ValidationRule:
"""校验规则"""
type: PhysicalRule
enabled: bool
description: str
severity: str = "high" # critical/high/medium/low
@dataclass
class ValidationIssue:
"""校验问题"""
rule: PhysicalRule
chapter: int
description: str
severity: str
entity_id: Optional[str] = None
suggested_fix: Optional[str] = None
@dataclass
class FourthWallState:
"""第四面墙状态"""
mode: ValidationMode = ValidationMode.NORMAL
enabled_rules: List[PhysicalRule] = field(default_factory=list)
bypassed_rules: List[PhysicalRule] = field(default_factory=list)
@property
def is_meta_mode(self) -> bool:
return self.mode == ValidationMode.META
class FourthWallValidator:
"""
第四面墙校验器
用法:
1. 当 Meta_Narrative_Panel.jsx 的 Toggle 开启时,调用 enable_meta_mode()
2. 当 Toggle 关闭时,调用 disable_meta_mode()
3. 验证时调用 validate() 方法
"""
# 默认启用的物理校验规则
DEFAULT_ENABLED_RULES = [
PhysicalRule.REALM_CONSISTENCY,
PhysicalRule.TIME_CONTINUITY,
PhysicalRule.LOCATION_COHERENCE,
PhysicalRule.POWER_BALANCE,
PhysicalRule.CAUSALITY,
]
# 元叙事模式下放行的规则(这些在元叙事模式下被跳过)
META_BYPASSABLE_RULES = [
PhysicalRule.TIME_CONTINUITY, # 允许时间跳跃
PhysicalRule.LOCATION_COHERENCE, # 允许瞬间移动
PhysicalRule.POWER_BALANCE, # 允许战力波动
]
def __init__(self):
self._state = FourthWallState(
enabled_rules=list(self.DEFAULT_ENABLED_RULES),
bypassed_rules=[]
)
self._listeners: List[callable] = []
@property
def state(self) -> FourthWallState:
return self._state
def enable_meta_mode(self) -> None:
"""开启元叙事模式,关闭物理校验"""
self._state.mode = ValidationMode.META
self._state.bypassed_rules = list(self.META_BYPASSABLE_RULES)
self._notify_listeners()
print("[FourthWall] 元叙事模式已激活 - 物理校验已关闭")
def disable_meta_mode(self) -> None:
"""关闭元叙事模式,恢复物理校验"""
self._state.mode = ValidationMode.NORMAL
self._state.bypassed_rules = []
self._notify_listeners()
print("[FourthWall] 标准模式已激活 - 物理校验已恢复")
def toggle(self) -> ValidationMode:
"""切换模式"""
if self._state.is_meta_mode:
self.disable_meta_mode()
else:
self.enable_meta_mode()
return self._state.mode
def validate(
self,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]] = None
) -> List[ValidationIssue]:
"""
验证章节物理连贯性
在元叙事模式下,返回空列表(跳过所有物理校验)
"""
issues: List[ValidationIssue] = []
# 元叙事模式:跳过所有物理校验
if self._state.is_meta_mode:
return issues
# 标准模式:执行校验
for rule_type in self._state.enabled_rules:
if rule_type not in self._state.bypassed_rules:
rule_issues = self._validate_rule(
rule_type, chapter, entities, world_state, previous_state
)
issues.extend(rule_issues)
return issues
def _validate_rule(
self,
rule: PhysicalRule,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]]
) -> List[ValidationIssue]:
"""根据规则类型执行校验"""
validators = {
PhysicalRule.REALM_CONSISTENCY: self._check_realm_consistency,
PhysicalRule.TIME_CONTINUITY: self._check_time_continuity,
PhysicalRule.LOCATION_COHERENCE: self._check_location_coherence,
PhysicalRule.POWER_BALANCE: self._check_power_balance,
PhysicalRule.CAUSALITY: self._check_causality,
}
validator = validators.get(rule)
if validator:
return validator(chapter, entities, world_state, previous_state)
return []
def _check_realm_consistency(
self,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]]
) -> List[ValidationIssue]:
"""检查境界一致性"""
issues: List[ValidationIssue] = []
# 检查主角境界是否合理
protagonist = next((e for e in entities if e.get("is_protagonist")), None)
if protagonist:
current_realm = protagonist.get("realm")
previous_realm = previous_state.get("protagonist", {}).get("realm") if previous_state else None
if previous_realm and current_realm != previous_realm:
# 境界变化超过1级
if not self._is_valid_realm_jump(previous_realm, current_realm):
issues.append(ValidationIssue(
rule=PhysicalRule.REALM_CONSISTENCY,
chapter=chapter,
description=f"境界跳跃不合理: {previous_realm}{current_realm}",
severity="high",
entity_id=protagonist.get("id"),
suggested_fix="补充修炼/机缘说明"
))
return issues
def _check_time_continuity(
self,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]]
) -> List[ValidationIssue]:
"""检查时间连续性"""
issues: List[ValidationIssue] = []
current_time = world_state.get("time_of_day")
previous_time = previous_state.get("world_state", {}).get("time_of_day") if previous_state else None
if previous_time and current_time:
# 检查时间是否倒退
time_order = {"早晨": 0, "上午": 1, "中午": 2, "下午": 3, "傍晚": 4, "夜晚": 5, "深夜": 6, "凌晨": 7}
if time_order.get(previous_time, -1) > time_order.get(current_time, -1):
issues.append(ValidationIssue(
rule=PhysicalRule.TIME_CONTINUITY,
chapter=chapter,
description=f"时间倒退: {previous_time}{current_time}",
severity="medium",
suggested_fix="添加时间跳跃说明"
))
return issues
def _check_location_coherence(
self,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]]
) -> List[ValidationIssue]:
"""检查地点连贯性"""
issues: List[ValidationIssue] = []
current_loc = world_state.get("location")
previous_loc = previous_state.get("world_state", {}).get("location") if previous_state else None
protagonist = next((e for e in entities if e.get("is_protagonist")), None)
if previous_loc and current_loc and protagonist:
# 如果地点变化但没有过渡说明
if current_loc != previous_loc:
has_transition = self._check_transition_exists(chapter, previous_loc, current_loc)
if not has_transition:
issues.append(ValidationIssue(
rule=PhysicalRule.LOCATION_COHERENCE,
chapter=chapter,
description=f"地点跳跃无过渡: {previous_loc}{current_loc}",
severity="low",
entity_id=protagonist.get("id"),
suggested_fix="添加移动过程描写"
))
return issues
def _check_power_balance(
self,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]]
) -> List[ValidationIssue]:
"""检查战力平衡"""
issues: List[ValidationIssue] = []
# 检查是否有越太多级战斗
protagonist = next((e for e in entities if e.get("is_protagonist")), None)
opponents = [e for e in entities if e.get("is_opponent")]
if protagonist and opponents:
p_realm = protagonist.get("realm_level", 0)
for opp in opponents:
o_realm = opp.get("realm_level", 0)
if p_realm - o_realm > 2:
issues.append(ValidationIssue(
rule=PhysicalRule.POWER_BALANCE,
chapter=chapter,
description=f"战力差距过大: {p_realm} vs {o_realm}",
severity="medium",
entity_id=opp.get("id"),
suggested_fix="增加战斗难度或金手指解释"
))
return issues
def _check_causality(
self,
chapter: int,
entities: List[Dict[str, Any]],
world_state: Dict[str, Any],
previous_state: Optional[Dict[str, Any]]
) -> List[ValidationIssue]:
"""检查因果关系"""
# 简化实现:检查是否有突兀的力量获得
issues: List[ValidationIssue] = []
new_skills = world_state.get("new_skills_gained", [])
protagonist = next((e for e in entities if e.get("is_protagonist")), None)
if new_skills and protagonist:
has_setup = self._check_setup_exists(chapter, new_skills)
if not has_setup:
issues.append(ValidationIssue(
rule=PhysicalRule.CAUSALITY,
chapter=chapter,
description=f"突兀获得技能: {new_skills}",
severity="high",
entity_id=protagonist.get("id"),
suggested_fix="补充技能来源铺垫"
))
return issues
def _is_valid_realm_jump(self, from_realm: str, to_realm: str) -> bool:
"""判断境界跳跃是否合理"""
# 简化实现
valid_jumps = {
"炼气期一层": ["炼气期二层"],
"炼气期二层": ["炼气期三层"],
"筑基期一层": ["筑基期二层"],
}
return to_realm in valid_jumps.get(from_realm, [])
def _check_transition_exists(self, chapter: int, from_loc: str, to_loc: str) -> bool:
"""检查过渡是否存在"""
# 简化实现:应该读取章节正文检查
return False
def _check_setup_exists(self, chapter: int, skills: List[str]) -> bool:
"""检查铺垫是否存在"""
# 简化实现:应该读取章节正文检查
return False
def subscribe(self, callback: callable) -> None:
"""订阅状态变化"""
self._listeners.append(callback)
def unsubscribe(self, callback: callable) -> None:
"""取消订阅"""
if callback in self._listeners:
self._listeners.remove(callback)
def _notify_listeners(self) -> None:
"""通知所有监听器"""
for callback in self._listeners:
try:
callback(self._state)
except Exception as e:
print(f"[FourthWall] 通知监听器失败: {e}")
def get_config(self) -> Dict[str, Any]:
"""获取当前配置"""
return {
"mode": self._state.mode.value,
"enabled_rules": [r.value for r in self._state.enabled_rules],
"bypassed_rules": [r.value for r in self._state.bypassed_rules],
}
@staticmethod
def from_config(config: Dict[str, Any]) -> "FourthWallValidator":
"""从配置恢复"""
validator = FourthWallValidator()
if config.get("mode") == ValidationMode.META.value:
validator.enable_meta_mode()
return validator
# 全局实例
_validator_instance: Optional[FourthWallValidator] = None
def get_validator() -> FourthWallValidator:
"""获取全局校验器实例"""
global _validator_instance
if _validator_instance is None:
_validator_instance = FourthWallValidator()
return _validator_instance
def enable_meta_mode() -> None:
"""快捷函数:开启元叙事模式"""
get_validator().enable_meta_mode()
def disable_meta_mode() -> None:
"""快捷函数:关闭元叙事模式"""
get_validator().disable_meta_mode()
def is_meta_mode() -> bool:
"""快捷函数:检查是否在元叙事模式"""
return get_validator().state.is_meta_mode