Files
mtgodot-poc/audit/contracts/world.environment-weather.md
T
shenandshen c93894313a fix: 装备属性面板避让逻辑 + 多项功能更新
- item_tooltip_view.gd: 新增 avoid_rect 属性,tooltip 与装备窗口重叠时自动推到左侧
- inventory_ui.gd: 悬停装备时传入窗口矩形作为避让区域
- 包含其他累积的功能开发和测试文件
2026-09-21 16:38:59 -07:00

12 KiB
Raw Blame History

world.environment_weather —— 天空、环境、光照、昼夜、雪和天气

状态:PARTIAL

本合同检查 40250 的 .msenv 环境加载、背景/角色光照、线性雾、天空六面、云层、滤色、lens flare、风、雪粒子和地图环境生命周期。判断标准是同一份环境数据是否经过同一类调用链、在同一时序产生相同的可见状态和清理副作用;“字段已解析”或“测试能创建粒子”不能代替渲染与正式场景接入等价。

40250 参考调用链

  • GameLib/MapOutdoorRender.cpp / MapOutdoorRenderHTP.cpp / MapOutdoorRenderSTP.cpp
    • OnSetEnvironmentDataPtr 将环境数据分派到 screen filter、SkyBox 和 lens flare;渲染顺序是天空、云、环境开始、地形/角色/水/雪/特效、环境结束和 lens flare。
    • OnBeginEnvironment.msenv 的 fog near/far/color、背景方向光和角色方向光分别应用到 SpeedTree、terrain patch 和角色渲染;风强度进入森林渲染器。
    • SetEnvironmentSkyBox 使用 scale、gradient、texture render mode、六面纹理、云纹理、云高度/缩放/颜色/滚动速度,并通过 SkyBox transition 更新环境。
  • GameLib/SnowEnvironment.cpp / SnowParticle.cpp
    • 雪环境由专用粒子池、相机/世界范围、风/重力和粒子生命周期驱动,随 outdoor 渲染阶段更新和绘制,不是一次性创建的通用屏幕粒子节点。
  • Client/Eternexus/root/servercommandparser.py / game.py
    • 服务器 xmas_snow 0/1ServerCommandParser 进入 __XMasSnow_Enable,先按 __IsXMasMap 过滤,再调用 background.EnableSnow(0/1);该命令不是按地图名称自动推导天气。
  • EterLib/EnvironmentMap.cpp
    • 环境对象作为 outdoor 环境资源的生命周期边界参与加载/卸载;环境切换必须同步释放旧天空、雾、滤色、lens flare 和粒子状态。

当前端实现映射

  • formats/environment.* / extension/src/environment_builder.*
    • 已解析 .msenv 的方向光、fog、sky gradient/六面/云、filter 和 lens flare 字段;apply_environment 已创建背景 Sun、角色 CharacterLightWorldEnvironmenttexture-mode sky 已用 shader 采样六面和滚动云层。
    • filter、lens flare、wind 目前主要保存在 WorldEnvironment metadata;没有对应运行时后处理、光晕节点或 SpeedTree 风更新。fog 使用 Godot depth fog,并主动 clamp/push begin/end、curve/density 与参考端 D3D 线性雾不相同。
  • extension/src/metin2_world.cpp / project/game_scene.gd
    • .msenv 在正式地图加载时接入 Metin2World,世界卸载会移除环境节点;GameScene 会优先采用 .msenv 环境,避免兜底光照覆盖它。
    • 生产场景创建 fx/weather.gd,并由 EntityStore::apply_server_command -> M2Client.weather_changed -> GameScene._on_weather_changed 接收 xmas_snow;场景按 40250 四张排除地图过滤,并在换图后重新应用当前开关。
    • WeatherDayNightSystem 仍未实例化到正式场景;它的按地图自动天气/昼夜预设不作为 40250 生产行为。
  • project/fx/weather.gd
    • 使用跟随相机的单个 GPUParticles3D 实现 snow/rain/none,粒子数量、重力、速度和颜色可切换;它没有 40250 SnowEnvironment/SnowParticle 的池、风向、范围、渲染阶段或资源失败回退链。
  • project/weather_daynight_system.gd
    • 是当前端独立的昼夜/地图天气 helper,能计算 phase、天气和光照字典;但其地图预设与 40250 .msenv 静态环境不是同一数据源,且正式 GameScene 未消费它。

分支等价矩阵

40250 判据/副作用 当前实现 结论
.msenv 解析、地图加载、环境节点创建和卸载 formats/environment + Metin2World::load_map + apply_environment 基础链路通过;复杂地图/重入清理仍需扩展证据
背景/角色两套方向光和可见层 Sun layer 1、CharacterLight layer 2 部分等价;光照色/能量和角色渲染消费仍需逐场景比对
fog near/far/color、density/linear 分支、terrain/HTP/STP 使用 Godot depth fogbegin/end 被 clampcurve=0.5、density=0 不等价;参考的线性 D3D 雾公式和 LOD 分支没有 1:1 保持
六面天空、gradient、scale、texture mode、cloud plane/UV Godot sky shader/ProceduralSkyMaterial,六面和云测试通过 部分等价;shader 采样与参考 quad/transition 仍需像素和边界比对
screen filter alpha blend 和 lens flare 字段只写 metadata,无运行时后处理/flare 渲染节点 GAP
风强度进入森林/树木更新 固定 msenv_wind_strength=0.2 metadata,无 SpeedTree/树节点风更新 GAP
SnowEnvironment/SnowParticle 池、范围、风/重力和 outdoor render 时序 单个相机跟随 GPUParticles3D 部分等价;粒子可切换不代表池/时序/清理等价
服务器 xmas_snow 0/1__IsXMasMap 过滤和雪开关 typed command -> weather_changed -> GameScene map filter -> Weather.set_weather 部分等价;命令/过滤时序已对齐,但粒子池/渲染阶段不是 SnowEnvironment 1:1
.msenv 静态地图环境 vs 昼夜/天气切换 正式链消费服务器 xmas_snowWeatherDayNightSystem helper 仍独立存在且不驱动生产地图 部分等价;40250 的 DayMode/PRESERVE_DayMode 和环境切换仍未接入
地图切换、暂停、重载和失败清理 world 环境节点 queue_free;天气节点未按地图环境重置/验证 部分等价;缺少环境/粒子/云资源失败和快速切图组合证据

已执行测试

  • project/environment_test.gd:通过;A1 .msenv、双方向光、WorldEnvironment、云纹理和 wind/filter metadata 可读取。
  • project/skybox_test.gd:通过;CapeDragonHead/DawnMistWood texture-mode 六面天空、云层、scale 和 UV speed 断言通过。
  • project/p9_test.gd:通过;通用 weather snow/rain/none 粒子开关路径通过,但不是参考雪环境池测试。
  • project/test_weather_daynight_parity.gd22 passed、0 failed;仅覆盖 WeatherDayNightSystem helper 的默认时相、时间推进、天气预设和信号,不覆盖正式 GameScene 接入或 40250 .msenv 渲染。
  • extension/tests/net_entity_test.cpp / build/extension/net_entity_test:通过;覆盖 GC_CHAT/COMMANDxmas_snow 1/0 typed event 顺序。
  • project/gamescene_test.gd:通过;覆盖正式 GameScene 对 eligible map、四张 40250 排除地图和关闭命令的雪开关处理。
  • project/netbridge_test.gd:通过;确认 M2Client.weather_changed 信号已注册。

Audit evidence round 2026-09-22T09:30Z

  • 重新运行 environment_test.gdskybox_test.gdp9_test.gdtest_weather_daynight_parity.gd,结果分别通过、通过、通过、22/22 通过。
  • environment_test.gd 实际加载 A1 .msenv 地图,skybox_test.gd 实际加载 CapeDragonHead/DawnMistWood 六面天空;这些结果确认 .msenv/天空基础链路仍可用,但不改变 filter、lens flare、wind、线性 fog 和 SnowEnvironment 池的差异结论。
  • test_weather_daynight_parity.gd 仍然只实例化独立 WeatherDayNightSystem;对照 GameScene::_build_world 当前只创建 fx/weather.gd,未发现正式地图加载时消费该 helper 的调用边沿,因此不能将 22/22 记为生产天气接入通过。
  • 本轮修复了服务器 xmas_snow 的命令接入和正式场景地图过滤;合同继续保持 PARTIAL,下一实现入口是 DayMode/PRESERVE_DayMode、SnowEnvironment 池以及已确认的 filter/lens flare/wind GAP。

Deep audit round 2026-09-21

Fresh regression results

  • environment_test.gdskybox_test.gdp9_test.gd 均退出码 0;真实 A1/CapeDragonHead/DawnMistWood 环境、六面天空、云参数和基础天气切换断言通过。
  • test_weather_daynight_parity.gd 22/22 通过,但它验证的是独立 WeatherDayNightSystem helper,不证明正式 GameScene 已实例化并消费天气系统。

Static parity conclusion

  • .msenv 解析、背景/角色光、SkyBox 和地图环境节点的基础链路存在;filter、lens flare、wind 仍主要停留在 metadata,未形成 40250 的运行时后处理、光晕和树木风更新。
  • Godot depth fog 的 clamp/curve/density 与 40250 线性 D3D 雾不等价;六面天空/云 shader 有结构测试,但没有与参考 transition/render order 的像素 oracle。
  • 生产场景已接入 40250 的服务器 xmas_snow 命令和地图排除过滤,但没有接入 DayMode/PRESERVE_DayMode;单个 GPUParticles3D 也不等价于 SnowEnvironment/SnowParticle 池和 outdoor render 时序。

本轮仍为 PARTIAL,完成服务器天气命令的实现和第三轮环境/天气证据登记。

Implementation fix round 2026-09-22T10:00Z

  • 修复前 gamescene_test.gd 的生产链回归无法让 xmas_snow=1 启用雪;native command-bus 也没有天气事件。
  • 按 40250 ServerCommandParser.__XMasSnow_Enable -> game.__XMasSnow_Enable -> background.EnableSnow,新增 EntityStore::WeatherChanged typed event、M2Client.weather_changed(bool) 信号,以及 GameScene._on_weather_changed -> _apply_server_weather
  • _apply_server_weather 复刻 __IsXMasMap 的四张排除地图:metin2_map_n_flame_01metin2_map_n_desert_01metin2_map_spiderdungeonmetin2_map_deviltower1;地图切换后重新计算开关,避免服务器命令状态污染新地图。
  • 修复后 native net_entity_testgamescene_test.gdnetbridge_test.gdp9_test.gdenvironment_test.gd 均通过。Godot 粒子仍只是平台适配,SnowEnvironment 池、DayMode、filter/lens flare/wind 和线性 fog 差异继续保留。

Active EterLib environment-render review

  • EterLib/SkyBox.cpp 实际维护天空六面纹理、天空/云纹理、gradient、scale、scroll、天气/颜色过渡和 render 顺序;ScreenFilter.cppLensFlare.cpp 是独立的屏幕滤镜与镜头光晕渲染对象,不只是环境字典字段。
  • 当前 WorldEnvironment/sky shader 能提供天空和雾的部分视觉结果,但 filter、lens flare 和风更新主要停留在 metadata,没有对应运行时后处理/光晕对象;Godot depth fog 的 clamp、curve 和 density 也不等价于参考端的 D3D 线性雾分支。
  • 因此本轮完成 SkyBoxScreenFilterLensFlare 活跃源码静态核对;天空结构测试通过不能证明 transition/render order、滤镜、光晕和地图环境切换副作用一致,合同保持 PARTIAL

已确认差异和未验证项

  1. 保持 filter/lens flare/wind 的明确 GAP,或实现对应的后处理、光晕和树木风更新,并为每个资源失败/禁用分支补测试。
  2. 以 40250 的 fog near/far、天空 transition、云 plane、背景/角色光照和 render order 建立截图/参数 oracle,禁止只用 metadata 断言代替渲染证据。
  3. 补齐 DayMode/PRESERVE_DayMode 的正式环境切换和场景生命周期;WeatherDayNightSystem 的自动地图预设继续隔离,不能替代 40250 服务器命令。
  4. 建立真实地图快速切换、暂停恢复、环境资源缺失、重复加载/卸载和粒子/天空无悬挂节点的组合测试。
  5. 对 SnowEnvironment 的池化、世界范围、风/重力、相机边界和 outdoor render 时序补专门实现或明确平台适配合同。

下一轮验证入口

  • 进入实现阶段后,优先修复正式 GameScene 的天气/地图环境接入和 fog/filter/lens flare/wind 中的已确认 GAP;修复后重新运行本合同四组测试并增加真实渲染证据。