BBSMC Logo
模组整合包光影资源包软件汉化插件数据包地图
登录
模组插件数据包光影资源包整合包软件汉化地图
登录
设置
Live2DMC

Live2DMC

Live2D MC —— 把 Live2D 模型放进 Minecraft(Forge)

优化前置实用工具
004 days ago

Live2DMC

Live2D MC —— 把 Live2D 模型放进 Minecraft(Forge)

0
0
优化
前置
实用工具

    关于附属

    具体方法
简介渲染图更新日志版本百科反馈讨论

Live2D MC · 附属 Mod API 文档

适用:com.chillet.live2dmc v1.0.0(Minecraft 1.20.1 / Forge 47.4.10+,仅客户端) 接口版本:Live2DMcApi.API_VERSION = "1"

这份文档面向其他 mod 的作者:如何读取/控制 Live2D 模型、如何往 Live2D MC 的设置界面里加自己的页签、 如何监听状态变化。全部接口都在 com.chillet.live2dmc.api 包里,不需要接触原生库(JNI)。


目录

  1. 快速开始
  2. Live2DMcApi:模型接口
  3. Live2DMcUiApi:往设置界面加页签
  4. Live2DMcEvents:状态监听
  5. 控件库速查(com.chillet.live2dmc.ui)
  6. 线程、时机与限制
  7. 完整示例:一个小附属 mod
  8. FAQ / 踩坑
  9. 版本与兼容承诺

1. 快速开始

1.1 依赖

把 Live2D MC 的构建产物放进你工程的 libs/,只在编译期依赖(运行时由玩家安装):

dependencies {
    compileOnly files("libs/live2dmc-1.0.0.jar")
}

如果发布时想让安装器提示玩家先装 Live2D MC,在 mods.toml 里加一条软依赖:

[[dependencies.youraddon]]
modId = "live2dmc"
mandatory = false
versionRange = "[1.0.0,)"
ordering = "AFTER"
side = "CLIENT"

1.2 三条硬规则

  1. 只在客户端用。API 类都标了 @OnlyIn(Dist.CLIENT);Live2D MC 本身是 clientSideOnly, 专用服务器上没有它。你的调用代码要么整个类只在客户端加载,要么用 FMLEnvironment.dist == Dist.CLIENT 包住(推荐:@Mod.EventBusSubscriber(value = Dist.CLIENT) 的独立类)。
  2. 渲染方法必须发生在渲染线程(Screen#render、RenderGuiEvent.Post 等); 查询/设置配置类方法建议也在主线程调(内部会直接改模型参数)。
  3. 先判可用性再调:Live2DMcApi.isAvailable() / hasModel()。 玩家没放模型、或原生库没加载时,render* 返回 false,其它方法退化成空操作/空表,不要当成异常。

1.3 最小骨架

package com.example.addon;
import com.chillet.live2dmc.api.Live2DMcApi;
import com.chillet.live2dmc.api.Live2DMcEvents;
import com.chillet.live2dmc.api.Live2DMcUiApi;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
@Mod.EventBusSubscriber(modid = ExampleAddon.MODID, value = Dist.CLIENT,
        bus = Mod.EventBusSubscriber.Bus.MOD)
public final class ExampleClient {
    @SubscribeEvent
    public static void onClientSetup(FMLClientSetupEvent event) {
        if (!Live2DMcApi.API_VERSION.equals("1")) {
            return;                         // 接口大版本不匹配就别注册了
        }
        Live2DMcUiApi.registerTab("example", "示例", builder -> {
            // 见第 3 节
        });
        Live2DMcEvents.register(new Live2DMcEvents.Listener() {
            @Override
            public void onModelChanged(String model) {
                // 玩家换了模型
            }
        });
    }
}

registerTab / register 建议放在 FMLClientSetupEvent(MOD 总线)里: 它们只是往内存列表里加条目,越早越好;页签构建回调在每次切到该页签时执行。


2. Live2DMcApi:模型接口

所有方法都是 public static。下表是完整清单。

2.1 状态

方法 返回 说明
modId() String 本 mod 的 id:"live2dmc"
isAvailable() boolean 原生库 + GL 辅助上下文就绪。没就绪时所有渲染都返回 false
hasModel() boolean 当前有已加载的模型(= currentModel() 非空且可用)
isEnabled() / setEnabled(boolean) boolean 总开关(与设置界面里的「总开关」同一个值)。关掉后 render* 一律返回 false,HUD 也不画
statusLine() String 一行状态文案,如 就绪(282x360) / 不可用:…,可直接显示
hintLine() String 给玩家的首步提示(如"把模型放进 config/live2dmc/live2d")

2.2 模型

方法 说明
models() 已扫描到的模型名列表(模型目录名)
currentModel() 当前模型名(目录名);没有时返回 ""
currentModelLabel() 当前模型显示名
selectModel(String name) 切换到 models() 里的某个模型;名字不存在返回 false。切换会清空当前表情
cycleModel() 切到下一个模型(同样清空表情)
rescanModels() 重新扫描 config/live2dmc/live2d/(玩家刚放进新模型时用)
openModelFolder() 调系统文件管理器打开模型目录

2.3 表情

表情是叠加机制:可以同时勾选多个,参数逐个合并(同名参数后者覆盖)。取消勾选时会把该表情改过的参数 还原成应用前的值(不是粗暴清零),所以取消后立刻恢复原样,不需要重进游戏。

方法 说明
expressions() 当前模型可用的表情名(来自 model3.json 的 Expressions;没有时自动扫目录里的 *.exp3.json)
selectedExpressions() 当前勾选的表情(顺序 = 叠加顺序)
setExpressions(List<String>) 直接设置组合;空表 = 无表情
toggleExpression(String name) 勾选/取消一个
clearExpressions() 清空(并还原参数)
Live2DMcApi.setExpressions(List.of("Happy1", "Shy"));  // 叠加
Live2DMcApi.clearExpressions();                        // 全关

2.4 动作

方法 说明
cycleMotion() 播放下一个动作组(模型没配动作时是空操作)
currentMotion() 当前动作组显示名(没有时返回 "—")

2.5 参数

public record Param(String id, String name, String group, float min, float max) { }

数据来源是模型目录里的 *.cdi3.json;模型没有 cdi3 时退化成一份标准参数表(角度/眼球/呼吸/眨眼等)。

方法 说明
parameters() List<Param>:全部可调参数(含分组与范围)
parameter(String id) 读取覆盖值;没有覆盖时返回 0(不是模型的实时参数值)
setParameter(String id, float value) 写覆盖值:立即作用到模型,盖过跟随鼠标/眨眼/动作,并会持久化到 overrides.json
hasParameterOverride(String id) 是否被覆盖过
resetParameters() 清空全部参数覆盖

⚠ 注意:setParameter 是持久化覆盖,不是"临时推一下"。如果你只是想每帧驱动参数, 又想尊重用户在参数页里手动改的值,可以:

if (!Live2DMcApi.hasParameterOverride("ParamAngleZ")) {
    Live2DMcApi.setParameter("ParamAngleZ", driven);
}

或者用完调 resetParameters()(会一起清掉玩家自己的改动,慎用)。

2.6 部件

public record Part(String id, String name) { }
方法 说明
parts() 部件列表(来自 cdi3)
isPartVisible(String id) / setPartVisible(String id, boolean visible) 查询 / 显示隐藏(持久化)
showAllParts() 全部显示

⚠ 实现方式是"合成表情的 Parts 字段"。只有当模型的 drawable 确实挂在部件下时才看得出效果; 部分导出工具不按部件组织 drawable,此时调用不会有可见变化(不算 bug)。

2.7 位置 / 缩放 / 不透明度

模型位置和 HUD 共用同一份配置,改完会持久化。

方法 说明
offsetX() / offsetY() / setOffset(double x, double y) 模型位置(预览和 HUD 都会偏移)
scale() / setScale(double) 缩放(1.0 = 原始大小)
opacity() / setOpacity(double) 不透明度 0..1

这三个只影响 renderFollowMouse(...) 与 HUD;render(...) 是固定比例的头像模式,不套用它们。

2.8 HUD(桌面挂件)

方法 说明
isHudEnabled() / setHudEnabled(boolean) 开关
hudAnchorX() / hudAnchorY() / setHudAnchor(double x, double y) 锚点,0..1 的整屏比例(默认 0.84 / 0.98)
hudScale() / setHudScale(double) HUD 独立缩放
HUD 会画在所有界面之上(物品栏、聊天、设置界面都能看到),打开 Live2D MC 自己的设置界面时自动隐藏。

2.9 渲染

// 居中、不看鼠标:画进任意 GUI 矩形
boolean render(GuiGraphics graphics, int x, int y, int w, int h);
// 同上,并按鼠标位置转头
boolean renderFollowMouse(GuiGraphics graphics, int x, int y, int w, int h,
                          float mouseX, float mouseY);
  • 坐标是 GUI 逻辑像素,(x, y) 是矩形左上角,w/h 是可用区域;模型按自身比例居中放进去。
  • render(...) 用固定的"装进盒子"缩放(0.92,忽略玩家设置的缩放/偏移),适合当头像/预览; renderFollowMouse(...) 会套用玩家在模型页里设置的缩放与偏移,并按鼠标转头,适合当桌面宠物。
  • 直接画进当前 GuiGraphics(内部会立刻 flush 自己那批几何),所以在 GUI 里任何位置都能用: 自己 Screen 的 render、HUD 叠加、物品栏上方等。
  • 返回 true 表示真的画出来了;false 表示没模型 / 原生库不可用 / 总开关关闭,请画自己的占位内容。
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTick) {
    this.renderBackground(graphics);
    boolean drawn = Live2DMcApi.renderFollowMouse(graphics, 20, 30, 180, 240, mouseX, mouseY);
    if (!drawn) {
        graphics.drawString(this.font, "(没有模型)", 20, 30, 0xFF888888);
    }
    super.render(graphics, mouseX, mouseY, partialTick);
}

2.10 主题 / 界面 / 保存

方法 说明
isLightTheme() / setLightTheme(boolean) 读 / 切深色浅色主题(会写配置;同时影响控件库配色)
openConsole() 打开 Live2D MC 的设置界面(当前没有别的界面时才会打开)
save() 立即落盘配置与参数/部件覆盖(正常关界面时会自动保存)
resetDefaults() 恢复全部出厂设置(缩放/HUD/表情/参数/部件等)

3. Live2DMcUiApi:往设置界面加页签

3.1 注册

Live2DMcUiApi.registerTab(
        "youraddon",                       // 唯一 id(页脚会显示,方便排查)
        "拓展",                             // 页签标题(自己本地化;建议 ≤4 个汉字)
        builder -> { /* 往页面里加控件 */ }
);
方法 说明
registerTab(String id, String title, Consumer<TabBuilder> build) 注册页签。id 为空或 build 为 null 会被忽略;同 id 只保留第一个(重复注册会记一条 warn)
tabs() 已注册页签列表(TabEntry{id, title, build()})
openConsole() 打开设置界面
notifyConsoleOpened() / notifyConsoleClosed() 由设置界面自动调用,一般不要自己调
页签标题会显示在内置 5 个页签(模型 / HUD / 参数 / 部件 / 表情)右边:太长会被按段宽省略,
所以标题尽量短;页面内容区仍然是完整宽度。

3.2 坐标与构建时机

TabBuilder 给出的坐标是绝对 GUI 坐标(不是相对坐标):

方法 说明
bodyX() / bodyY() 内容区左上角
bodyW() / bodyH() 内容区宽 / 高
add(UiWidget) 往屏幕加一个控件(按调用顺序绘制,后加的在上面);null 会被忽略
Live2DMcUiApi.registerTab("youraddon", "拓展", tab -> {
    int x = tab.bodyX(), y = tab.bodyY(), w = tab.bodyW();
    tab.add(new UiToggle(() -> "启用功能", MyConfig::enabled, MyConfig::setEnabled)
            .bounds(x, y, w / 2 - 2, UiTheme.CONTROL_HEIGHT));
    tab.add(new UiSlider(() -> "强度",
            MyConfig::strength, MyConfig::setStrength, 0.0D, 1.0D, 0.01D)
            .bounds(x, y + 24, w - 12, 18));
});

页面生命周期

  • 构建回调在每次切到该页签(以及重新打开设置界面)时执行,用来读取最新状态。
  • 控件不跨次保留:状态请存在你自己的字段/配置里,不要在控件对象上存;每次构建重新 new 即可。
  • 构建抛异常会被 catch 并记一条 warn,你的页签会变成空白页,不会崩游戏。
  • 不要自己往屏幕上重复画同一批控件;控件由界面统一渲染、派发鼠标和键盘事件。

3.3 可用控件

全部在 com.chillet.live2dmc.ui,都是 public(详见第 5 节): UiButton、UiToggle、UiSlider、UiCheckRow、UiTabs、UiTextField、UiScrollArea、 UiModelPreview、UiHudMap、UiDraw、UiTheme、UiText。 所有控件都用 .bounds(x, y, w, h) 定位,返回自身,方便链式。

3.4 滚动列表

UiScrollArea 里的子控件用内容坐标((0, 0) = 滚动区域左上角),滚动/裁剪由它负责:

UiScrollArea area = new UiScrollArea().tag("youraddon").bounds(x, y, w, h);
int rowY = 2;
for (String entry : myEntries) {
    area.add(new UiButton(() -> entry, () -> pick(entry))
            .bounds(2, rowY, w - 12, 18));
    rowY += 20;
}
tab.add(area);

滚轮只在列表区域响应;area.add 可以放任意控件(一排开关、一行行按钮都行),坐标从内容原点算起。

4. Live2DMcEvents:状态监听

public interface Listener {
    default void onModelChanged(String model) { }
    default void onExpressionsChanged(List<String> selected) { }
    default void onConfigSaved() { }
    default void onConsoleOpened() { }
    default void onConsoleClosed() { }
}
方法 触发时机
register(Listener) / unregister(Listener) 监听器列表(重复注册会重复回调,请自己保证只注册一次)
onModelChanged(String model) 换模型成功(selectModel / cycleModel / 自动切模型)
onExpressionsChanged(List<String>) 表情组合变化(setExpressions / toggle / clear)
onConfigSaved() 配置写盘(关设置界面、手动 save())
onConsoleOpened() / onConsoleClosed() 设置界面打开 / 关闭
Live2DMcEvents.register(new Live2DMcEvents.Listener() {
    @Override
    public void onExpressionsChanged(List<String> selected) {
        LOGGER.info("当前表情:{}", selected);
    }
    @Override
    public void onConsoleClosed() {
        MyConfig.save();          // 玩家调完参数 → 保存自己的配置
    }
});
  • 监听器抛出的异常会被吞掉并记 warn,不会连累 Live2D MC。
  • 事件都在客户端主线程触发(register 本身可以在初始化线程调用)。
  • 不想再收事件时 unregister(那个实例)。

5. 控件库速查(com.chillet.live2dmc.ui)

所有控件都继承 UiWidget,公共字段/方法:

public int x, y, w, h;
public boolean visible = true;   // false 时不渲染、不响应
public boolean enabled = true;   // false 时点击无效
<T extends UiWidget> T bounds(int x, int y, int w, int h);
boolean contains(double mx, double my);
String tooltip();                // 悬停提示(默认 null)

UiButton

new UiButton(Supplier<String> label, Runnable action);
new UiButton(Supplier<String> label, Runnable action, Style style);   // PRIMARY / WARN / GHOST

UiToggle

new UiToggle(Supplier<String> label,
             Supplier<Boolean> getter,
             Consumer<Boolean> setter);

UiSlider

new UiSlider(Supplier<String> label, DoubleSupplier getter, DoubleConsumer setter,
             double min, double max, double step);            // 数值格式默认 "%.2f"
new UiSlider(..., double min, double max, double step, String format);

拖动时按 step 量化;标签右边实时显示数值。

UiCheckRow

new UiCheckRow(Supplier<String> label, BooleanSupplier selected, Runnable onSelect);

UiTabs

new UiTabs(String[] labels, IntSupplier index, IntConsumer onChange);

UiTextField

new UiTextField(String value, int maxLength, String label, String placeholder,
                boolean masked, Consumer<String> onChange);
  • 点一下聚焦,键盘输入(含中文输入法上屏)由界面转发;ESC 第一次只取消聚焦。
  • onChange 每次改动都会回调。
  • ⚠ 聚焦是由界面按 widget instanceof UiTextField 判定的:输入框必须直接 add 到页面上, 放进 UiScrollArea 里会收不到键盘。

UiScrollArea

UiScrollArea area = new UiScrollArea().tag("youraddon");
area.add(child);          // 子控件坐标 = 内容坐标
area.clear();
area.contentHeight();
area.scrollBy(int dy);
area.canScroll();

UiDraw(静态绘制工具)

UiDraw.rect(g, x, y, w, h, argb);
UiDraw.rounded(g, x, y, w, h, radius, argb);
UiDraw.roundedGradient(g, x, y, w, h, radius, topArgb, bottomArgb);
UiDraw.card(g, x, y, w, h, radius, borderArgb, topArgb, bottomArgb);
UiDraw.shadow(g, x, y, w, h, radius);
UiDraw.inset(g, x, y, w, h, radius);
UiDraw.circle(g, cx, cy, radius, argb);
UiDraw.line(g, x0, y0, x1, y1, thickness, argb);
UiDraw.hairline(g, x, y, w, h, argb);
UiDraw.text(g, font, s, x, y, argb);
UiDraw.textCentered(g, font, s, centerX, y, argb);
UiDraw.textRight(g, font, s, rightX, y, argb);
UiDraw.ellipsize(font, s, maxWidth);
UiDraw.scissorOn(g, x, y, w, h); / UiDraw.scissorOff(g);
UiDraw.lerpColor(a, b, t); / UiDraw.withAlpha(argb, alpha);

UiTheme

主题色和尺寸都是 public static(UiTheme.setLight(true/false) 切换深/浅色):

UiTheme.ACCENT, UiTheme.WARN, UiTheme.TEXT, UiTheme.TEXT_DIM, UiTheme.TEXT_FAINT,
UiTheme.CONTROL, UiTheme.CONTROL_BORDER, UiTheme.CARD_TOP, UiTheme.INSET,
UiTheme.TAB_TRACK, UiTheme.SLIDER_FILL, ...
UiTheme.PAD            // 10
UiTheme.ROW_GAP        // 4
UiTheme.CONTROL_HEIGHT // 18
UiTheme.RADIUS_CARD    // 10
UiTheme.RADIUS_CONTROL // 6

UiText

UiText.tr("youraddon.key", args);   // 取本地化字符串(I18n)
UiText.ct("youraddon.key", args);   // 取 Component

6. 线程、时机与限制

事项 约定
渲染 只能在渲染线程(Screen#render / GUI 叠加事件里)调用 render*
查询/设置 客户端主线程调用;不要在网络线程/异步线程里调
无模型时 render* 返回 false,models()/expressions()/parameters() 为空表,设置类是空操作
平台 原生库只带 Windows x64;其他平台 isAvailable() == false
主 mod 关闭 Live2D MC 是 clientSideOnly mod:玩家没装时你的 mod 不应报错(软依赖 + isAvailable() 判断)
不要反射/直连内部类 只依赖 com.chillet.live2dmc.api 三个类与 ui 控件库;其余包不保证兼容
模型本身 不随 mod 分发;玩家自备,版权自负

7. 完整示例:一个小附属 mod

需求:给 Live2D MC 加一个「跟随血量」页签;玩家换模型时把状态同步到自己的配置;收到含"开心"的聊天就笑。

package com.example.addon;
import com.chillet.live2dmc.api.*;
import com.chillet.live2dmc.ui.*;
import net.minecraft.client.Minecraft;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import java.util.List;
@Mod.EventBusSubscriber(modid = "youraddon", value = Dist.CLIENT)
public final class ExampleAddon {
    private static boolean moodEnabled = true;
    @SubscribeEvent
    public static void onClientSetup(FMLClientSetupEvent event) {
        // 只注册一次:MOD 总线里的 FMLClientSetupEvent
        Live2DMcUiApi.registerTab("youraddon_mood", "心情", ExampleAddon::buildMoodTab);
        Live2DMcEvents.register(new Live2DMcEvents.Listener() {
            @Override
            public void onModelChanged(String model) {
                moodEnabled = true;   // 换模型时重置自己状态
            }
        });
    }
    private static void buildMoodTab(Live2DMcUiApi.TabBuilder tab) {
        int x = tab.bodyX(), y = tab.bodyY(), w = tab.bodyW(), h = tab.bodyH();
        tab.add(new UiToggle(() -> "跟随血量",
                () -> moodEnabled,
                v -> moodEnabled = v)
                .bounds(x, y, w / 2 - 2, UiTheme.CONTROL_HEIGHT));
        // 表情快捷按钮:直接调主 mod 的 API
        tab.add(new UiButton(() -> "笑一个", () -> {
            List<String> names = Live2DMcApi.expressions();
            if (names.contains("Happy1")) {
                Live2DMcApi.toggleExpression("Happy1");
            }
        }, UiButton.Style.PRIMARY)
                .bounds(x + w / 2 + 2, y, w / 2 - 2, UiTheme.CONTROL_HEIGHT));
        // 参数滑条:读写主 mod 的覆盖值
        tab.add(new UiSlider(() -> "被驱动的参数(ParamAngleZ)",
                () -> Live2DMcApi.parameter("ParamAngleZ"),
                v -> Live2DMcApi.setParameter("ParamAngleZ", (float) v),
                -30.0D, 30.0D, 0.5D)
                .bounds(x, y + 26, w, 18));
        // 底部说明
        tab.add(new UiButton(() -> "重置全部参数", Live2DMcApi::resetParameters,
                UiButton.Style.WARN)
                .bounds(x, y + h - 22, w / 3, UiTheme.CONTROL_HEIGHT));
    }
    @SubscribeEvent
    public static void onClientTick(TickEvent.ClientTickEvent event) {
        if (event.phase != TickEvent.Phase.END) {
            return;
        }
        if (!moodEnabled || !Live2DMcApi.hasModel()) {
            return;
        }
        var player = Minecraft.getInstance().player;
        if (player == null) {
            return;
        }
        // 玩家自己改过就不抢
        if (!Live2DMcApi.hasParameterOverride("ParamAngleZ")) {
            Live2DMcApi.setParameter("ParamAngleZ", (1.0F - player.getHealth() / 20.0F) * 25.0F);
        }
    }
}

8. FAQ / 踩坑

Q:我在自己界面里画模型,结果是一片黑/花了? render* 只能在渲染线程的 GUI 绘制阶段调用(Screen#render),并且要传当前的 GuiGraphics。 不要放到 ClientTickEvent 或网络回调里。 Q:页签没出现在设置界面里?

  1. 注册时机太晚 —— 必须在界面打开前注册(推荐 FMLClientSetupEvent);
  2. id 和别的附属 mod 撞了(日志有 页签 id 已存在 的 warn);
  3. 你的 mod 没加载成功/版本低于 1.0.0。 Q:页签里的控件点不动? 坐标要用绝对屏幕坐标(bodyX()/bodyY() 起算),控件不能超出内容区,也不要被后加的控件完全盖住; visible=false 或 enabled=false 的控件不响应。 Q:UiTextField 打不了字? 它必须直接 tab.add(...) 到页面上(不能塞进 UiScrollArea),且要先点一下让它聚焦。 Q:Live2DMcApi.parameter("ParamAngleX") 返回 0,但模型明明在动? 它读的是覆盖值,不是模型的实时值;没有覆盖就返回 0。想知道模型有哪些参数、范围多少,用 parameters()。 Q:setExpressions 没反应? 先确认模型名:expressions() 里有没有你传的名字(大小写、空格要一致)。模型没有表情时列表为空。 Q:setPartVisible 没反应? 部件开关依赖模型把 drawable 挂在部件下;不少导出工具不这样做,此时没有可见变化。 Q:openConsole() 没打开界面? 当前已经有别的界面(背包、聊天等)时它不会强制切换;让玩家先关掉当前界面,或用按键绑定。 Q:我的 mod 在专用服务器上崩了(NoClassDefFoundError)? Live2D MC 是纯客户端 mod。请把调用 API 的类放到 @Mod.EventBusSubscriber(value = Dist.CLIENT) 的 独立类里,或先用 FMLEnvironment.dist == Dist.CLIENT 判断。

9. 版本与兼容承诺

  • 当前 API_VERSION = "1"。v1 内只增不改:新增方法/控件不会破坏已有调用。
  • 发生不兼容变更(删方法、改语义)时会提升 API_VERSION 并在这里注明迁移方式。
  • 附属 mod 侧建议:
if (!"1".equals(Live2DMcApi.API_VERSION)) {
    LOGGER.warn("Live2D MC API 版本不匹配:{}", Live2DMcApi.API_VERSION);
    return;
}
  • 只有 com.chillet.live2dmc.api.* 与 com.chillet.live2dmc.ui.* 属于公开接口; 其他包(live2d、render、client)是内部实现,随时可能调整。
BBSMC Logo

中国最活跃的 Minecraft 中文资源社区

QQ 群:1078515449

资源

模组整合包光影资源包地图

社区

汉化软件插件数据包

帮助

服务条款隐私政策社区规则开源代码
设置

"Minecraft"以及"我的世界"为美国微软公司的商标,本站与微软公司没有从属关系。 本站与 Modrinth 无从属关系,网站遵循 LGPL 协议开源。

© 2019-2026 青岛柒兮网络科技有限公司 | 鲁B2-20210590 | 鲁ICP备2021009459号-12 | 公安备案 鲁公网安备37021002001586号