开始之前!
FreeMinecraftModels (FMM) 目前正在积极开发中!这意味着某些功能尚未完成,并且正在积极开发中。
然而,目前插件的核心功能已完全可用 - 转换 bbmodel 文件、生成资源包、在游戏中生成实体并管理它们的动画、放置持久化道具的能力,这些都基本可以正常工作。
请考虑在 https://www.patreon.com/magmaguy 支持开发!
导出的资源包内容在 FreeMinecraftModels 这边采用 CC0 许可证,不保留任何权利。您可以自由使用、分发、修改用于任何目的,无需任何限制或署名。
使用此插件
FreeMinecraftModels (FMM) 能为 Minecraft 服务器管理员做什么?
它可以:
- 导入 .bbmodel 或 fmmodel(FFM 的自定义格式)模型
- 生成超出普通 Minecraft 资源包模型限制的资源包(最大 112x112x112 单位或游戏内 7x7x7 方块,使用多个骨骼时功能上无限制)
- 在游戏中显示这些模型,向基岩版客户端发送特定的基岩版兼容数据包,同时向 1.19.4+ Java 版客户端发送显示实体
- 按照在 Blockbench 中配置的方式为这些模型设置动画
- 处理默认状态动画,无需其他插件(行走、待机、死亡、攻击、生成)
- 处理随底层实体旋转且 x 和 z 轴不同的碰撞箱
- 管理三种类型的模型:静态、动态和道具
- 道具是持久化的,可以放置在世界中,即使服务器重启也会保持,并且可以将带有道具的地图分发到其他服务器
- 动态模型适用于需要底层生物实体才能运行的模型,理想情况下由自定义 Boss 插件或宠物插件使用
- 静态模型适用于不应移动的非持久化模型,基本上是临时装饰或效果
如何添加现有模型?
要导入模型,只需将 .bbmodel 拖到 imports 文件夹中并执行 /fmm reload。这将在 models 文件夹中生成一个 .fmmodel 文件,并将模型添加到 outputs 文件夹中的资源包。
您需要使用该资源包才能正确查看模型! 这是一个普通的资源包,因此您只需将其放入资源包文件夹即可。Minecraft 服务器有办法托管资源包。我推荐使用我的插件 ResourcePackManager,它会自动获取文件并远程托管,甚至将它们与其他插件的文件合并。
如何在游戏中查看模型?
重要的是要注意,虽然 FreeMinecraftModels 可以作为独立插件用于查看道具(基本上是可以放置在世界中的自定义模型),但该插件通常在与诸如 EliteMobs 之类的插件配合使用时效果最佳,在那里模型被积极用于具体的事情,在这种情况下是 Boss 战。
有三种类型的模型:静态、动态和道具。
- 道具是持久化的,可以放置在世界中,即使服务器重启也会保持,并且可以将带有道具的地图分发到其他服务器
- 动态模型适用于需要底层生物实体才能运行的模型,理想情况下由自定义 Boss 插件或宠物插件使用
- 静态模型适用于不应移动的非持久化模型,基本上是临时装饰或效果
在游戏中查看静态模型
要在游戏中查看静态模型,请使用命令 /fmm spawn static <id>,其中 id 是模型的文件名,小写且不带文件扩展名。
在游戏中查看动态模型
要在游戏中查看动态模型,请使用命令 /fmm spawn dynamic <id>,其中 id 是模型的文件名,小写且不带文件扩展名。
在游戏中查看道具
要在游戏中查看动态模型,请使用命令 /fmm spawn prop <id>,其中 id 是模型的文件名,小写且不带文件扩展名。
FreeMinecraftModels (FMM) 能为建模师做什么?
FMM 遵循标准资源包规则进行资源包生成。此外,它尽可能与 ModelEngine 兼容的模型保持兼容,以尝试标准化跨插件的模型创建。
模型生成功能/限制
如果您曾经为 ModelEngine 创建过模型,您会熟悉许多 Minecraft 资源包生成限制:
立方体:
这里的立方体与 Blockbench 中的相同,它们是构成模型的立方体。
- 立方体最大可以达到 112x112x112 "像素"(Blockbench 单位)或游戏内 7x7x7 方块(使用显示大小绕过普通 Minecraft 限制,很快将通过显示实体进一步绕过 1.19.4+)
- 立方体的合法旋转为 0、22.5、-22.5、45 和 -45。没有其他旋转有效。
- 立方体只在一个轴上旋转,这意味着 [22.5, 0, 0] 的旋转是可以的,[22.5, 0, 45] 的旋转将无法完全工作,只会在一个轴上旋转。
骨骼:
骨骼是 Blockbench 所称的"组"。它们用于将立方体分组在一起,应该用于为动画蓝图将骨骼分组在一起。
- 骨骼最大可以达到 112x112x112 "像素"(Blockbench 单位)或游戏内 7x7x7 方块。请注意,骨骼的大小由其包含的内容设置,因此如果您的立方体相距超过 7 个方块,您可能会超过此大小限制。绕过此限制很简单,只需将方块放在不包含在第一个骨骼蓝图中的不同骨骼蓝图中!
- 可以有任何旋转!但是,建议避免使用 90、-90、180 和 -180 的默认旋转,因为这些通常会导致意外行为。请注意,这实际上不适用于动画,只是骨骼的默认静止位置。
骨骼比立方体灵活得多,但您应该使用尽可能少的骨骼!在 FMM 中,由于 Minecraft 的限制,每个骨骼都是一个不同的实体。在规模化时,这将很快影响性能!始终使用尽可能少的骨骼,并注意您计划生成该模型的数量 - 您计划拥有的越多,您应该拥有的骨骼就越少!
虚拟骨骼
虚拟骨骼是 model engine 术语,用于具有特定元数据的骨骼,通常以特定名称的形式,用于特定目的。
以下虚拟骨骼已在 FreeMinecraftModels 中实现:
- 碰撞箱/眼睛高度:名为 "hitbox" 的骨骼,带有定义边界的立方体蓝图,并且具有相同的 x 和 z 值(如果它们不相同,将选择最大值)定义碰撞箱。眼睛高度设置在碰撞箱的骨骼蓝图的枢轴点。
- 名称标签:名称以 "tag_" 开头的骨骼。老实说,我更希望在这里更具体一些,使用 "tag_name",以便将标签用于其他事情,但这将在以后认真考虑。
- 头部:名称以 h_ 开头的骨骼。这是一个虚拟骨骼,用于定义模型的头部,它将根据底层实体头部的旋转而旋转。
更安全、更简单、不可编辑的文件分发
FMM 尝试解决的一件事是用户重新利用他们获得的模型,以模型创建者不希望他们编辑的方式编辑它们,特别是为了重新皮肤或以其他方式稍微改变模型,并可能试图作为原创作品转售。
为此,FMM 使用 .fmmodel 文件格式,旨在将 .bbmodel 文件精简到可以被插件使用但无法在 Blockbench 中编辑的程度。
作为建模师,您现在可以选择是否要发布不可编辑的 .fmmodel 文件、可编辑的 .bbmodel 文件,甚至对两者进行差异定价或分发服务条款。
生成 .fmmodel 就像将您的 .bbmodel 放入 ~/plugins/FreeMinecraftModels/imports 文件夹并使用 /fmm reload 重新加载插件或重启服务器一样简单。然后您的 .fmmodel 将位于 ~/plugins/FreeMinecraftModels/models 文件夹中。
FreeMinecraftModels (FMM) 能为想要将其集成到插件中的开发人员做什么?
FMM 有一个 maven 仓库! Maven:
<repository>
<id>magmaguy-repo-releases</id>
<name>MagmaGuy's Repository</name>
<url>https://repo.magmaguy.com/releases</url>
</repository>
<dependency>
<groupId>com.magmaguy</groupId>
<artifactId>FreeMinecraftModels</artifactId>
<version>LATEST.VERSION.HERE</version>
</dependency>
Gradle:
maven {
name = "magmaguyRepoReleases"
url = uri("https://repo.magmaguy.com/releases")
}
compileOnly group : 'com.magmaguy', name: 'FreeMinecraftModels', version: 'LATEST.VERSION.HERE'
注意 FreeMinecraftModels 旨在用作 API,需要在服务器上安装插件。不要将其打包到您的插件中!
API 使用
FMM 旨在尽可能易于用作 API。
现在,如果您希望使用 FreeMinecraftModels 作为 API 来访问使用自定义模型,您只需要了解四个类:
ModeledEntity- 所有实体的基类StaticEntity- 当您想使用非永久性静态模型时DynamicEntity- 当您想用模型伪装另一个生物实体时PropEntity- 当您想在世界中放置一个即使服务器重启也会保持的模型时
以下是处理静态模型的代码片段:
import org.bukkit.Bukkit;
public class FreeMinecraftModelsModel {
private StaticEntity staticEntity = null;
//Create the model
public FreeMinecraftModelsModel(String id, Location location) {
//This spawns the entity!
staticEntity = StaticEntity.create(id, location);
//This checks if the entity spawned correctly
if (staticEntity == null) Bukkit.getLogger().warning(("FMM failed to find a model named " + id + " !"));
}
public void remove() {
//This removes the entity
staticEntity.remove();
}
}
请记住,静态模型旨在保持在原地并充当固定位置的装饰元素(这里的"移动"不包括动画)。虽然可以移动它们,但如果这是您的目的,请考虑是否可能想要使用动态模型。
以下是我的自定义 Boss 插件 EliteMobs 如何使用动态实体:
package com.magmaguy.elitemobs.thirdparty.custommodels.freeminecraftmodels;
import com.magmaguy.elitemobs.thirdparty.custommodels.CustomModelInterface;
import api.com.magmaguy.freeminecraftmodels.ModeledEntityManager;
import customentity.com.magmaguy.freeminecraftmodels.DynamicEntity;
import lombok.Getter;
import org.bukkit.entity.LivingEntity;
public class CustomModelFMM implements CustomModelInterface {
@Getter
private DynamicEntity dynamicEntity;
public CustomModelFMM(LivingEntity livingEntity, String modelName, String nametagName) {
dynamicEntity = DynamicEntity.create(modelName, livingEntity);
if (dynamicEntity == null) return;
dynamicEntity.setName(nametagName);
}
public static void reloadModels() {
ModeledEntityManager.reload();
}
public static boolean modelExists(String modelName) {
return ModeledEntityManager.modelExists(modelName);
}
@Override
public void shoot() {
if (dynamicEntity.hasAnimation("attack_ranged")) dynamicEntity.playAnimation("attack_ranged", false);
else dynamicEntity.playAnimation("attack", false);
}
@Override
public void melee() {
if (dynamicEntity.hasAnimation("attack_melee")) dynamicEntity.playAnimation("attack_melee", false);
else dynamicEntity.playAnimation("attack", false);
}
@Override
public void playAnimationByName(String animationName) {
dynamicEntity.playAnimation(animationName, false);
}
@Override
public void setName(String nametagName, boolean visible) {
dynamicEntity.setName(nametagName);
dynamicEntity.setNameVisible(visible);
}
@Override
public void setNameVisible(boolean visible) {
dynamicEntity.setNameVisible(visible);
}
@Override
public void switchPhase() {
dynamicEntity.stopCurrentAnimations();
}
}
动态模型建立在生物实体之上,可以在使用 create 方法时提供(如上面的示例),或者在动态实体上运行 spawn 方法时提供。
作为开发人员为 FreeMinecraftModels (FMM) 项目做出贡献
FMM 在 GPLV3 许可证下分发,欢迎代码贡献。以下是基本贡献指南:
- 遵循现有的命名约定,保持现有的详细程度,并添加足够的文档,使您的贡献易于理解
- 保持贡献与插件的范围相关。如果您不知道它是否相关,请随时提前询问。
- 注意代码的性能影响。如果贡献过于未优化或导致性能影响过大,可能会被拒绝。
插件总体概述
为了节省您的时间,以下是 FMM 的逻辑流程的快速分解:
- 读取
imports文件夹 - 将文件从
imports文件夹移动到models文件夹。如果文件是.bbmodel,它会在models文件夹中转换为.fmmodel。 - 读取
models文件夹中的文件。 - 解释所有模型结构,创建包含
Bone组的Skeleton,这些骨骼包含子Bone和Cube组。Cube和Bone生成与它们各自相关的 JSON 资源包数据。这意味着Cube生成特定于立方体的 JSON,Bone生成轮廓和单独的骨骼蓝图文件。请注意,一个骨骼蓝图会生成一个资源包文件。模型在生成时会添加到列表中。 - 仍然在
Skeleton中,解释模型中的所有Animations(如果有) - 所有数据现在已初始化,资源包已在
outputs文件夹中生成,插件已准备好使用。
此插件中使用的技巧:
这里使用的技巧已经相当成熟和标准化,但仍将列出,因为它们可能违反直觉。
请注意,这些技巧对用户和建模师完全不可见;列出限制和解决方法只是为了帮助您了解 FMM 如何绕过各种 Minecraft 限制。
- 所有模型都放大 4 倍,然后在代码中重新调整大小和枢轴点,以扩展模型的理论最大尺寸
- 因为资源包模型只能具有从 -16 到 +32 的大小,所以模型会在后台移动。这对玩家完全不可见。
- 皮革马铠用于创建可以通过代码影响色调的模型(即用于伤害指示)。马铠必须设置为白色才能显示正确的颜色!
- Blockbench 对纹理使用特定的 ID 系统,但实际上从配置中按顺序读取纹理。这里根据它们在纹理列表中的位置分配 ID,遵循 Blockbench 的做法。
- 由于 Minecraft 的限制,每个骨骼都是一个不同的实体
- 皮革马铠位于盔甲架的头部槽位
- 盔甲架和显示实体都用于默认静态项目;基岩版客户端获得盔甲架,1.19.4+ 客户端获得显示实体(较旧的客户端将获得盔甲架)
为 FreeMinecraftModels (FMM) 项目做出一般贡献
FMM 实际上是由 https://www.patreon.com/magmaguy 的可爱人们众筹的!所有贡献的帮助都超出您的想象 ;)
当前计划的功能:
- 基岩版客户端 RSP 生成
- 带有 geyser 集成的 RSP 管理
- tag_projectile 作为元骨骼,可以从中发射抛射物(每个模型可以有多个)
当前希望修复的奇怪限制:
- TransformationMatrix 很混乱,但尚未开发出更好的解决方案。它们需要一些擅长矩阵的人来做一些工作。