跳转到内容

物品与库存

全船物品一律装在“容器”里流转:物品堆(数量 + 动态属性)→ 容器格子(带白名单)→ 容器注册表(找货)→ 资源预留(任务锁货)→ 船员搬运。本页讲清楚堆叠、容器、预留、地面物品与搬运的全部规则与数值。

本游戏没有“全局背包”。木头、煤炭、食物、弹药等一切物品都必须实际存在于某个容器中,容器分三类宿主:

  1. 建筑容器:每个建筑最多拥有输入(Input)/ 输出(Output)/ 存储(Storage)三个容器,容量由 BuildingContainerConfig.csv 配置(见下文容量表)。
  2. 地面容器:物品掉在甲板某一格时,该格会自动生成一个地面容器(默认 20 格),物品以九宫格图标显示在地板上。
  3. 船员随身背包:每名船员有一个 10 格背包(代码常量,Crew.cs),仅用于搬运途中临时持有物品。

在游戏循环中的位置:生产(生产与制作)产出进输出容器 → 搬运任务把物品送进仓库或下一个建筑的输入容器 → 消耗系统(修建 / 武器装弹 / 锅炉补煤 / 进食饮水)从仓库取走。整条链路由资源预留系统保证“一份货不会被两个任务同时盯上”。

玩家接触物品系统的入口:

入口 行为 出处
“船上物品”常驻面板(屏幕左侧) 每 0.2 秒聚合全船非生产建筑的三类容器,按物品 + 鲜/陈状态分行显示总数 ShipInventoryPanel.cs
点击建筑 / 地面物品 在鼠标点击位置弹出容器内容浮窗(含输入/输出/存储分区、生产进度),每 0.3 秒刷新内容,同一建筑期间位置不动 ContainerPopupManager.cs
地面物品九宫格图标 每格地面容器最多显示 9 个物品图标,超出部分显示 “+N” FloorItemVisualManager.cs
鼠标悬停建筑(仅开发面板开启时显示文字) 浮动水晶指示器 + 容器调试文本 BuildingHoverManager.cs

物品在容器里的最小单位是物品堆ItemStack.cs):物品 ID + 数量 + 一组动态属性(年龄 / 新鲜度 / 耐久 / 饱食 / 品质)。

  • 堆叠上限来自 StaticItemConfig.csvMaxStackSize 列(策划可直接改,改后需重新运行 Tools → CSV Code Generator)。
  • 配置缺失时回退到代码常量 50ItemStack.csMAX_STACK_SIZE)。
  • MaxStackSize ≤ 1 的物品完全不可堆叠也不可合并(当前表中只有 Monster 怪物 = 1)。

两个物品堆可以合并,当且仅当同时满足ItemStack.cs):

  1. 物品 ID 相同;
  2. 堆叠上限 > 1(不可堆叠物品直接拒绝);
  3. 目标堆未满;
  4. 双方的动态属性类型集合完全一致(例如都带 Age + Hungry;值可以不同)。

合并数量公式:

本次合并量 = min(目标堆上限 − 目标堆当前数量, 来源堆数量)

合并是“目标加、来源减”的真转移;来源堆剩余部分留在原地继续找下一个格子。

拆分:从一个堆里分出 n 个(n 必须严格小于当前数量),动态属性原样克隆到新堆。容器间转移只取走一格的一部分时,内部即走拆分。

合并时的属性结算(不同属性规则不同,详见下节)——这是策划要重点理解的机制:把新货倒进旧货堆,旧货的年龄/新鲜度会被摊薄而不是取最差值。

每个物品堆可携带最多 5 种动态属性,是否携带由 StaticItemConfig.csvUse* 开关决定(属性默认值 Default*、上限 Max* 同表配置):

属性 值域 单位 合并结算规则 出处
Age 年龄 0 ~ MaxAge 游戏天 按数量加权平均,四舍五入取整 Age.cs
Freshness 新鲜度 0 ~ MaxFreshness(默认 100) 百分比 按数量加权平均 Freshness.cs
HP 耐久 0 ~ MaxHP 按数量加权平均,四舍五入取整 HP.cs
Hungry 饱食恢复 0 ~ MaxHungry(默认 100) 百分比 按数量加权平均 Hungry.cs
Quality 品质 0=差 / 1=普通 / 2=优质 / 3=史诗 等级 取较高品质;但低品质一方数量 ≥ 高品质一方 3 倍时,取数量多的一方 Quality.cs

加权平均公式(Age / Freshness / HP / Hungry 通用):

合并后属性值 = (目标堆值 × 目标堆原数量 + 来源值 × 本次并入数量) ÷ (目标堆原数量 + 本次并入数量)

设计意图(Age.cs 代码注释明示):避免“1 滴老货污染整桶”的棘轮问题;副作用是玩家可以持续补新货摊薄老货——这是有意的玩法,鼓励主动轮转库存。

注意:CSV 中的 UseThirst / DefaultThirst / MaxThirst(解渴值)不会成为物品堆属性(没有对应属性类),它由船员需求系统直接读配置使用。

带 Age 属性且 FreshDays ≥ 0 的物品会逐日变质(ShelfLifeSystem.cs,每艘船一个实例,订阅日切事件,见 时间与调度):

  • 每过 1 游戏天,全船所有容器内带 Age 属性且 FreshDays ≥ 0 的物品堆年龄 +1(FreshDays = -1 的物品被跳过,年龄不增长)。
  • 三段状态(FreshnessState.cs):
状态 判定 对玩家的价值
新鲜 Fresh 年龄 ≤ FreshDays 100%
陈旧 Stale FreshDays < 年龄 ≤ FreshDays + StaleDays 50%(饱食/解渴恢复量、出售价统一打 5 折,代码常量 StaleValueMultiplier = 0.5FreshnessState.cs
腐烂 年龄 > FreshDays + StaleDays 整堆消失,原地转化为 RotItemId 指定的物品(等量)
  • 腐烂预警:年龄恰好等于 FreshDays + StaleDays 那天(即“明天就烂”)触发预警事件,UI 弹提示,给玩家整整一天去消耗 / 出售 / 再加工。
  • 腐烂整堆消失前会先清掉该格子上所有人的预留,防止任务系统永远认为这批货还被锁着。
  • 腐烂转化物(如腐食)如果被目标容器白名单拒收,会直接丢弃(仅日志告警)。

当前会腐烂的物品(StaticItemConfig.csv):

物品 新鲜段(天) 陈旧段(天) 腐烂于第几天 转化为
DrinkableWater 饮用水 10 8 第 19 天 StaleWater 臭水
MonsterMeat 怪物肉 3 2 第 6 天 RottenFood 腐食
CookedMeal 熟食 18 12 第 31 天 RottenFood 腐食
Grog 格罗格酒 36 24 第 61 天 StaleWater 臭水

容器(BaseContainer.cs)= 固定数量的格子ContainerSlot.cs),每格放一个物品堆。容量即格子数。

入库流程(两阶段)AddHandler.cs):

  1. 先逐格尝试并入已有的同物品格子(受合并规则约束);
  2. 剩余部分按堆叠上限切块放入空格(按格子序号从小到大找第一个白名单允许的空格)。

部分入库:空间只够装一部分时,操作仍返回成功并报告实际入库数量——容器满时多出的部分会被截断

**白名单过滤(Filter)**两级,均为白名单语义(空 = 不限制):

  • 容器级:限制整个容器收什么(如武器输入容器只收对应弹药)。
  • 格子级:限制单个格子收什么。典型用法是多弹药武器:AA 炮输入容器 2 格、2 种消耗品时,每种弹药独占 容量 ÷ 弹药种数 个格子,防止单一弹药占满(BuildingComponentContainers.cs 自动根据 WeaponConsumptionConfig.csv 的 Item1~Item4 生成,详见武器与弹药)。

容器三类型ContainerType.cs),语义直接决定搬运 AI 的行为:

类型 用途 可作搬运来源? 可作搬运目标?
Input 输入 建筑加工原料区 (防止船员从引擎输入区偷煤导致生产中断,回归测试 ContainerRegistryInputExclusionTests.cs 否(只能由定向投料任务写入)
Output 输出 生产产出区
Storage 存储 通用仓库 是(唯一合法目标)

各建筑容器容量BuildingContainerConfig.csv 全量,单位:格;未配置的建筑三容器容量均为 0,墙 / 楼梯等不暴露容器):

建筑 输入 输出 存储
WaterPump 水泵 0 1 0
Boiler 锅炉 3 3 0
Engine 引擎 1 1 0
ButcherTable 屠宰台 2 2 0
Galley 厨房 3 2 0
AmmoBench 弹药工作台 3 3 0
Brewery 酿酒坊 3 2 0
WoodContainer 木箱 0 0 30
PurchaseBox 采购箱 0 0 100
MagicContainer 魔法容器 0 0 100
WaterBarrel 水桶 0 0 1
Cannon_Prod / MachineGun_Prod / Flame_Prod(量产武器) 1 0 0
AA_Gun_Prod 2 0 0
Cannon_Dev / MachineGun_Dev / Flame_Dev(开发武器) 1 0 0
AA_Gun_Dev 2 0 0

特殊容器

容器 容量 行为 出处
船员随身背包 10 格 搬运途中临时持有 Crew.cs(代码常量)
地面容器 20 格(代码常量 DEFAULT_FLOOR_CAPACITY 按格子坐标自动创建/销毁 FloorContainerManager.cs
单格容器 1 格 装备槽类场景 OneGridContainer.cs
开发者容器 默认 50 格 取之不尽:移除永远成功不扣数量、查询总数恒为 999999、预留永远成功(见开发者工具 DevContainer.cs

所有建筑容器与地面容器统一注册到容器注册表ContainerRegistry.cs,每艘船一个实例)。任务系统找货 / 找仓位只通过它:

  • 找来源(FindSources):遍历所有注册容器,跳过 Input 容器、跳过施工格上的地面容器;只统计可用数量(扣除预留)> 0 的容器;按直线距离(格,欧几里得,非寻路距离)从近到远排序,截取前 N 个候选。
  • 找目标(FindTargets):只接受 Storage 类型且不是地面容器的容器,且可接纳数量 > 0;同样按直线距离从近到远排序。
  • 各业务的候选数 N:建筑生产取料预检 50 / 实际派单 8(ProductionFetchIssuer.cs),施工取料 8(FetchRequest.cs),锅炉补煤 8(SupplyBoilerRequest.cs),武器装弹 12(ReloadTurretRequest.cs),进食饮水 1(NeedRequestHelper.cs)。

资源预留系统(任务如何锁货)

Section titled “资源预留系统(任务如何锁货)”

这是物流稳定性的核心(ContainerReservationManager.cs,每个容器内置一个)。

概念:任务创建时在来源容器登记“我要 N 个 X”。物品物理上不动,仍躺在原格子里,但这 N 个对其他任务隐形。

可用数量 = 物理总数 − 所有人的预留总数

规则细则

  1. 预留按(物品 ID,预留者 ID)记账,并落实到具体格子:按格子序号从小到大,在已有该物品且尚有未预留余量的格子上分配。不能预留“未来才会有”的货。
  2. 预留申请量 > 当前可用量 → 整笔失败(不做部分预留)。
  3. 同一份货不可能被两个预留者重复锁定(测试佐证 ContainerReserveTests.cs)。
  4. 取货特权:操作者从容器取货时,可取上限 = 可用数量 + 自己的预留量;优先从自己预留的格子取(RemoveHandler.cs)。无操作者 ID 的“系统操作”只能动可用部分,绝不会碰别人预留的份额。
  5. 取走 / 转出后,按格子精确地自动释放等量预留——取多少释放多少,剩余预留继续有效。
  6. 预留不跟随物品转移:货从 A 容器搬到 B 容器后,A 上的预留被释放,B 上不会自动产生新预留。
  7. 每个任务用全局唯一的预留者 ID(如生产取料的 ProdFetch_建筑_物品_批次_随机串ProductionFetchIssuer.cs),避免跨任务串号。
  8. 兜底释放:任务无论完成、取消还是失败,结束时统一释放其名下所有剩余预留(TaskBase.cs + ResourceReservation.cs)——不存在超时机制,靠任务生命周期保证。
  9. 特殊清理:腐烂整堆消失前释放该格全部预留;水桶泄漏每次只漏 1 个单位时按数量精确扣减预留(“漏掉的这 1 份谁倒霉算谁的”,ContainerReservationManager.cs 注释)。

策划答疑:为什么界面显示有货,任务却说没货 / 卖不掉?

现象 原因
面板显示有 50 木头,施工却报“材料不足” 已有别的任务预留了这批木头:找货只看可用数量,面板显示的是物理总数(不扣预留,ShipInventoryPanel.cs
引擎输入区明明有煤,别的锅炉不来拿 Input 容器永远不作为搬运来源(防偷料保护)
施工蓝图脚下堆着材料,别处的需求不来拿 施工格(建筑处于框架状态)上的地面容器被排除出来源(施工现场材料保护,ContainerRegistry.cs
货卡在厨房输出区,“船上物品”面板看不到 面板只统计非生产建筑(不在 ProductionBuildingConfig.csv 里的建筑)的容器,生产中间品不计入“可用资源”
出售时交易界面数量比面板少 交易出售只扫 Storage 类型容器(PlayerTrader.cs,见交易

物品落地 = 该格自动创建一个 20 格的地面容器(FloorContainerManager.cs):

  • 来源:搬运任务中断时丢下携带物、Task_Haul 把材料送到施工格旁、船员失禁在脚下产生 1 个粪便(Crew.cs)。怪物战利品掉落走独立的 Loot 系统,不直接生成地面容器(见战利品与掉落)。
  • 可视化FloorItemVisualManager.cs):每格按 3×3 九宫格摆放物品图标(始终面向相机),最多 9 个,超出显示 “+N” 标签。图标尺寸 0.3、离地高度 0.1(Unity Inspector 序列化字段);九宫格间距 0.25(代码常量)。无图标资源的物品显示按物品 ID 哈希取色的色块(5 色备选,Inspector 字段)。
  • 拾回:地面容器默认注册为 Storage 类型,所以可以作为搬运来源被任务取走(施工格除外);但永远不会被选为搬运目标——散落地面的物品只会被搬进建筑仓库,不会从仓库搬到地上。
  • 自动清理:每发生 50 次“获取或创建地面容器”操作就清扫一遍空容器(代码常量 CLEANUP_INTERVAL);地面容器总数 ≥ 500 打警告日志、≥ 1000 打错误日志(仅日志,不阻止创建)。
  • 地板被摧毁:该格地面容器连同里面所有物品直接消失(材料丢失,仅日志告警)。

以“厨房缺怪物肉”为例(任务与工作 提供任务框架):

  1. 发单:生产派发器发现输入容器缺料,通过容器注册表找最近的合法来源(直线距离排序)。
  2. 锁货:在来源容器上预留所需数量;预留失败则尝试下一个候选来源。
  3. 建任务:生成搬运任务(送地面用 Task_Haul.cs,送建筑输入容器用 Task_HaulToContainer.cs),任务构造时把预留登记到自己名下。
  4. 可分配检查:任务被船员领取前持续校验“预留还在吗”(结果缓存 0.5 秒,代码常量,TaskBase.cs);预留失效(如货腐烂被清)则任务显示“预约失效”且无法分配。
  5. 执行四步:走到来源 → 拾取(先释放预留,再把货转移进船员 10 格背包,进入携带状态,Steps.Carry.cs)→ 走到目的地 → 放置(从背包转移进目标容器,Steps.Place.cs)。
  6. 中断兜底:任务中途取消 / 失败时,携带中的物品自动丢到船员脚下的地面容器(TaskBase.cs 的携带清理);未消费的预留由任务结束流程统一释放。
  7. 放置失败:目标容器装不下全部数量时放置步骤整体失败(转移要求一次容纳全部,不做部分转移,TransferHandler.cs),物品随后按中断流程丢到地面。
公式 出处
本次合并量 = min(堆叠上限 − 目标堆数量, 来源堆数量) ItemStack.cs
合并后属性值 = (目标值×目标原数量 + 来源值×并入数量) ÷ (目标原数量 + 并入数量)(Age/HP 四舍五入) ItemProperty.cs
品质合并 = 高品质方获胜;若低品质方数量 ≥ 高品质方 × 3 则数量方获胜 Quality.cs
可用数量 = 物理总数 − 全部预留 ContainerReservationManager.cs
操作者可取量 = 可用数量 + 自己的预留量 RemoveHandler.cs
腐烂条件:年龄 > FreshDays + StaleDays;预警:年龄 = FreshDays + StaleDays ShelfLifeSystem.cs
陈旧品价值 = 原值 × 0.5 FreshnessState.cs(代码常量)
武器格子白名单:每种弹药独占 输入容量 ÷ 弹药种数 个格子 BuildingComponentContainers.cs
数值 单位 来源类型 出处
堆叠上限回退值 50 代码常量 ItemStack.cs
船员背包容量 10 代码常量 Crew.cs
地面容器容量 20 代码常量 FloorContainerManager.cs
地面容器清理周期 每 50 次操作 代码常量 FloorContainerManager.cs
地面容器数量警告 / 错误阈值 500 / 1000 代码常量 FloorContainerManager.cs
地面图标上限 / 间距 9 个 / 0.25 个 / 世界单位 代码常量 FloorItemVisualManager.cs
地面图标尺寸 / 离地高度 0.3 / 0.1 世界单位 Inspector 序列化字段 FloorItemVisualManager.cs
开发者容器虚拟存量 999999 代码常量 DevContainer.cs
任务可分配检查缓存 0.5 代码常量 TaskBase.cs
船上物品面板刷新 0.2 代码常量 ShipInventoryPanel.cs
容器浮窗刷新 0.3 代码常量 ContainerPopupManager.cs
找货候选数:生产预检/派单、施工、锅炉、装弹、进食饮水 50/8、8、8、12、1 代码常量 ProductionFetchIssuer.cs
陈旧品价值系数 0.5 代码常量 FreshnessState.cs

物品总表(StaticItemConfig.csv,全量 29 行,CSV 配置,策划可直接改)

Section titled “物品总表(StaticItemConfig.csv,全量 29 行,CSV 配置,策划可直接改)”

列含义:堆叠上限 = 单格最多叠多少;动态属性列出该物品携带的属性及默认值;“鲜/陈(天)“为 -1 表示永不变质。

ItemId 名称 类型 堆叠上限 动态属性(默认值) 鲜/陈(天) 腐烂转化
Monster 怪物 Consumable 1 HP 100/100、Age 10(上限 100)、品质 1、饱食 50 -1(不走保质期)
SaltPork 咸肉 Food 20 品质 1、饱食 40 -1
DrinkableWater 饮用水 Food 50 Age 0(上限 19);解渴 50 10 / 8 StaleWater
Water 水(工业) Resource 50 -1
Steam 蒸汽 Resource 50 -1
Bullet 子弹 Resource 50 -1
CannonShell 炮弹 Resource 200 -1
Fuel 燃料 Resource 500 -1
AA_Gun_Bullet AA 子弹 Resource 50 -1
Wood 木头 Material 100 -1
Stone 石头 Material 100 -1
IronPlate 铁板 Material 50 -1
Feces 粪便 Waste 10 -1
Coal 煤炭 Resource 100 -1
MonsterCorpse 怪物尸体 Material 5 新鲜度 100/100 -1
MonsterMeat 怪物肉 Food 20 新鲜度 100/100、Age 0(上限 6)、饱食 15 3 / 2 RottenFood
BeastOil 兽油 Resource 50 -1
CookedMeal 熟食 Food 20 Age 0(上限 31)、饱食 50 18 / 12 RottenFood
BlackPowder 黑火药 Resource 50 -1
MonsterBrew 怪物酒 Food 30 品质 1;解渴 50;含酒精,单次饮用血醇 +40,自动饮用优先级 -1(不自动喝) -1
Grog 格罗格酒 Food 50 Age 0(上限 61)、品质 1;解渴 50;含酒精,单次饮用血醇 +10,优先级 20 36 / 24 StaleWater
RottenFood 腐食 Waste 50 品质 1 -1
StaleWater 臭水 Waste 50 品质 1 -1
LuxuryWine 奢侈红酒 Resource 30 -1
LuxuryTobacco 奢侈烟草 Resource 30 -1
LuxuryCloth 奢侈布匹 Resource 30 -1
LuxuryArtillery 奢侈火炮 Resource 30 -1
LuxuryCoffee 奢侈咖啡 Resource 30 -1
LuxurySilk 奢侈丝绸 Resource 30 -1

注:解渴值(Thirst 列)与饮用优先级由需求系统直接读取,不挂在物品堆上;完整逐列表格另见物品数据表配置表总览

  • 生产与制作:生产建筑通过输入/输出容器吞吐物料;取料派单走预留 + 搬运链路(ProductionFetchIssuer.cs)。
  • 修建:施工取料把材料搬到蓝图旁的地面容器;施工格地面容器受“来源排除”保护不被挪用。
  • 任务与工作:预留的生命周期与任务绑定;搬运任务的步骤组合(走→拾→走→放)。
  • 船员:10 格随身背包;失禁产生粪便;进食饮水从容器预留并取货。
  • 武器与弹药:武器输入容器自动生成弹药白名单与格子分配;装弹任务找货候选 12 个。
  • 交易:出售只扫 Storage 容器;陈旧食物饮品出售价打 5 折。
  • 战利品与掉落:怪物掉落走独立 Loot 系统,收集后才进入容器体系。
  • 时间与调度:保质期系统挂在“每游戏日”日切事件上。
  • 存档:容器经专用序列化类(SerializableContainerData.cs)保存容量 / 白名单 / 物品及属性;预留不进存档(见已知限制)。
  • 界面总览:船上物品面板、容器浮窗、地面物品图标的归属层级。
  • 开发者工具:无限物品的开发者容器;编辑器容器监视窗口(ContainerMonitorWindow.cs);悬停调试文本由开发面板开关。
想调什么 改哪里 注意
某物品堆叠上限 StaticItemConfig.csvMaxStackSize 改完跑 Tools → CSV Code Generator → Generate All
给物品加 / 删动态属性 同表 Use* / Default* / Max* Age、Hungry、HP、Freshness 还要求对应 Max > 0 才会真正挂上属性
让某物品会腐烂 同表 UseAge=trueFreshDays / StaleDays / RotItemId MaxAge 必须 ≥ FreshDays + StaleDays + 1,否则年龄被钳在上限永远到不了腐烂阈值(现有四种腐烂物均精确等于该值)
某建筑容器容量 BuildingContainerConfig.csv 对应行 容量 0 = 不创建该容器;新建筑不配行则三容器全无
武器吃什么弹药(输入白名单) WeaponConsumptionConfig.csv 的 Item1~Item4 白名单与格子分配自动生成
陈旧品打折力度 FreshnessState.csStaleValueMultiplier(现 0.5) 代码常量,需程序改
船员背包容量 Crew.cs 构造背包处(现 10) 代码常量,需程序改
地面容器格数 / 清理频率 FloorContainerManager.cs(现 20 格 / 每 50 次操作) 代码常量,需程序改
地面图标大小 / 离地高度 / 占位色 FloorItemVisualManager 组件的 Inspector 字段 运行时自动创建的单例对象,改默认值需改脚本序列化初值
找货候选数量 / 排序 各请求类(ProductionFetchIssuer.csFetchRequest.cs 等)传入的 maxResults 代码常量,需程序改
面板 / 浮窗刷新频率 ShipInventoryPanel.cs(0.2 秒)、ContainerPopupManager.cs(0.3 秒) 代码常量,需程序改
  1. 预留不进存档SerializableContainerData.cs 的预留转换是空实现(代码注释“暂时跳过,可后续完善”)。读档后所有预留清零,依赖任务系统重新发单建立预留。
  2. 找货用直线距离:来源排序按格子坐标欧几里得距离,不是寻路距离——隔着一层甲板的“近”仓库可能实际绕路很远。
  3. 预留锁数量不锁实物:系统操作(无操作者)取走可用份额时,物理上可能恰好动了你预留的那一格的实物,但数量账目守恒,预留者随后取货仍然成功(测试佐证 ContainerReserveTests.cs)。
  4. 部分入库会静默截断:容器满时入库返回“成功 + 实际数量”,超出部分不退回;腐烂转化物被白名单拒收时直接丢弃(仅日志)。
  5. 转移不支持部分成功:目标装不下全部数量时整笔失败(TransferHandler.cs 预校验),搬运任务随即把货丢在地上。
  6. 地板摧毁 = 物品蒸发:该格地面容器及全部内容直接删除,无掉落保护。
  7. 摊薄合并可被刻意利用:往陈旧堆里持续倒新货可把平均年龄压回新鲜段——代码注释明确这是有意设计(鼓励轮转库存),调保质期数值时要把这个回血手段算进去。
  8. 不可堆叠物品的“同属性合并 1 个”分支是死代码ItemStack.cs 的可合并量计算里有 MaxStackSize ≤ 1 时按属性全同合并 1 个的逻辑,但合并前置检查对不可堆叠物品直接拒绝,该分支实际不可达。
  9. 按物品堆实例移除不会自动释放预留RemoveHandler.csRemoveStackHandler 注释明示由调用方负责);生产路径主要走“按物品 ID 移除”,该路径有自动精确释放。
  10. 怪物(Monster)带 Age 属性但 FreshDays = -1,保质期系统完全跳过它,年龄不会逐日增长——Age 10 只是静态档案值。
  11. 待重构标记(代码 TODO):FloorItemVisualManager.cs 应改用统一单例基类;BuildingHoverManager.cs 计划重构为挂在建筑上的分布式悬停组件。
  12. 属性合并依赖反射:物品堆合并属性时通过反射调用各属性的合并方法(ItemStack.cs),与项目“运行时禁反射”的规约存在出入,属于历史遗留实现。