Theseus 模组文档
API 参考 / spi 包:音符与判定 SPI

NoteData


想先跑起来?

这一页是签名与行为参考。音符实例基类,注意「所有权边界」。直接做一遍:教程 · 添加新音符类型。

运行时音符基类(api 侧)。自定义类型在 deserialize / onCreateRuntime 中构造并维护它;游玩期宿主把它(或内置类型的只读适配器)交给判定与渲染回调。它不依赖引擎内部模型,模组只依赖 mod-api 即可实现自定义音符。

写语义按所有权分两类(契约,消除"写了却静默无效"):

方法速览

方法用途
time() / setTime(long)音符时间(毫秒)
lane() / setLane(int)所在轨道(0-based)
typeKey()音符类型 key(宿主填的内核类型字符串)
endTime() / setEndTime(Long)长音符结束时间(非长音符为 null)
isJudged() / setJudged(boolean)判定状态(自定义类型自管)
extensionData() / setExtensionData(Object)运行时扩展数据(不参与序列化)

time()

签名:

java
public abstract long time();

行为:音符时间(毫秒,判定线时刻)。自定义类型即你在解析期写入值;内置适配器实时读内核音符(含运行期被 setTime 改写后的值)。

示例:

java
long t = note.time();

lane()

签名:

java
public abstract int lane();

行为:音符所在轨道(0-based)。与 time() 同源:自定义类型读自有字段,内置适配器读内核音符。

示例:

java
if (note.lane() == lane) { /* 同轨 */ }

typeKey()

签名:

java
public abstract String typeKey();

行为:音符类型 key,与 NoteTypeDefinition.serializationKey() 对应,由宿主填充(内置适配器返回内核音符的原始 type 字符串)。自定义实现通常直接返回 serializationKey()。

示例:

java
@Override
public String typeKey() {
    return "stardust";
}

endTime()

签名:

java
public abstract Long endTime();

行为:长音符结束时间(毫秒);非长音符返回 null。注意长按语义的类型必须提供非空 endTime,否则宿主没有终点判定路径。

示例:

java
Long end = note.endTime();

isJudged()

签名:

java
public abstract boolean isJudged();

行为:音符是否已被判定。宿主管线不读写自定义类型实例的这个字段(判定状态在宿主内部队列里);内置适配器恒返回 false。若你需要该状态,请在自有子类中维护并在 onJudgeTick / onJudged 里自行更新。

示例:

java
@Override
public boolean isJudged() {
    return judged;
}

extensionData()

签名:

java
public abstract Object extensionData();

行为:运行时扩展数据的读取端。自定义类型的值会在 render 中经 NoteRenderContext.extensionData()、在判定回调中经 NoteView.extensionData() 原样透传(同一实例);内置类型为 null。不参与序列化。

示例:

java
Object state = note.extensionData();

setTime(long time)

签名:

java
public abstract void setTime(long time);

行为:设置音符时间(毫秒)。约定在解析期(deserialize / onCreateRuntime)调用。自定义类型的运行期改写不进入宿主管线;内置适配器会转发到内核音符并真实生效。

示例:

java
note.setTime(json.get("time").getAsLong());

setLane(int lane)

签名:

java
public abstract void setLane(int lane);

行为:设置所在轨道(0-based),语义同 setTime:解析期写入;内置适配器转发内核音符并生效。

示例:

java
note.setLane(json.get("lane").getAsInt());

setEndTime(Long endTime)

签名:

java
public abstract void setEndTime(Long endTime);

行为:设置长音符结束时间;非长音符传 null。内置适配器转发内核音符并生效。

示例:

java
note.setEndTime(json.has("endTime") ? json.get("endTime").getAsLong() : null);

setJudged(boolean judged)

签名:

java
public abstract void setJudged(boolean judged);

行为:设置判定状态。仅对自定义类型有意义(宿主不消费);内置适配器为无操作,避免模组绕过判定引擎改分。

示例:

java
note.setJudged(true);

setExtensionData(Object data)

签名:

java
public abstract void setExtensionData(Object data);

行为:挂载运行时扩展数据(任意对象,不参与序列化)。自定义类型在解析期写入,判定/渲染期经只读透传取回;内置适配器为无操作(数据存不下来)。

示例:

java
note.setExtensionData(new AimState(angleRad));

完整签名

java
public abstract class NoteData {

    public abstract long time();

    public abstract int lane();

    public abstract String typeKey();

    public abstract Long endTime();

    public abstract boolean isJudged();

    public abstract Object extensionData();

    public abstract void setTime(long time);

    public abstract void setLane(int lane);

    public abstract void setEndTime(Long endTime);

    public abstract void setJudged(boolean judged);

    public abstract void setExtensionData(Object data);
}

线程:源码未声明额外线程约束;实例在解析期写入,游玩期由更新/渲染线程读取。

生命周期阶段:解析期由模组构造并写入;游玩期(判定与渲染回调)读取。

稳定性:2.0 起冻结:2.x 内只增不破(禁止删签名/改签名/改语义)。