fix(level-builder): 锚点补偿+旋转修复+天空盒+解析器去重
- asset_mapping: 38种BSP资产实测锚点+pivot_offset_xy自动补偿 - scene_builder: Rotator改关键字参数修正旋转轴映射 - scene_builder: spawn前XY锚点补偿(支持Yaw旋转) - scene_builder: 新增ExponentialHeightFog+大气效果后处理 - build_cmdline: 构建后自动添加雾+GameMode+DirectionalLight大气 - build_guide_parser: 去重+全局地面+旋转列名兼容+边界段范围修正 - BarrierWall实际尺寸修正(60×210非20×100) - 搭建指南: 全局地面中心坐标+西边界旋转统一+院门改双开门
This commit is contained in:
@@ -138,6 +138,9 @@ class BuildGuideParser:
|
||||
# 添加 Player Start
|
||||
self._add_player_start()
|
||||
|
||||
# 去重:检测同名称 Actor,保留后出现的
|
||||
self._deduplicate_actors()
|
||||
|
||||
# 构建输出
|
||||
result = {
|
||||
"metadata": self.metadata,
|
||||
@@ -163,11 +166,15 @@ class BuildGuideParser:
|
||||
# Phase B — 地面
|
||||
# ----------------------------------------------------------
|
||||
def _parse_phase_ground(self, lines: list[str]):
|
||||
"""解析 Phase B 地面铺设表格。"""
|
||||
text = "\n".join(lines)
|
||||
# 找到 Phase B 区域
|
||||
b_start = self._find_section_start(lines, "Phase B")
|
||||
b_end = self._find_section_start(lines, "Phase C")
|
||||
"""解析 Phase B 地面铺设表格。仅处理 B1 铺设地面段,不处理 B2 边界段。"""
|
||||
# 找到地面铺设段起始
|
||||
b_start = self._find_section_start(lines, "铺设地面")
|
||||
if b_start < 0:
|
||||
b_start = self._find_section_start(lines, "Phase B")
|
||||
# 地面段在边界段前结束
|
||||
b_end = self._find_section_start(lines, "放置边界围挡")
|
||||
if b_end < 0:
|
||||
b_end = self._find_section_start(lines, "Phase C")
|
||||
if b_start < 0:
|
||||
return
|
||||
if b_end < 0:
|
||||
@@ -175,10 +182,13 @@ class BuildGuideParser:
|
||||
|
||||
section_text = "\n".join(lines[b_start:b_end])
|
||||
|
||||
# 地面子区域标题:#### Z1 家 地面(MI_DevGray)
|
||||
# 地面子区域标题:#### Z1 家 地面(MI_DevGray)或 #### 全局地面(MI_DevGray)
|
||||
floor_pattern = re.compile(
|
||||
r'####\s+Z(\d+)\s+\S+\s+地面(?:((.+?)))?'
|
||||
)
|
||||
global_floor_pattern = re.compile(
|
||||
r'####\s+全局地面(?:((.+?)))?'
|
||||
)
|
||||
|
||||
current_zone = ""
|
||||
current_material = ""
|
||||
@@ -196,6 +206,14 @@ class BuildGuideParser:
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# 检测全局地面
|
||||
gm = global_floor_pattern.match(line)
|
||||
if gm:
|
||||
current_zone = "GLOBAL"
|
||||
current_material = gm.group(1) or "MI_DevGray"
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# 检测水面区域
|
||||
if '水面' in line and current_zone:
|
||||
current_material = "MI_DevSkyBlue"
|
||||
@@ -289,7 +307,11 @@ class BuildGuideParser:
|
||||
|
||||
asset_key = clean_cell(row.get("资产", ""))
|
||||
location = parse_location(row.get("位置 (X,Y,Z)", row.get("位置", "")))
|
||||
rotation = parse_rotation(row.get("旋转 (Pitch,Yaw,Roll)", row.get("旋转", "(0,0,0)")))
|
||||
rotation = parse_rotation(
|
||||
row.get("旋转 (Pitch,Yaw,Roll)")
|
||||
or row.get("旋转 (P,Y,R)")
|
||||
or row.get("旋转", "(0,0,0)")
|
||||
)
|
||||
scale = parse_scale(row.get("缩放", "—"))
|
||||
material = clean_cell(row.get("材质", ""))
|
||||
|
||||
@@ -309,7 +331,11 @@ class BuildGuideParser:
|
||||
def _expand_range_row(self, row: dict, name: str) -> list[ActorData]:
|
||||
"""展开范围格式行。如 'LVL_BND_East_01~15' → 15 个 Actor。"""
|
||||
asset_key = clean_cell(row.get("资产", ""))
|
||||
rotation = parse_rotation(row.get("旋转 (Pitch,Yaw,Roll)", row.get("旋转", "(0,0,0)")))
|
||||
rotation = parse_rotation(
|
||||
row.get("旋转 (Pitch,Yaw,Roll)")
|
||||
or row.get("旋转 (P,Y,R)")
|
||||
or row.get("旋转", "(0,0,0)")
|
||||
)
|
||||
scale = parse_scale(row.get("缩放", "—"))
|
||||
material = clean_cell(row.get("材质", ""))
|
||||
|
||||
@@ -478,7 +504,10 @@ class BuildGuideParser:
|
||||
)
|
||||
|
||||
# 旋转:结构体表可能有,布景表可能没有
|
||||
rot_col = row.get("旋转 (Pitch,Yaw,Roll)", row.get("旋转", ""))
|
||||
# 兼容多种列名格式:(Pitch,Yaw,Roll)、(P,Y,R)、无后缀
|
||||
rot_col = (row.get("旋转 (Pitch,Yaw,Roll)")
|
||||
or row.get("旋转 (P,Y,R)")
|
||||
or row.get("旋转", ""))
|
||||
rotation = parse_rotation(rot_col) if rot_col else (0.0, 0.0, 0.0)
|
||||
|
||||
# 缩放
|
||||
@@ -724,6 +753,33 @@ class BuildGuideParser:
|
||||
note="Z1 院内院门内侧约60cm,面向+Y(北)",
|
||||
))
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 去重
|
||||
# ----------------------------------------------------------
|
||||
def _deduplicate_actors(self):
|
||||
"""去除同名称的重复 Actor,保留后出现的(后出现的通常是更完整的定义)。"""
|
||||
seen = {}
|
||||
unique = []
|
||||
for actor in self.actors:
|
||||
name = actor.actor_name
|
||||
if name in seen:
|
||||
# 同名但位置不同——可能是合法的同名(如 Z3 墙段),保留
|
||||
prev = seen[name]
|
||||
if prev.location == actor.location and prev.asset_key == actor.asset_key:
|
||||
logger.warning(f"去重:移除重复 Actor '{name}' (loc={actor.location})")
|
||||
continue # 跳过完全重复的
|
||||
else:
|
||||
# 同名但不同位置/资产——合法,保留
|
||||
unique.append(actor)
|
||||
else:
|
||||
seen[name] = actor
|
||||
unique.append(actor)
|
||||
|
||||
removed = len(self.actors) - len(unique)
|
||||
if removed > 0:
|
||||
logger.info(f"去重完成:移除 {removed} 个重复 Actor")
|
||||
self.actors = unique
|
||||
|
||||
# ----------------------------------------------------------
|
||||
# 辅助方法
|
||||
# ----------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user