跳轉到

算式表

本檔角色:所有核心算式的權威 source of truth。 涵蓋物理(動力 / 熱 / 磁 / 損耗)、武器技能、經濟、信譽、評分。

0. 命名約定

  • 變數:snake_case;常數:UPPER_SNAKE_CASE
  • 時間步長dt(秒);物理引擎 fixed 60Hz → dt = 1/60 ≈ 0.0166
  • 單位:質量 g、長度 mm 或 m(標註)、力 N、效果能量 J、電池容量 mJ、功率 W/mW、溫度 °C;衝撞 stress 鏈用 mJ§7
  • 量化分域:經濟 = bigint§12§15);信譽 / 評分 / 仲裁權重 = 整數(X100 量化 / 查表,§16§19);物理 = f32(wasm 統一 build)

1. 質量與體積

volume_cm³ = volume_m³ × 1_000_000                 // 幾何積分的 canonical 外部單位為 m³
mass_grams = volume_cm³ × density_g_per_cm³        // density 權威單位 = g/cm³(材質表 §1)

整車驗證(車輛組裝.md):

VEHICLE_TOTAL_MASS_MIN_GRAMS ≤ Σ part.mass_grams ≤ VEHICLE_TOTAL_MASS_MAX_GRAMS
max_part / min_part ≤ VEHICLE_PART_MASS_RATIO_MAX

整車限制值只由 零件與共用介面.md §7.1 定義;本節只保留聚合算式。

2. 駕駛動力

輸出功率 = motor 吸收上限與 battery 依 SOC 線性降額後的可供輸出取小

soc = remaining_energy_q / initial_energy_q
available_output_mw = floor(configured_output_mw × remaining_energy_q / initial_energy_q)
drive_input_mw = min(motor.auto_input_mw, available_output_mw)
actual_power_w = drive_input_mw / 1000
actual_supply_power_w = drive_input_mw / 1000

remaining_energy_q 使用 1/60 mJ quantum;固定 60Hz 下,供應 P mW 一幀恰扣 P quantum。 作者設定與資料卡使用 configured_output_w;進入決定性解算前固定換算 configured_output_mw = configured_output_w × 1000,後續取小與扣能一律使用 mW。 只要 motor/battery 存活且自走命令有效,駕駛先扣 drive_input_mw,即使已達極速、失去牽引、 卡牆或輪胎全壞也不省電。全 SOC 無 knee/reserve/固定停車線;低 SOC 可保有非零能量,但可供 功率可能已不足以克服質量、坡度與滾阻。

衍生扭力 / 速度(給上層運動模擬):

motor.derived_torque_nm    = actual_power_w × torque_ratio / 100 × K_TORQUE_FROM_W
motor.derived_top_speed_mps = actual_power_w × (100 - torque_ratio) / 100 × K_SPEED_FROM_W

surface_grip = min(active grip_loss / sticky grip_modifier,無命中為 1)
surface_top_speed_mps = motor.derived_top_speed_mps × surface_grip
torque_impulse_ns = (motor.derived_torque_nm / wheel_radius_m) × dt × surface_grip
top_speed_impulse_ns = total_mass_kg × max(0, surface_top_speed_mps - forward_speed_mps)
drive_impulse_ns = min(torque_impulse_ns, top_speed_impulse_ns)

contact_friction_ij = Average(tire_collider_i.material.friction, surface_collider_j.material.friction)
traction_share_ns_i = Σ_j(normal_impulse_ns_ij × contact_friction_ij)
linear_share_ns_i = min(drive_impulse_ns / original_driven_tire_count, traction_share_ns_i)
angular_impulse_nms_i = linear_share_ns_i × tire_radius_m_i
wheel_speed_limit_rad_s_i = surface_top_speed_mps / tire_radius_m_i

rr_pair_ij = tire_collider_i.material.rolling_resistance × surface_collider_j.material.rolling_resistance
rolling_impulse_ns_i = K_ROLLING_RESISTANCE × Σ_j(rr_pair_ij × normal_impulse_ns_ij)
rolling_impulse_ns_i = min(rolling_impulse_ns_i, impulse_to_zero_relative_rolling_speed_i)

top_speed_impulse_ns 是該幀可增加的最大前向動量:起步仍使用完整扭矩,但接近極速時只補足 剩餘 Δv,不得因 fixed timestep 在最後一幀跨越地表可達極速。drive_impulse_ns 永遠以安裝時 原始 driven tire 數分母切份,只把各份交給未損壞 tire,故標準四輪依序剩 100/75/50/25/0%; 不得把損壞輪份額重分配。每顆 tire 沿 chassis-side Mount local +X 的 Revolute 軸取得角衝量,primary body 同時取得等量反向反作用角衝量,車體線性前進只由輪胎接觸摩擦產生。實際單輪份額再受 本幀真實 contact manifold 的 normal impulse 與雙方材質 Average 合成上限約束;無接觸可空轉, 但不得直接推 primary body。rolling impulse 沿 wheel_axis × contact_normal 的實際滾動方向反向 作用,最多降至相對速度零,不得反向加速。接觸依 canonical collider key 穩定累加。 已達 wheel_speed_limit_rad_s_i 的輪胎不再取得驅動。broken tire/roller 的 collider、獨立 body 與 Revolute 於幀末退出物理,primary body 依剩餘完好零件重算質量、local COM 與慣量; tire 全損壞時推進為 0。grip_modifier 同時縮放可傳遞扭矩與地表可達前向速度,sticky 仍另外套用材質表的每幀 速度衰減。正式公版首次扭矩校準見 D-20260807-02,Revolute 接觸拓樸見 D-20260807-03,損壞鏈見 D-20260811-06 與取代舊係數切換模型的 D-20260814-05

駕駛耗電(固定幀整數帳、不得透支):

granted_drive_q = min(remaining_energy_q, drive_input_mw)
remaining_energy_q -= granted_drive_q

HUD 同時顯示儲存 SOC 與 available_output_mw / configured_output_mw;當 available_output_mw < motor.auto_input_mw 顯示「輸出受限」,實際失速由既有 stall/進度回饋呈現。

3. 武器 / 技能動能(不過 motor)

⚠️ 武器/技能預算只與 battery 的低 SOC available_output_mw 有關,不過 motor。駕駛先結帳,之後依已簽 canonical input event 順序結帳;兩路不互相削減滿額瞬時效果,只共用剩餘能量帳。

skill_power_budget_mw = floor(available_output_mw × allocation_pct / 100)
effect_energy_j = skill_power_budget_mw × effect_frames / (60 × 1000)
battery_cost_q = skill_power_budget_mw × cost_frames

allocation_pct 是 1–100 整數百分比,計算時除以 100,不依全槽總和正規化;總和低於 100 可刻意 低配。Event 的 effect_frames=60(1 秒效果預算),cost_frames 由各 Event protocol 常數獨立指定; Hold 的 effect/cost 都是當幀 1 frame。若剩餘能量不足,granted/requested 同比例縮放效果與成本, 禁止透支。passive weapon 不耗能。launch 只有 projectile 確實成功 release 時,才以 LAUNCH_FIRE_INTERVAL_MS 對應幀數同時結算效果、電池成本與熱;冷卻中、空彈或 release 失敗皆為 0。

Skill 類型 觸發行為 dt
Event 單發 boost / brake / jump / slam 1.0(等效 1 秒衝擊)
Hold 持續 swerve_left / swerve_right / stabilize / weapon 當幀實際 dt

技能效果分發(各 K 常數待 playtest 校準;VEHICLE_X / VEHICLE_Y / VEHICLE_Z = 車輛 local 單位向量 = 前向 / 左向 / 上向,對應 runtime GLB 軸 −Z / −X / +Y,見 零件與共用介面.md §5 軸向速查):

Skill 效果
boost +VEHICLE_X × applied_energy × K_BOOST 線性衝量
brake -VEHICLE_X × applied_energy × K_BRAKE
swerve_left +VEHICLE_Y × applied_energy × K_SWERVE
swerve_right -VEHICLE_Y × applied_energy × K_SWERVE
jump +VEHICLE_Z × applied_energy × K_JUMP
slam -VEHICLE_Z × applied_energy × K_SLAM
stabilize 角阻尼 += applied_energy × K_STABILIZE
weapon 分發給武器機制(active 觸發;passive 占槽常駐)

武器 general actuator 轉速零件與共用介面.md §3.7;energy-driven、共用功率分配):

P    = available_output_w × allocation_pct / 100                  // 該武器功率預算
ωᵢ   = P × K_WEAPON_ROTOR_SPEED × ( speed_weightᵢ / Σ speed_weight )
  • 各 actuator 分同一份 P(共用 chip weapon 槽);speed_weight 預設 1 → 均分 1/N
  • 加 actuator → Σ 變大 → 各自變慢(總功率守恆);耗能 / 發熱不隨 actuator 數或分配變(仍 ∝ applied_energy、只由 allocation_pct 決定)。
  • 鏈條 payload:基座轉速同上式;尾段 Chain_Segment 走物理 joint 擺動、不吃此式
  • 單轉子(N=1)= 滿速 P × K_WEAPON_ROTOR_SPEED(連帶釘死舊單轉子揮速)。

runtime 不使用不可讀回驗證的 Rapier joint motor。每幀以 actuator 軸上的相對角速度/有界目標角求 Δω,再以兩端 body 的 world inverse inertia 求 torque impulse;payload 與 primary chassis 接收等量反向角衝量。max_angle_deg = 360 追目標角速度;小於 360° 時,以 snapshot 內 phase 配合 sinlinear[-max/2,+max/2] 目標角。未 Hold 或斷電不再注入 torque,但既有慣性與 joint 碰撞仍照物理續行。鏈條只直接驅動第一節,後續節點由 authored Revolute/Spherical joint 傳力;Rapier 0.19.3 會把 JointData.spherical canonicalize 為等價的 Generic joint 表示。

被動武器加持(passive 專屬;三因子、僅及武器零件自身)

massReductionPctX100 = allocation_pct × passive_weight_split_pct         × K_PASSIVE_EFFECT_MAX_PCT / 100
resistPctX100        = allocation_pct × (100 − passive_weight_split_pct) × K_PASSIVE_EFFECT_MAX_PCT / 100
// bigint 整除截斷;X100 整數(K=30 時值域 0–3000 = 0–30.00%)

effective_mass_g(武器)   = mass_g × (10000 − massReductionPctX100) / 10000
fatigue 累積(武器)       ×= (10000 − resistPctX100) / 10000
熱流入(武器)             ×= (10000 − resistPctX100) / 10000     // thermal_limit 本身不變(升溫變慢、閾值語意不動)
  • 三因子:allocation_pct(chip 上鏈鎖死 = 總量)× passive_weight_split_pct組裝層分配 0–100、減重 vs 抗性,車輛組裝.md §3.5)× K_PASSIVE_EFFECT_MAX_PCT(上限常數 30、初估)。
  • 靜態係數:組裝 / 車輛實例化時套用一次,非 runtime 變動(不踩「runtime 改 mass」紅線);有效質量進入整車總質量 / 質量比 / 重心 / 慣量計算(GLB extras 的 mass_g 原始值不動);全 peer 同式 =deterministic。
  • 僅及 passive 武器零件自身:chip / motor / battery 熱模型與其他零件耐久零改動(chip 閾值殺手鐧不稀釋);抗性只改自身承受、不改對外輸出。
  • 二階 tradeoff(物理自然湧現):壓減重 = 更快但撞角動量變小;壓抗性 = 耐打但重。

晶片與電池的技能廢熱以實際電池成本分帳:

chip_heat_j = battery_cost_j × K_CHIP_SKILL_WASTE_HEAT
battery_heat_j = battery_cost_j × K_BATTERY_SKILL_WASTE_HEAT

殺手鐧判定(單一閾值)不在積分前以 J 直接比較 °C;本次 chip 廢熱先與所有來源一同進 §6.2,再用積分結果判定:

if chip.thermalLimitC !== null and chip.T_next > chip.thermalLimitC:
    chip.broken = true   // 所有技能立即失效但能基本駕駛
    // 該次觸發仍以「正常強度」執行(無 ×bonus 加成)

effect_energy_jbattery_cost_j、chip heat 與 battery heat 是四個不同帳目;不得再以效果能量直接 扣 mAh 或直接加溫。

4. 武器反作用力

武器動作(general_push / general_actuated / launch)對 chassis 質心產生反向衝量:

reaction_impulse = -action_direction × applied_energy × K_REACTION
chassis.apply_impulse_at_center_of_mass(reaction_impulse)
  • action_direction:武器 Axis empty +Z 軸(loadout knob 後)
  • K_REACTION 初估 0.002 N·s/J;輸入為實際獲准的 effect_energy_j(依真實接觸摩擦重校,見calibration.md §18),待 playtest
  • action 側(對目標的前推)遞送:上式為 chassis recoil 側。對目標的前推(沿 +action_direction)——general_actuated 由轉子 / 鏈條 mesh、launch 由子彈 body 經 Rapier contact 自然遞送(無需額外施力);general_push 無自運動 mesh → 引擎對接觸中的目標直接施加等大反向衝量 +action_direction × applied_energy × K_REACTION(與 chassis recoil 成 action-reaction 對,見 零件與共用介面.md §3.7
  • 多 actuator零件與共用介面.md §3.7):共用同一份 applied_energy淨反作用力仍 = 上式 weapon-level(沿 Axis、各 actuator 的 share 加總即全量、不需逐 actuator 拆向;同既有單轉子的線性簡化、不模擬轉向 recoil 抵銷);鏈條尾段甩動的反作用走 joint 自然處理

launch 的每枚 projectile 在 world 建立時即依 authored child pose、convex 形狀、材質與質量配置為 dynamic body,先以 fixed joint 持彈。每次開火只按 child index 移除下一枚 hold joint,沿 mounted Axis +Z 施 impulse 並對 chassis 施等量 recoil;不得在開火時建立替代球體或增加總質量。已發射 projectile 永久留場,且不再參與該車的 teleport/freeze/scale/deploy 查詢。

magnet 不需此函數(Rapier contact pair 物理自然處理)。

5. 磁力(真實物理:1/r² + N 極方向)

5.1 統一磁源 schema

設計原則(enum 三選一 + 身分/強度分離)

  • 一個材質的 magnetism_role 三選一:source(主動磁源)/ passive(被動鐵磁)/ none(無磁性);型別系統強制互斥(見 材質表.md §8
  • 主動磁源的強度由建模物件 Root Extras magnet_source_strength_n 決定(不在材質層)
  • 物件「成為磁鐵」條件:含 magnetism_role: source 材質 sub-mesh Root Extras strength_n > 0
  • 場地磁源於 Stage 2 pre-bake 為 Root Extras auto_magnet_sources(清單 [{ node, pos, strength_n, n_pole }],每個 source 材質 mesh node 一項、strength_n 取該 node 自身 extras,見 場地.md §8.6);runtime 直接讀、免掃 mesh
來源 strength_n n_pole_direction
武器 magnet 動態 available_output_w × allocation_pct / 100 × K_MAGNET_FORCE(即 §3 的功率預算 P × K;持續場強、去 dt——場強非能量;不依賴材質) Axis empty +Z 軸
場地物件 / 部件磁源 靜態 Root Extras magnet_source_strength_n(0–10 N)+ sub-mesh 材質 magnetism_role: source sub-mesh 面積加權平均法向(pre-bake 入 extras;退化〔近球對稱、平均趨零〕→ fallback node +Z,材質表.md §8.3

5.2 磁源 → 鐵磁物體(無方向)

delta     = target_submesh.center - source.position
direction = -delta.normalize()                          // 朝磁源
force_mag = source.strength_n
          × target_submesh.material.magnetic_susceptibility
          × K_MAGNET_PERMEABILITY_M2 / (r²)
force     = direction × force_mag
  • 純吸引(無 polarity 開關)
  • 1/r² 真實衰減(無自訂 radius 上限);r 單位 = m(尺度由 K_MAGNET_PERMEABILITY_M2 吸收)
  • r < 0.01 m 截斷:不施力(視為已接觸、防 1/r² 近貼爆量——接觸交由碰撞解算)
  • 施力點 = 剛體質心:力以整體 impulse 施於 body(applyImpulseWorld、不產生磁力扭矩);sub-mesh 僅決定受力大小與方向(delta 取 sub-mesh 中心)
  • Newton 3rdforce 施於 target body 的同時 −force 施於 source body——場力是引擎手動施加、不會自動產生反作用(§4 的「Rapier 自然處理」僅指接觸碰撞);場地 fixed / kinematic 磁源施了也不動、天然無影響;武器磁鐵吸目標時自身同受反向拉力(重車吸輕車 vs 輕車吸重車結果不同——戰術差異)
  • 多材質零件:每 sub-mesh 各自計算(鋼骨被吸 / 橡膠不受力 → 零件被拉得不對稱)
  • vehicle target 依 vehicleId → partIndex → canonical collider key 排序;Track Entity target 依 entityIndex → canonical collider key 排序。每個 passive sub-mesh 以其實際 collider 世界中心計算方向,但聚合後的 impulse 仍只施於兩側剛體 COM,不產生 torque;fixed/kinematic Track Entity 本身不移動,動態磁源仍承受反作用力
  • 公式僅對 target_submesh.material.magnetism_role === 'passive' 的 sub-mesh 套用;其他 role 對應 magnetic_susceptibility: null,直接 force = 0(不進入公式,避免 null × number = NaN)

5.3 磁源 ↔ 磁源(兩 N 極已知)

theta    = a.n_pole_direction · b.n_pole_direction      // [-1, 1]
coupling = -theta                                        // N 對 N(互指、θ<0)→ coupling>0=沿 +delta 遠離=斥;同指向(N-S 串列、θ>0)→ coupling<0=吸
force_mag = a.strength_n × b.strength_n × coupling
          × K_MAGNET_PERMEABILITY_M2 / (r²)
delta    = b.position - a.position
force    = delta.normalize() × force_mag                 // 施於 b;−force 施於 a(Newton 3rd,同 §5.2)
  • 同極相斥、異極相吸(真實物理);兩源各受 ±force(10mm 截斷 / 施力點質心同 §5.2
  • 玩家可主動讓 N 對 N 反制場地磁吸
  • owner 比對:不對自身生效

6. 熱模型(per-part 單一能量域)

6.1 Manifest 烘焙量

C_part = Σ(mass_kg_i × specific_heat_i) // J/°C
H_air  = Σ(exposed_area_m2_i × K_THERMAL_AMBIENT_W_PER_M2_C × conductivity_factor_i) // W/°C
thermalLimitC = min(all non-null sub-mesh thermal_limit)

conductivity_factor_i = 0.25 + 0.75 × min(k_i, THERMAL_CONDUCTIVITY_FACTOR_CAP_W_PER_M_C) / THERMAL_CONDUCTIVITY_FACTOR_CAP_W_PER_M_C。同一 part 內,三角面所有頂點與 中心都嚴格位於另一水密 region 內才從 exposed_area 排除;碰觸邊界或部分相交不猜裁切面積。 跨 part 裝配遮蔽在單資產 manifest 無法得知,本版不扣除。Canonical current PhysicsManifest 直接保存 heatCapacityJPerCambientConductanceWPerCthermalLimitC;runtime 不讀 auto_*、不重算。

6.2 backward Euler 單次積分

每幀所有來源先進 per-part ledger:瞬時能量 E(J)、持續功率 Q(W)、空氣熱導 H_air 與接觸固定熱庫 (H_j, T_surface_j)。最後每個 part 只解算一次

T_next = (C×T + E + dt×(Q + H_air×T_air + Σ(H_j×T_surface_j)))
         / (C + dt×(H_air + ΣH_j))
T_next = clamp(T_next, MIN_TEMPERATURE_C, MAX_TEMPERATURE_C)

T_air 與固定地表熱庫溫度都取場地 weather.temperature。此隱式式在任意合法 dt/熱導下 保持有限、單調且不越過固定熱庫;除初始化、restore 與本式外,禁止直接寫 temperature +=

過熱破壞(無 graceful degradation):

if part.thermalLimitC !== null and T_next > part.thermalLimitC:
    part.broken = true

跳過條件:建模屬性不可破壞 / part.thermalLimitC === null(manifest pre-bake 結果:所有 sub-mesh 皆 null)→ 跳過過熱檢查(見 材質表.md §10)。

6.3 各 part 類別的 heat_in 源

Part ledger heat source
chassis / body / weapon 無自身發熱;仍接收 ambient、burn/freeze 與外部接觸來源
tire / roller 同上,另接收 solid surface 導熱與 abs(tangential_impulse × tangential_slip_speed) × K_THERMAL_SLIP
motor K_MOTOR_HEAT × actual_power_w(W)
battery K_BATTERY_PASSIVE × actual_supply_power_w(W)+battery_cost_j × K_BATTERY_SKILL_WASTE_HEAT(J)
chip(晶片) battery_cost_j × K_CHIP_SKILL_WASTE_HEAT(J)

6.4 流體 deploy 對溫度影響

burnfreeze 的 authored temperature_delta_per_sec 先乘該 part 的 C 轉為 W 再進 ledger。 burn 正熱量受 passive weapon thermal resist 折抵;freeze 負熱量不折抵。freeze 仍是純冷卻, 不引入低溫降效。chip 本次 skill 若把投影溫度推過閾值,該次仍完整執行,統一積分後才 broken。

6.5 tire/roller 與 solid surface 接觸熱

effusivity_factor = quantized_sqrt(thermal_conductivity × density_kg_m3 × specific_heat)
pair_factor = 2 × factor_part × factor_surface / (factor_part + factor_surface)
H_contact = K_THERMAL_CONTACT × pair_factor × baked_contact_area_m2 × normal_impulse_ns
slip_energy_j = K_THERMAL_SLIP × abs(tangential_impulse_ns × tangential_slip_speed_mps)

只使用實際 contact manifold;surface 是不耗竭固定熱庫。fluid sensor 不走此式。

7. 衝撞 Fatigue(耐受度因子族)

對稱套用 attacker / target(Newton 3rd law),每邊由碰撞事件的 collider handle 取得自己實際 接觸 sub-mesh 材質;車輛與 destructible Track Entity 都不得退回 materials[0]

vA_point = vA_com + ωA × (contact_point - comA)
vB_point = vB_com + ωB × (contact_point - comB)
v_close = max(0, dot(vA_point - vB_point, normal_A_to_B))
m_effective_normal = 1 / (
  n·(invMassA + invMassB)·n
  + (rA×n)·worldInvInertiaA·(rA×n)
  + (rB×n)·worldInvInertiaB·(rB×n)
)
impact_energy_J = 0.5 × m_effective_normal × v_close²

local_normal = quantize(inverse(collider_world_rotation) × world_contact_normal)
contact_area_m² = max(
  IMPACT_CONTACT_AREA_MIN_M2,
  abs(nx) × area(sign(nx) ? right : left)
  + abs(ny) × area(sign(ny) ? top : bottom)
  + abs(nz) × area(sign(nz) ? back : front)
)
stress_MPa = impact_energy_J / (contact_area_m² × K_IMPACT_DEPTH_M) / 1_000_000
// 單位鏈:J / (m² × m) = Pa,再除 1,000,000 得 MPa——與 yield_strength / ultimate_strength(MPa,材質表)直接可比
// K_IMPACT_DEPTH_M = 等效變形深度(0.001m 初估、待 playtest,calibration.md §18)

if stress > yield_strength:
    entity.fatigue += stress / ultimate_strength

if stress > ultimate_strength × K_STRESS_BURST_FACTOR:    // 1.5,calibration.md §18
    entity.broken = true                  // 一擊重傷
elif entity.fatigue ≥ 1.0:
    entity.broken = true                  // 累積疲勞破壞

if entity.broken:
    entity.fatigue = min(entity.fatigue, 1.0)   // broken 後凍結

以上撞擊運動量使用 solver 前依 body handle 保存的 COM pose、線速度、角速度、effective inverse mass 與 world inverse inertia;固定體 inverse 值為 0。接觸點、速度與有效質量中間量以 IMPACT_KINEMATICS_QUANTIZATION_PER_UNIT 量化。collision-start 在 solver 後送達而沒有可用 manifold 時,以 solver 前 collider 位姿及 IMPACT_CONTACT_QUERY_MARGIN_FRAMES 重建接觸;若 Rapier manifold 法線與 solver 前相對接觸點速度的 closing 分量小於 IMPACT_NORMAL_MIN_CLOSING_MPS,以該相對速度方向作確定性退化法線。兩者皆無可信結果才 fail closed;不得回退 collider 中心、質心速度或 owner 整車質量近似。

持續 solid 接觸另由 solver ledger 計算剪切:

if tangent_slip_speed ≥ SHEAR_DAMAGE_MIN_SLIP_MPS:
    shear_energy_J = K_SHEAR_DAMAGE_TRANSFER
                     × abs(tangent_impulse_Ns)
                     × tangent_slip_speed_mps

法向撞擊與剪切能量交給同一接觸面積/材質 stress 路徑。tire/roller 對固定場地已有專用 rolling/slip wear ledger,不再套一般剪切 fatigue。武器不按名稱或類型加成:鈍器、尖端、刀刃、 揮刀與旋轉鋸的差異只來自幾何面積、材質、質量/慣量、ω×r 與真實 solver 接觸。

六向面積來自同一個實際接觸 collider proxy 的 current PhysicsManifest 烘焙值。contact pair 先依 canonical collider key 固定 A/B;A 使用朝向 B 的 manifold normal,B 使用反向 normal,各自轉回 collider local。法線以 IMPACT_NORMAL_QUANTIZATION_PER_UNIT 量化,固定 X→Y→Z 加總;不採最大軸 硬切、不做 L1 再正規化,也不得退回整顆零件或點雲 AABB。

跳過條件與可破壞性決策:見 材質表.md §10(建模屬性決定可破壞性,材質僅提供強度數值)。

8. Acid 腐蝕

// K_ACID 見 [calibration.md §18](程式參數/calibration.md)(與 abs ultimate=50 配對約 0.05 fatigue/sec)

if not is_fluid and ultimate > 0:
    part.fatigue += K_ACID / ultimate × dt
    if part.fatigue ≥ 1.0: part.broken = true

材質敏感:abs 衰得快、titanium 慢。每個 distinct zone/part 每 fixed step 最多套用一次;若同一 zone 同時交疊該 part 多個 collider,從實際交疊者選 ultimate_strength 最低的有效固體材質,並以 canonical collider key 解同值,避免 compound collider 重複計傷又保留弱表面語意。

9. 輪胎摩擦磨耗(併入 fatigue)

// 每個有效 tire collider region × solid surface contact,依 canonical collider key 累加
rolling_energy_j = abs(rolling_impulse_ns × rolling_speed_mps)
slip_energy_j = abs(tangential_impulse_ns × tangential_slip_speed_mps)
wear_energy_j = rolling_energy_j + K_TIRE_SLIP_WEAR_MULTIPLIER × slip_energy_j

wear_capacity_j = K_TIRE_WEAR_CAPACITY × material_region_volume_m3
                  × ultimate_strength_mpa × 1,000,000
thermal_ratio = clamp((tire.temperature - T_air) / (tire.thermalLimitC - T_air), 0, 1)
thermal_wear = 1 + K_TIRE_THERMAL_WEAR_MAX × thermal_ratio × thermal_ratio
tire.fatigue += thermal_wear × wear_energy_j / wear_capacity_j
if tire.fatigue ≥ 1.0: tire.broken = true

只有實際 solid contact 且 rolling/slip speed 至少 MIN_TIRE_WEAR_SPEED_MPS 才記帳;無接觸、 靜止或 sensor/fluid 接觸為 0。故極速巡航、滑行與下坡仍有 rolling wear,空轉/側滑/鎖死拖行 另有放大的 slip wear。wear_capacity_j 逐實際 collider region 烘焙,內部輪轂不得替胎面增加容量; 非有限/非正體積或 ultimate strength 必須 fail closed。無有效熱限時 thermal_ratio=0T_air >= tire.thermalLimitC 時取 1。tire.temperature > tire.thermalLimitC 仍直接 broken;broken 後停止磨耗, respawn 不清 fatigue,新回合才重設。損壞後 Grip 行為見零件與場景.md §tire

10. 場地物理

10.1 場地 Entity destructible

可破壞性決策見 材質表.md §10。場地 entity 標 destructible: true(需 physics: "default")時,沿用 §7 衝撞 fatigue 算式:

if entity.fatigue ≥ 1.0 or stress > ultimate_strength × K_STRESS_BURST_FACTOR:    // 1.5,calibration.md §18
    entity.broken = true
    entity.breakFrame = currentFrame
    disable(entity.intact_body, entity.intact_colliders, entity.intact_visual)
    // 同幀停止 move/conveyor/entity-local magnets;不把 intact body 改成 Dynamic,避免雙重質量
    // 不建立/啟用 fragment body、collider、sensor、damage 或路障
    visualFragments = reconstruct(entityIndex, breakFrame, descriptorVersion, currentFrame)

world 只預配置 intact body/collider。fatigue、broken、breakFrame 進 current SavedState、restore validation 與 checksum;逐片 active/spawn/expiry/fade/pose/velocity 不進共識。currentFrame - breakFrame 超過 VISUAL_FRAGMENT_LIFETIME_MS 對應幀數時不重建,淡出使用共用 presentation 參數。

10.2 天氣 patch 混合計算(rain / snow 動態地表)

雨/雪 patch 影響車輛與地表互動,採 混合計算(multiplier 而非 override)

patch 內 friction           = 原材質 friction           × patch_friction_modifier
patch 內 rolling_resistance = 原材質 rolling_resistance × patch_rolling_modifier

預設係數(依 weather.type 自動帶入,創作者可調,schema 見 場地.md §8.3):

參數 rain 預設 snow 預設 範圍
patch_friction_modifier 0.65 0.5 0.3–0.9
patch_rolling_modifier 1.5 2.0 1.0–2.5(>1 = 拖感變重)

Patch deterministic spawn

seed = SHA-256(matchId ‖ NUL ‖ roundIndex ‖ NUL ‖ track_manifest_digest) 的前 32 bits(LE)
counter = (spawn_ordinal, born_frame, attempt_index),每次固定最多 8 次候選
位置:重力平面的 typed auto_exposure grid 內均勻取樣,採沿重力方向第一個靜態 solid 表面
數量:≤ WEATHER_PATCH_COUNT_MAX(50,protocol.md §3)/ 場
生命週期:spawn_rate 使用整數 accumulator;lifetime 預烘成整數 frame;rate > 0 時 frame 0 先生成
遮蔽:橋面/屋頂可生成;其下方與隧道由第一表面 exposure 遮蔽,不生成

設計理由(為什麼 multiplier 而非 override):物理直覺(雨水落柏油 vs 泥土 vs 沙的滑度應該不同)+ 湧現玩法(dirt + rain 自動產出「比 mud 還滑」的緊張感)。

Patch 只修改 tire/roller 與靜態 solid surface 的實際接觸:先乘 surface friction/rolling resistance,再進既定 combine/牽引/側滑/滾阻。涵蓋以切平面圓、法向距離與法向相似度判定;同類 patch 重疊只取穩定 ID 最小者一次,不連乘。基礎材質 restitution 仍生效,但 weather 不再另改 restitution。

patch 視覺 + 遮蔽一致:physics engine 維護唯一 active descriptors(位置、法向、半徑、出生/到期 frame、modifier);participant、spectator 與編輯器預覽只消費 descriptors,不另跑 RNG。scheduler accumulator、spawn ordinal 與 active descriptors 全部進 current SavedState/checksum/restore。schema 見 場地.md §8.3 / §8.6

10.3 風力套用

風是獨立參數(不綁 weather.type)。body 以六個帶正負號的局部軸面積與各自壓力中心計算相對氣流;無風時移動車也有阻力:

v_point = v_body + omega × r_center_of_pressure
v_air = v_wind - v_point
F_axis = K_AERO_DRAG × drag_area_axis × v_air_axis × |v_air|
F_lift = K_AERO_LIFT × lift_factor × |F_drag_horizontal| × normalized_gravity_direction
|F_drag + F_lift| ≤ mass × |gravity| × K_AERO_MAX_WEIGHT_MULTIPLIER

其中:

  • weather.wind_speed_mps 與量化風向組成世界座標 v_wind;上限見 protocol.md §3
  • 每個局部軸只在 v_air_axis 朝該軸正向時使用對應 +axis-axisdrag_area_m2center_of_pressure_m
  • lift_factor 沿重力形成下壓,負值反向形成升力;lift 施於各 drag force 量值加權的壓力中心
  • K_AERO_DRAG = 0.6K_AERO_LIFT = 1K_AERO_MAX_WEIGHT_MULTIPLIER = 2 是 synthetic 初值,正式資產 playtest 前只承諾公式與界限

10.4 重力與物理引擎

每場地有自己的重力設定(schema 見 場地.md §8.4):

gravity_vector = normalize(physics.gravity_direction) × physics.gravity_strength_m_s2
rapier_world.set_gravity(gravity_vector)

支援低重力(月球感)/ 高重力 / 反重力 / 橫向重力 / 斜向重力等創意場地。

耦合

  • 「掉出場地」三層 fallback 沿重力方向投影 AABB + 5m buffer(反方向不檢核)
  • 武器 launch 投射物彈道受場地重力影響(高重力場地拋射物落得快)
  • 雨/雪 patch 沿重力反向「貼地」生成

11. 車輛回合初始狀態(每回合載入新車)

每回合載入該回合的車(carRotation[i])+ 場地 = 全新世界;車輛以下列初始狀態開始。回合間不共享任何 runtime 狀態(fatigue / heat / 電量 / 彈藥 / 已射出 bullet)——這是「換上新車 + 新場地世界」的自然結果、非 reset 流程;每 peer 各自從同一份 GLB 載入 → 初始狀態天然一致(determinism)。

// 新車載入時的回合初始狀態
for part in vehicle.parts:
    part.fatigue = 0
    part.temperature = T_air               // 當前場地溫度(= weather.temperature)
    part.broken = false

vehicle.battery.remaining_energy_q = battery.initial_energy_q // 滿電;1 quantum = 1/60 mJ
vehicle.weapon.launch_ammo = full                             // 滿彈(= auto_launch_ammo 全部,建模參數/零件與共用介面.md §3.7.3)

回合內:狀態累積(fatigue↑ / heat / 電量耗 / 彈藥 Hold 連發);彈藥有限、打完即空(一回合就這麼多、用完沒了)。回合數由房間設定(可變 N)。

12. 經濟:月度派發係數

〔ECON-R-030〕 月度派發係數只依 softCapmonthMinted 的整數公式計算:

factorX100 = softCap × 100 / (softCap + monthMinted)
monthMinted factorX100 拿到比例
0 100 100%
softCap 50 50%
5×softCap 16 16%
> 99×softCap 0 整數量化 floor 到 0 → 當月鑄幣停止(等效月硬頂),防極端刷量兜底

13. 經濟:比賽獎金

〔ECON-R-031〕 比賽獎金依總名次、完賽人數、月度係數與治理參數決定:

function computeMatchPrize(rank, finisherCount, factorX100, config): bigint {
  if (finisherCount < min_player_count) return 0n;   // finisherCount = 完賽人數
  const mult = rank_multipliers_pct[min(rank - 1, len - 1)];
  return base × finisherCount × mult × factorX100 / (100n × 100n);
}

〔ECON-R-032〕 rank = 總名次(N 回合積分加總後的最終名次,見 §20.1);獎金 per-match 發一次(非每回合)。

整除截斷尾數抹零消失(不發給任何人、不累加 monthMinted、不存滯留池)— 必要性:跨 peer 共識一致。

finisherCount = 完賽人數(完成整場比賽 = N 回合、未斷線 / 未棄賽者;斷線 / 棄賽者不計、不發獎金);finisherCount < 3 → 整場 matchPrizesroyalties 全空(經濟 void,權威見 經濟系統.md §6.2)。

範例(8 人賽,月初係數 100,依總名次):

名次 獎金(minor units)
1 400 (4.00 幣)
2 200 (2.00)
3 120 (1.20)
4–8 56 (0.56) each

高峰月(係數 50)所有獎金減半。

14. 經濟:創作回饋金

〔ECON-R-033〕 單一 UGC 的回饋金由評分、利基加成、月度係數與基礎額共同決定:

function computeRoyaltyForUgc(ratingX100, factorX100, config): bigint {
  const ratingMultX10000 = ratingX100 × 20;                // rating / 5 的 X10000 量化(ratingX100 已含 ×100、再 ×20)
  const nicheMultX100  = nicheMultiplierX100(ratingX100);  // 線性 clamp(見經濟系統 §7.1)
  return base × ratingMultX10000 × nicheMultX100 × factorX100 / (100n × 100n × 100n × 100n);
}

維度驗算:base 50、rating 4.5(ratingMultX10000 = 9000)、niche ×2.0(200)、係數 100 → 50×9000×200×100 / 10⁸ = 90 minor(0.9 幣)。

Niche 加成(線性連續、整數量化):nicheMultX100 = clamp(ratingX100 - 250, 50, 200),rating ≤3.0 → ×0.5、4.0 → ×1.5、≥4.5 → ×2.0(權威見 經濟系統.md §7.1)。

15. 經濟:三層分潤

每筆 royalty 依 fork 血緣拆 70/20/10:

current_share     = total × 70 / 100   // 當前創作者
parent_share      = total × 20 / 100   // 直接 parent
grandparent_share = total × 10 / 100   // 祖先依深度衰減
// 缺層份額(無 parent / grandparent)與整除殘留一律歸當前創作者——原創(無血緣)作品實拿 100%(無公共池機制)

詳見 經濟系統.md § 三層分潤 + 版權.md §Fork 衍生樹

16. 信譽分數

〔MOD-R-001〕

reputation = clamp(500 + Σ(加分事件) - Σ(扣分事件), 0, 1000)

純函數,由事件鏈推導。事件加減值見 信譽系統.md

17. 信譽加權投票

weight = log10(reputation + 10)

〔MOD-R-010〕 整數評估(共識計算禁用浮點 log10):仲裁 tally 是全網重算驗證的共識計算,浮點 log10 跨硬體不一致(同 §19 隱式評分的理由),runtime 一律用預算整數表

weightX100(rep) = ARBITRATION_WEIGHT_X100_TABLE[clamp(rep, 0, 1000)]
// 表 = 離線一次性生成 round(100 × log10(rep + 10))、隨 client 出貨(bit-exact);runtime 不得呼叫浮點 log10
// 通過判定全整數:Σ(pass weightX100) × 100 > Σ(有效票 weightX100) × ARBITRATION_PASS_THRESHOLD_PCT
// current = 60(= 加權通過比例 > 60%,無除法捨入;權威見 [protocol.md §5](程式參數/protocol.md))

範例:

信譽 weight(weightX100)
200(仲裁門檻) 2.32(232)
500 2.71(271)
800 2.91(291)
1000 3.00(300)

公式全域最大差異 ~3 倍(避免大戶獨裁);仲裁面板內(皆 ≥ 200)差距 ≤ 1.29×、近似人頭。

18. UGC 評分權重(依信譽)

〔ECON-R-034〕 UGC 評分投票權重依投票者信譽分成 0.5、1.0、1.5 三級:

ratingWeightX100 = 50   if reputation < 200      (0.5)
                 = 150  if reputation > 800      (1.5)
                 = 100  otherwise                (1.0)

19. UGC 評分(Bayesian + 隱式 fallback)

〔ECON-R-035〕 UGC 評分依票數選用隱式 fallback、Bayesian 拉中性或明確票均值:

if voteCount == 0:
    ratingX100 = implicitRatingX100(ugcUsageCount)        // 純使用量推估
elif voteCount < BAYESIAN_PRIOR_SAMPLES:
    ratingX100 = (n × explicitMean + k × NEUTRAL) / (n + k)   // Bayesian 拉中性
else:
    ratingX100 = explicitMean

RATING_NEUTRAL_X100BAYESIAN_PRIOR_SAMPLES 的值只由 protocol.md §5 定義;本節只定義算式。

〔ECON-R-036〕 隱式 fallback(整數查表):浮點 log10 跨硬體不一致會炸毀 consensus derive,故隱式評分採整數查表:

function implicitRatingX100(ugcUsageCount: number): number {
  if (ugcUsageCount === 0) return 300; // 3.00
  if (ugcUsageCount < 10) return 360; // 3.60
  if (ugcUsageCount < 100) return 420; // 4.20
  if (ugcUsageCount < 1000) return 480; // 4.80
  return 480; // 封頂 4.80
}
ugcUsageCount ratingX100
0 300 (3.00)
1-9 360 (3.60)
10-99 420 (4.20)
100-999 480 (4.80)
1000+ 480 (4.80, 封頂)

封頂 4.80 而非 5.00:完全無評分但被多人用 = 證明有功能性但未必精緻,留給顯式評分達 5.00 的精品差異化空間。UI 顯示時加 (隱式) 標籤(信譽系統.md §3.1)。實作見 程式架構/ugc-rating.md §3.3

20. TrueSkill(配對評分;整數定點)

TrueSkill 為 Microsoft 商標;本節是自製整數定點實作、僅指示性沿用演算法名稱與參數慣例(歸屬聲明見 版權.md §11.1)。

〔ECON-R-052〕 8 人 FFA 用 TrueSkill 成對近似多人更新(μ, σ 演化)。rating 屬共識 deriveMatchDerivedState、全網重算需 bit-exact)→ 全程整數定點:浮點與超越函數(Gaussian erf)禁入(同 §17 仲裁 log10 查表化先例、資料系統.md §17 不變式)。

定點表示:μ、σ 一律 X1000 整數(初始 μ=TRUESKILL_MU_INITIAL_X1000(25000)、σ=TRUESKILL_SIGMA_INITIAL_X1000(8333));β=TRUESKILL_BETA_X1000(4166)、τ=TRUESKILL_TAU_X10000(833,尺度 X10000、使用處明確換算)。所有除法 = 整數截斷、運算順序照公式書寫序(跨 peer 一致)。

每場後成對近似更新(rankings=§20.1 總名次、per-match 一次;FFA 不平手 =draw margin 0、無平手常數):

對每有序對 (i, j),i ≠ j,勝負由總名次決定(i 勝 j 時):
  cSq = 2×β² + σi² + σj²                     // X1000² 域
  c   = isqrt(cSq)                            // 整數開根(floor)——無浮點根
  t   = (μi − μj) × 1000 / c                  // X1000、截斷
  (v, w) = (TRUESKILL_V_TABLE_X1000, TRUESKILL_W_TABLE_X1000)(t)   // 查表:clamp ±TRUESKILL_VW_T_CLAMP_X1000(6000)、步長 TRUESKILL_VW_T_STEP_X1000(10)(=0.01)、不插值
  Δμi += σi² / c × v / 1000;Δμj −= σj² / c × v / 1000
  wi 累加 w(供 σ 縮減);wj 同
每人淨值:μ' = μ + ΣΔμ / (P−1)
σ 縮減(每人一次、用平均 w̄ = Σw / (P−1);cSq = 該玩家 P−1 個配對 cSq 的整數平均(截斷)——聚合方式實作即權威):
  σ'² = σ² − σ² × w̄ × σ² / (cSq × 1000) + TAU_X10000² / 100   // + τ² 動態注入(X1000² 域);中間積超 2^53 → BigInt 精確計算
  σ'  = isqrt(σ'²)      // 自然正下界(縮減項恆 < σ²:w̄ < 1000 且 σ² < cSq)+ τ² 注入;無普適下限

σ 下限 TRUESKILL_SIGMA_MIN_X1000(6000)僅適用頻繁斷線者disconnectCount ≥ FREQUENT_DISCONNECT_THRESHOLDadjustRatingForFrequentDisconnects 托底,程式架構/matchmaking.md §1)——普適套用會使托底永為 no-op、且成熟玩家 σ 無法低於新人初值。

  • TRUESKILL_V_TABLE_X1000TRUESKILL_W_TABLE_X1000= 離線生成整數查表(v(t)=φ(t)/Φ(t)、w(t)=v(t)(v(t)+t) 的 X1000 值;各 1201 筆、隨 client 出貨——同仲裁權重表模式)。粒度 0.01 的精度損失對配對評級可忽略——共識要求 =bit-exact、非高精度
  • 新人 σ 大(變動快);成熟玩家 σ 小(穩定);頻繁斷線者 σ 托底 6000 不收斂(上)。

配對窗口尺度基準:displayRating = (μ − 3σ)(X1000 整數;權威 賽內機制.md §1.2);窗口比較於 displayRating ÷ 1000 的整數分域(窗口初始 ±5、每 10 秒 +5、上限 ±30——窗口常數維持整數分尺度)。

20.1 多回合積分與總名次

一場比賽(match)含 MATCH_ROUND_COUNT 個回合(round);每回合各自一軌、各自名次,積分加總定總名次。

回合積分(線性、整數):

roundPoints(k, P) = P − k + 1        // k = 該回合名次 1..P;P = 開賽人數(全程恆定)
totalPoints(peer) = Σ_round roundPoints(k_round, P)
  • 第 1 名得 P、最後一名得 1;回合名次先分①合法完賽、②未完賽存活、③未完賽失能、④未完賽退出。合法完賽依 finishedAtFrame 升冪;其餘各區依 lapsDone 降冪、routeProgressUm 降冪、PeerId 字典序。routeProgressUm 是 checkpoint 依序約束下、微米整數量化且單調不退的 route arc-length,抄近路不得越過下一個未點亮 checkpoint 的弧長。
  • battery/motor broken 關閉輸入、驅動、技能與主動武器,但保留 chassis 物理及 checkpoint/終點判定;慣性、環境或撞擊造成的合法 swept crossing 仍可完賽。場上無未完賽存活車後才啟動單一回合級 120 幀終局窗;所有未完賽失能車線速度 < 0.05 m/s 且角速度 < 0.1 rad/s 連續 15 幀可提早結束。chassis physicsRetired 不參與滑行窗。
  • 回合內失能/退役/DNF 者仍得低分並繼續下一回合(換上全新車);已合法完賽者之後失能或退出不改名次區塊。

直接致毀破壞統計:權威事件是 target vehicle part 在固定幀末首次由 broken=false 轉為 broken=true。同一 (targetVehicleId, partIndex, frame) 的有效損傷先依 source 彙整成 damageContributionQ = round(normalizedFatigueContribution × 10^9);最大者取得一件,同值依 canonical source key、event key 的 code-unit 順序。敵方車碰撞、已發射 projectile 與其 fluid zone 保留 source peer;自損、場地/環境、自然過熱與無 owner 來源可成為最大來源但不給任何玩家件數。 chassis 自身實際 broken 可計一件,chassis retirement 停用的其他 intact part 不計;不追蹤助攻或 間接推牆因果。每回合完整 roster 的非負整數結果進 current SavedState、checksum 與 required RoundResult.destructionCounts,真正沒有破壞才是 0。

  • P = 開賽人數恆定;中途斷線者後續回合 DNF 佔末位,不縮減 P(各回合積分基準一致)。

總名次(match 結束、totalPoints 由高到低)tiebreak:

  1. 總完成時間 Σ_round finishTimes(DNF 回合計該回合 durationLimitSec × 1000 ms)少 → 多
  2. 仍同 → PeerId lexicographic(決定性)

純函數(consensus-critical:簽章者各自重算驗 MatchResultEvent.ranking、防主 peer 偽造,見 程式架構/ledger-settlement.md §5):

function deriveTotalRanking(rounds: RoundResult[]): PeerId[] {
  const P = rounds[0].ranking.length; // 開賽人數(各回合 ranking 含全員、DNF 佔末位)
  const points = (p: PeerId) =>
    rounds.reduce((s, r) => s + (P - r.ranking.indexOf(p)), 0); // Σ (P − k + 1),k = indexOf+1
  const totalTime = (p: PeerId) =>
    rounds.reduce((s, r) => s + (r.finishTimes.get(p) ?? 0), 0);
  return [...rounds[0].ranking].sort(
    (a, b) =>
      points(b) - points(a) || // 積分高 → 低
      totalTime(a) - totalTime(b) || // 總完成時間少 → 多
      (a < b ? -1 : a > b ? 1 : 0),
  ); // PeerId lexicographic(決定性)
}

總名次是 §13 computeMatchPrize(rank)與 §20 TrueSkill(rankings)的唯一輸入 → 獎金 / rating / 信譽皆 per-match 結算一次。線性積分之後可改 top-heavy(暫定線性)。結構 / 結算見 程式架構/ledger-settlement.md §5 MatchResultEvent / RoundResult

21. 反複製相似度(computeFeatureSimilarity v1)

mesh 幾何指紋特徵向量 → 0–100 整數相似度(共識值——上傳宣告收件驗證逐對重算比對;程式架構/anti-piracy.md §3/§5.1、門檻 90/70 見 版權.md §5.3):

// 各維相對差(ppm 整數法、同 relDiff);標準化已消除平移/旋轉/縮放/鏡像
dVertex  = relDiffPpm(vertexCount)          // number 域
dVolume  = relDiffPpm(volume)               // bigint 量化域
dSurface = relDiffPpm(surfaceArea)
dAabb    = AABB 三軸 relDiffPpm  max
dBary    = 重心三軸絕對值域relDiffPpm  max

similarityX100 = max(0, 100  floor( max(五維 ppm) / 10_000 ))
  • 取 max(非加權平均):「最不像的維度決定不相似度」——真複製 = 全維都像 →sim 高 → 拒收;任一維實質大改 → 掉出 90;多維各小改 8% 的稀釋式洗白在 max 下仍 sim 92→ 照樣拒收(與 UGC機制.md §5.3 的 rigidDiff 最大分量規則同哲學)。
  • pcaAxes/isMirror v1 不進式(標準化後軸已對齊、鏡像已翻正——資訊已反映在 AABB/ 重心);如需納入隨版升級。
  • 版本護欄:公式綁 fingerprintVersion(v1=1)——升級時舊作品鎖原版、跨版本比對一律放行(版權.md §5.2.2),公式演化不成硬分叉。
  • 全整數運算(ppm 中介、floor 量化)——跨 peer bit 一致。

22. 常數權威來源

本檔公式中 K_AERO_* 的值見 protocol.md §2,其餘物理/武器 K_* 常數的值與完整清單見同檔 §18(待 playtest 校準)。本檔僅使用變數名,不另列數值表(避免重複指定)。

治理 / 升版流程:物理常數變更走 client major bump, ConfigUpdateEvent(物理性質是規則不是 config);詳見 版本規範.md