152 lines
5.5 KiB
Python
152 lines
5.5 KiB
Python
import os
|
||
import csv
|
||
from src.classes.map import Map
|
||
from src.classes.tile import TileType
|
||
from src.classes.region import Region, NormalRegion, CultivateRegion, CityRegion
|
||
from src.classes.sect_region import SectRegion
|
||
from src.utils.df import game_configs, get_str, get_int
|
||
from src.classes.essence import EssenceType
|
||
from src.classes.sect import sects_by_id # 直接导入已加载的宗门数据
|
||
|
||
# 静态配置路径
|
||
CONFIG_DIR = os.path.join(os.path.dirname(__file__), "../../static/game_configs")
|
||
|
||
def load_cultivation_world_map() -> Map:
|
||
"""
|
||
从静态 CSV 文件加载修仙世界地图。
|
||
读取: tile_map.csv, region_map.csv
|
||
以及: normal/city/cultivate/sect_region.csv
|
||
"""
|
||
tile_csv = os.path.join(CONFIG_DIR, "tile_map.csv")
|
||
region_csv = os.path.join(CONFIG_DIR, "region_map.csv")
|
||
|
||
if not os.path.exists(tile_csv) or not os.path.exists(region_csv):
|
||
raise FileNotFoundError(f"Map data files not found in {CONFIG_DIR}")
|
||
|
||
# 1. 读取 Tile Map 以确定尺寸
|
||
with open(tile_csv, 'r', encoding='utf-8') as f:
|
||
tile_rows = list(csv.reader(f))
|
||
|
||
height = len(tile_rows)
|
||
width = len(tile_rows[0]) if height > 0 else 0
|
||
|
||
game_map = Map(width=width, height=height)
|
||
|
||
# 2. 填充 Tile Type
|
||
for y, row in enumerate(tile_rows):
|
||
for x, tile_name in enumerate(row):
|
||
if x < width:
|
||
try:
|
||
t_type = TileType[tile_name.upper()]
|
||
except KeyError:
|
||
# 如果不是标准地形,则是宗门驻地名称
|
||
# 这些名称直接对应 SECT 类型
|
||
t_type = TileType.SECT
|
||
|
||
game_map.create_tile(x, y, t_type)
|
||
|
||
# 3. 读取 Region Map 并聚合坐标
|
||
# region_coords: { region_id: [(x, y), ...] }
|
||
region_coords = {}
|
||
|
||
with open(region_csv, 'r', encoding='utf-8') as f:
|
||
region_rows = list(csv.reader(f))
|
||
|
||
for y, row in enumerate(region_rows):
|
||
if y >= height: break
|
||
for x, val in enumerate(row):
|
||
if x >= width: break
|
||
try:
|
||
rid = int(val)
|
||
if rid != -1:
|
||
if rid not in region_coords:
|
||
region_coords[rid] = []
|
||
region_coords[rid].append((x, y))
|
||
except ValueError:
|
||
continue
|
||
|
||
# 4. 加载 Region 元数据并创建对象
|
||
_load_and_assign_regions(game_map, region_coords)
|
||
|
||
# 5. 更新缓存
|
||
game_map.update_sect_regions()
|
||
|
||
return game_map
|
||
|
||
def _load_and_assign_regions(game_map: Map, region_coords: dict[int, list[tuple[int, int]]]):
|
||
"""
|
||
读取各 region.csv,创建 Region 对象,并分配给 Map 和 Tile
|
||
"""
|
||
|
||
# 辅助函数:处理 Region 数据
|
||
def process_region_config(df, cls, type_tag):
|
||
for row in df:
|
||
rid = get_int(row, "id")
|
||
|
||
if rid not in region_coords:
|
||
continue
|
||
|
||
cors = region_coords[rid]
|
||
|
||
# 构建参数
|
||
params = {
|
||
"id": rid,
|
||
"name": get_str(row, "name"),
|
||
"desc": get_str(row, "desc"),
|
||
"cors": cors,
|
||
}
|
||
|
||
# 特有字段处理
|
||
if type_tag == "normal":
|
||
params["animal_ids"] = _parse_list(get_str(row, "animal_ids"))
|
||
params["plant_ids"] = _parse_list(get_str(row, "plant_ids"))
|
||
elif type_tag == "cultivate":
|
||
params["essence_type"] = EssenceType.from_str(get_str(row, "root_type"))
|
||
params["essence_density"] = get_int(row, "root_density")
|
||
elif type_tag == "sect":
|
||
sect_id = get_int(row, "sect_id")
|
||
params["sect_id"] = sect_id
|
||
|
||
# 直接从已加载的 sects_by_id 中获取宗门对象
|
||
# 如果找不到对应的 sect_id,默认使用驻地名称作为兜底(防止崩溃),但正常情况下应该能找到
|
||
sect_obj = sects_by_id.get(sect_id)
|
||
if sect_obj:
|
||
params["sect_name"] = sect_obj.name
|
||
else:
|
||
params["sect_name"] = get_str(row, "name")
|
||
|
||
# 实例化
|
||
try:
|
||
region_obj = cls(**params)
|
||
game_map.regions[rid] = region_obj
|
||
game_map.region_names[region_obj.name] = region_obj
|
||
|
||
# 写入 Map 缓存 (region_cors)
|
||
game_map.region_cors[rid] = cors
|
||
|
||
# 绑定到 Tiles
|
||
for rx, ry in cors:
|
||
if game_map.is_in_bounds(rx, ry):
|
||
game_map.tiles[(rx, ry)].region = region_obj
|
||
|
||
except Exception as e:
|
||
print(f"Error creating region {rid}: {e}")
|
||
|
||
# 执行加载
|
||
process_region_config(game_configs["normal_region"], NormalRegion, "normal")
|
||
process_region_config(game_configs["city_region"], CityRegion, "city")
|
||
process_region_config(game_configs["cultivate_region"], CultivateRegion, "cultivate")
|
||
process_region_config(game_configs["sect_region"], SectRegion, "sect")
|
||
|
||
def _parse_list(s: str) -> list[int]:
|
||
if not s: return []
|
||
res = []
|
||
for x in s.split(","):
|
||
x = x.strip()
|
||
if x:
|
||
try:
|
||
res.append(int(float(x)))
|
||
except (ValueError, TypeError):
|
||
pass
|
||
return res
|