You are viewing a potentially older version of this package. View all versions.
XiaohaiMod-HTF_MoreItemAPI-2.0.0 icon

HTF MoreItemAPI

Runtime API for How to Fish custom-item mods, with automatic Item IDs, AssetBundle icons and hand poses, game-component reconstruction, and FishNet spawning.

Date uploaded 3 days ago
Version 2.0.0
Download link XiaohaiMod-HTF_MoreItemAPI-2.0.0.zip
Downloads 458
Dependency string XiaohaiMod-HTF_MoreItemAPI-2.0.0

This mod requires the following mods to function

BepInEx-BepInExPack-5.4.2305 icon
BepInEx-BepInExPack

BepInEx pack for Mono Unity games. Preconfigured and ready to use.

Preferred version: 5.4.2305

README

HTF MoreItemAPI

Language / 语言: English · 简体中文


English

HTF MoreItemAPI is a BepInEx runtime API that lets C# content mods register independent custom items in How to Fish. A content mod loads its own AssetBundle and calls one registration method; the API copies a compatible original item skeleton, reconstructs the game and FishNet components, applies the authored physics and hand-pose data, and registers the result.

Use the separate HTFItemSDK Unity package to author prefabs, embedded inventory icons, visual hand poses, item-definition assets, and validated AssetBundles.

Supported environment

  • How to Fish 1.0.10
  • Unity 6000.4.4f1
  • BepInEx 5.4.23.5
  • HTF MoreItemAPI 2.0.0
  • BepInEx GUID xiaohai.HTF.MoreItemAPI
  • HTFItemSDK / Contracts 0.1.3

The generated-item pipeline validates the current Assembly-CSharp MVID before cloning game structures. An unsupported game update is rejected with a compatibility error instead of registering a partial network prefab.

Install

Copy these two assemblies from dist/ into the game's BepInEx/plugins/HTF-MoreItemAPI/ directory:

HTFMoreItemAPI.dll
HowToFish.ItemSDK.Contracts.dll

Every multiplayer participant must install the same API, content-mod DLL, and AssetBundle versions.

Recommended SDK definition workflow

Declare a hard dependency from your content mod:

[BepInDependency(ItemApiMetadata.PluginGuid, BepInDependency.DependencyFlags.HardDependency)]

Load the HTFItemDefinitionAsset built by HTFItemSDK and register it before connecting or starting a server:

AssetBundle bundle = AssetBundle.LoadFromFile(bundlePath);
HTFItemDefinitionAsset definition =
    bundle.LoadAsset<HTFItemDefinitionAsset>("C4ItemDefinition");

ItemRegistrationHandle handle = ItemRegistry.RegisterGenerated(
    GeneratedItemRegistration.FromDefinition(
        definition,
        "com.example.c4item"));

Creators do not select an ItemId. Keep modGuid and the definition's InternalName stable after release; HTF MoreItemAPI uses their normalized modGuid:internalName key as the logical item identity and assigns the game-local byte slot centrally.

Lower-level generated-item workflow

You can load a normal content prefab and icon directly instead of using an SDK definition:

GameObject contentPrefab = bundle.LoadAsset<GameObject>("EnergyDrinkItem");
Texture2D icon = bundle.LoadAsset<Texture2D>("EnergyDrinkIcon");

ItemRegistrationHandle handle = ItemRegistry.RegisterGenerated(
    new GeneratedItemRegistration
    {
        ModGuid = "example.author.items",
        InternalName = "energy_drink",
        ContentPrefab = contentPrefab,
        DisplayName = "Energy Drink",
        InventoryIcon = InventoryIcon.FromTexture(icon),
        PickupRadius = 0.55f,
        Buoyancy = 1f
    });

An AssetBundle Sprite can also be used:

Sprite icon = bundle.LoadAsset<Sprite>("EnergyDrinkIcon");
InventoryIcon inventoryIcon = InventoryIcon.FromSprite(icon);

The API never reads external PNG, ICO, JSON, or resource-path files. The inventory icon remains inside the content mod's AssetBundle.

Content prefab contract

ContentPrefab must be a prefab asset returned by AssetBundle.LoadAsset<GameObject>(), not a scene instance. Prepare the following normal Unity content:

  • Model, materials, lights, particles, audio, and other presentation assets.
  • Exactly one Rigidbody on the prefab root. Its mass, damping, gravity, interpolation, collision mode, and constraints become the final item settings.
  • At least one Collider for world collision.
  • A Texture2D or Sprite inventory icon.

Do not include Item, RigidbodySync, NetworkObject, FishNet components, or missing game scripts. HTF MoreItemAPI supplies and reconstructs them from a compatible original item template. It resets the cloned content root position and rotation, preserves scale, copies the authored Rigidbody settings to the generated game root, removes the content Rigidbody, and registers the content colliders as Item._worldColliders. A separate game-owned pickup trigger is created from PickupRadius.

The advanced ItemRegistry.Register(ItemRegistration) interface remains available for prefabs that already contain a complete original game-script structure. Public content mods should normally use RegisterGenerated.

IDs and networking

  • Content mods cannot set ItemId. After the original GameInfo registry is ready, the API reserves every original-game ID and centrally assigns free byte slots to pending custom items.
  • Allocation sorts stable modGuid:internalName keys, starts from a stable hash, and probes occupied slots. Registration order therefore cannot change the mapping for the same original registry and installed content-mod set.
  • ItemRegistrationHandle.ItemId is nullable while pending. Read it only after HasAssignedItemId is true; normal gameplay should wait for IsRegistered.
  • The underlying game registry uses byte IDs. ID 255 is reserved because the base game also uses it as a sentinel, leaving at most 255 numeric slots before original items are counted. Registration fails explicitly when no slot remains.
  • Every multiplayer peer must load the same content-mod set and versions before the network session starts. Changing the installed set can change collision-resolved byte assignments, so version-2 automatic IDs are not yet a permanent cross-mod-set save identity.
  • The API rejects conflicts by stable key, normalized name, or FishNet collection.
  • The default collection ID is derived deterministically from ModGuid:InternalName. On the rare event of a hash collision, explicitly configure the same unused NetworkCollectionId on every peer.
  • Call RegisterGenerated or Register before connecting a client or starting a server.
  • A returned ItemRegistrationHandle can initially be pending. Subscribe to ItemRegistry.RegistrationChanged; its successful final state is Registered.

Network-spawn a registered item

After the handle reaches Registered, the server or host can spawn the custom item through the game's ItemManager. FishNet will replicate that spawned object to the other peers:

if (handle.IsRegistered &&
    handle.ItemPrefab &&
    ItemManager.Instance &&
    ItemManager.Instance.IsServerInitialized)
{
    Item spawned = ItemManager.Instance.SpawnNewItem(
        handle.ItemPrefab,
        spawnPosition,
        spawnRotation);
}

Only the server may call SpawnNewItem. A client-side button or command must send a request through a ServerRpc owned by that content mod, then let the server execute this code after validating the request. Do not use UnityEngine.Object.Instantiate for gameplay spawning; that creates a local object outside FishNet's network-spawn path.

AssetBundle lifetime

The caller owns the AssetBundle. The API retains Unity object references only:

  • Do not call bundle.Unload(true) while the item is registered.
  • If the bundle container must be released after assets load, call bundle.Unload(false) only.
  • Prefer a square transparent PNG imported as Texture2D, or an unpacked/unrotated Sprite.

See Examples/ExampleItemPlugin.cs for an embedded-bundle example. The example is excluded from HTFMoreItemAPI.dll.

Building from source

The project references the installed game's managed assemblies and BepInEx. Build it from a checkout placed next to the game workspace layout used by the project, or update the HintPath entries in HTFMoreItemAPI.csproj for your installation. Clone HTFItemSDK beside HTF-MoreItemAPI; the Contracts/ project compiles the package's serializable runtime contract sources into HowToFish.ItemSDK.Contracts.dll, keeping one source of truth. The public C# namespace remains HowToFish.ItemAPI for source compatibility.

workspace/
├─ HTF-MoreItemAPI/
└─ HTFItemSDK/
dotnet build .\HTFMoreItemAPI.csproj -c Release

License

MIT. See LICENSE.


简体中文

HTF MoreItemAPI 是一个 BepInEx 运行时 API,让 C# 内容 Mod 可以在 How to Fish 中注册独立的自定义物品。内容 Mod 负责加载自己的 AssetBundle 并调用一次注册接口;API 会复制兼容的原版物品骨架,重构游戏和 FishNet 组件,应用开发者制作的物理与手持姿势数据,最后将物品注册到游戏中。

请使用独立的 HTFItemSDK Unity 包制作 Prefab、内嵌物品栏图标、可视化手持姿势、物品定义资产和经过验证的 AssetBundle。

支持环境

  • How to Fish 1.0.10
  • Unity 6000.4.4f1
  • BepInEx 5.4.23.5
  • HTF MoreItemAPI 2.0.0
  • BepInEx GUID xiaohai.HTF.MoreItemAPI
  • HTFItemSDK / Contracts 0.1.3

生成式物品流水线会先验证当前 Assembly-CSharp 的 MVID。游戏更新造成结构不兼容时,API 会输出兼容性错误并拒绝注册,不会留下不完整的网络 Prefab。

安装

dist/ 中的两个程序集复制到游戏的 BepInEx/plugins/HTF-MoreItemAPI/

HTFMoreItemAPI.dll
HowToFish.ItemSDK.Contracts.dll

所有联机参与者必须安装相同版本的 API、内容 Mod DLL 和 AssetBundle。

推荐的 SDK 物品定义流程

内容 Mod 必须声明硬依赖:

[BepInDependency(ItemApiMetadata.PluginGuid, BepInDependency.DependencyFlags.HardDependency)]

加载 HTFItemSDK 构建出的 HTFItemDefinitionAsset,并在连接客户端或启动服务器前完成注册:

AssetBundle bundle = AssetBundle.LoadFromFile(bundlePath);
HTFItemDefinitionAsset definition =
    bundle.LoadAsset<HTFItemDefinitionAsset>("C4ItemDefinition");

ItemRegistrationHandle handle = ItemRegistry.RegisterGenerated(
    GeneratedItemRegistration.FromDefinition(
        definition,
        "com.example.c4item"));

开发者不再设置 ItemId。发布后请长期保持 modGuid 和物品定义中的 InternalName 不变;HTF MoreItemAPI 会把规范化后的 modGuid:internalName 作为逻辑物品身份,并统一分配游戏内部的 byte 槽位。

底层生成式物品接口

不使用 SDK 物品定义时,也可以直接从 AssetBundle 加载普通内容 Prefab 和图标:

GameObject contentPrefab = bundle.LoadAsset<GameObject>("EnergyDrinkItem");
Texture2D icon = bundle.LoadAsset<Texture2D>("EnergyDrinkIcon");

ItemRegistrationHandle handle = ItemRegistry.RegisterGenerated(
    new GeneratedItemRegistration
    {
        ModGuid = "example.author.items",
        InternalName = "energy_drink",
        ContentPrefab = contentPrefab,
        DisplayName = "Energy Drink",
        InventoryIcon = InventoryIcon.FromTexture(icon),
        PickupRadius = 0.55f,
        Buoyancy = 1f
    });

也可以使用 AssetBundle 中的 Sprite

Sprite icon = bundle.LoadAsset<Sprite>("EnergyDrinkIcon");
InventoryIcon inventoryIcon = InventoryIcon.FromSprite(icon);

API 不会读取外部 PNG、ICO、JSON 或资源路径文件。物品栏图标始终保存在内容 Mod 自己的 AssetBundle 中。

内容 Prefab 规范

ContentPrefab 必须是 AssetBundle.LoadAsset<GameObject>() 返回的 Prefab 资产,不能是场景实例。开发者只需准备普通 Unity 内容:

  • 模型、材质、灯光、粒子、音频和其他表现资源。
  • Prefab 根节点恰好一个 Rigidbody;质量、阻尼、重力、插值、碰撞模式和约束会成为最终物品设置。
  • 至少一个用于世界碰撞的 Collider
  • 一个 Texture2DSprite 物品栏图标。

不要包含 ItemRigidbodySyncNetworkObject、FishNet 组件或缺失的游戏脚本。HTF MoreItemAPI 会从兼容的原版模板提供并重构这些结构。API 会重置克隆内容根节点的位置和旋转、保留缩放,把开发者设置的 Rigidbody 参数复制到生成的游戏根节点,删除内容 Rigidbody,并将内容碰撞体注册到 Item._worldColliders。拾取 Trigger 则根据 PickupRadius 单独生成。

高级接口 ItemRegistry.Register(ItemRegistration) 仍然保留,用于已经拥有完整原版游戏脚本结构的 Prefab。公开内容 Mod 通常应使用 RegisterGenerated

ID 与联网规则

  • 内容 Mod 不能自行设置 ItemId。原版 GameInfo 注册完成后,API 会保留全部原版 ID,再为待注册的自定义物品统一分配空闲 byte 槽位。
  • 分配器先按稳定的 modGuid:internalName 排序,再从稳定哈希位置开始探测空槽,因此在原版注册表和已安装内容 Mod 集合相同时,Mod 加载顺序不会改变映射。
  • ItemRegistrationHandle.ItemId 在等待阶段可为 null。只有 HasAssignedItemIdtrue 后才能读取;正常游戏逻辑应等待 IsRegistered
  • 游戏底层仍然使用 byte ID。原版还把 255 当作哨兵值,因此在扣除原版物品前也至多只有 255 个数值槽位。没有空槽时,注册会输出明确错误并失败。
  • 所有联机端必须在启动网络会话前加载相同版本、相同集合的内容 Mod。改变已安装 Mod 集合可能改变发生哈希碰撞后的 byte 映射,因此 2.0 的自动 ID 尚不能作为跨 Mod 集合永久不变的存档身份。
  • API 会拒绝稳定键、规范化名称或 FishNet collection 冲突。
  • 默认 collection ID 根据 ModGuid:InternalName 确定性生成。极少数情况下发生哈希冲突时,所有客户端必须显式配置同一个未占用的 NetworkCollectionId
  • 必须在连接客户端或启动服务器前调用 RegisterGeneratedRegister
  • 返回的 ItemRegistrationHandle 可能暂时处于 Pending 状态。可监听 ItemRegistry.RegistrationChanged;成功的最终状态为 Registered

网络生成已注册物品

当 Handle 进入 Registered 状态后,服务器或房主可以通过游戏原版 ItemManager 生成自定义物品,FishNet 会把生成的对象同步给其他联机端:

if (handle.IsRegistered &&
    handle.ItemPrefab &&
    ItemManager.Instance &&
    ItemManager.Instance.IsServerInitialized)
{
    Item spawned = ItemManager.Instance.SpawnNewItem(
        handle.ItemPrefab,
        spawnPosition,
        spawnRotation);
}

只有服务器可以调用 SpawnNewItem。如果生成操作由客户端按钮或命令触发,内容 Mod 必须通过自己拥有的 ServerRpc 向服务器发送请求,由服务器验证请求后执行上述代码。不要使用 UnityEngine.Object.Instantiate 生成游戏物品;那只会创建脱离 FishNet 网络生成流程的本地对象。

AssetBundle 生命周期

AssetBundle 由调用方管理,API 只保留 Unity 对象引用:

  • 物品已注册时不要调用 bundle.Unload(true)
  • 如果资源加载完成后必须释放 Bundle 容器,只能调用 bundle.Unload(false)
  • 图标建议使用透明背景正方形 PNG,并导入为 Texture2D,或使用未旋转打包的 Sprite

内嵌 AssetBundle 的完整示例位于 Examples/ExampleItemPlugin.cs,不会编入 HTFMoreItemAPI.dll

从源码构建

项目引用游戏安装目录中的托管程序集和 BepInEx。请把 HTFItemSDKHTF-MoreItemAPI 克隆到同一工作目录下;Contracts/ 项目会直接编译 SDK 中可序列化的运行时契约源码,避免维护两份类型定义。为降低已有内容 Mod 的源码迁移成本,公开 C# 命名空间继续使用 HowToFish.ItemAPI

workspace/
├─ HTF-MoreItemAPI/
└─ HTFItemSDK/

如果目录布局与项目默认值不同,请修改 HTFMoreItemAPI.csproj 中的 HintPath

dotnet build .\HTFMoreItemAPI.csproj -c Release

许可证

MIT,详见 LICENSE

CHANGELOG

Changelog

2.0.0 - 2026-08-30

  • Removed developer-supplied ItemId from both public registration models.
  • Added centralized byte-slot allocation after the original GameInfo registry is ready.
  • Reserved all original-game IDs plus the base game's byte-255 sentinel, then assigned pending items deterministically from their stable modGuid:internalName keys.
  • Exposed the assigned ID as nullable ItemRegistrationHandle.ItemId; it is available after allocation and registration.
  • Added explicit exhaustion diagnostics for the finite byte registry.

1.2.0 - 2026-08-30

  • Finalized the plugin name as HTF MoreItemAPI, the assembly as HTFMoreItemAPI.dll, and the BepInEx GUID as xiaohai.HTF.MoreItemAPI.
  • Added SDK item-definition and serialized hold-pose support.
  • Added original-game hand target and finger-joint mapping for generated items.
  • Stabilized generated item transforms, Rigidbody ownership, colliders, and held-item motion.
  • Added an embedded inventory-icon contract with no external resource files.
  • Standardized public documentation and runtime diagnostics in English.

1.1.1

  • Added the fixed generated-item reconstruction pipeline.
  • Added safe game-version validation and registration conflict checks.