Theseus 模组文档
API 参考 / judge 包:判定管线

SceneEntity 与 EntityPose


统一世界二期的模组可见层级 API(查询面)。宿主把实体层级(世界 → 轨道区 → 轨道i → …)以查询面对模组开放:每个实体即纯变换节点(组),没有渲染内容;宿主不做「按树渲染模组回调」,模组经只读查询取世界矩阵 / 继承量后自行变换自绘内容。

方法速览

方法用途
offsetX() / setOffsetX(double)读/写本 tick 水平偏移(实体本地坐标,像素)
offsetY() / setOffsetY(double)读/写本 tick 垂直偏移(实体本地坐标,像素)
translate(double, double)原地叠加标量平移,返回 this
rotateZ(double, double, double)追加绕 Z 轴旋转 op
rotateX(double, double, double)追加绕 X 轴旋转 op
rotateY(double, double, double)追加绕 Y 轴旋转 op
translate3D(double, double, double)追加三轴平移 op
scale(double, double, double, double)追加以本地圆心缩放的 op

完整签名

java
public interface SceneEntity {
}

public interface EntityPose {

    double offsetX();

    void setOffsetX(double x);

    double offsetY();

    void setOffsetY(double y);

    EntityPose translate(double dx, double dy);

    EntityPose rotateZ(double degrees, double pivotX, double pivotY);

    EntityPose rotateX(double degrees, double pivotY, double pivotZ);

    EntityPose rotateY(double degrees, double pivotX, double pivotZ);

    EntityPose translate3D(double dx, double dy, double dz);

    EntityPose scale(double sx, double sy, double pivotX, double pivotY);
}

合成口径:标量 offsetX/offsetY 的平移先施加(标量之间是可交换加法),再按 op 列表顺序逐项右乘;所有圆心/轴点一律写实体本地坐标,不是世界坐标,也不是「执行后」坐标。落盘后的本地变换 = translate(offsetX, offsetY) 后按列表顺序逐项右乘 op;世界矩阵 = 世界(父) · 本地(实体)。

所有权:实体归创建方模组独占。改他人实体的挂载 / 销毁 / 可见性 / alpha 会被宿主拒绝并输出 [ModConflict] 限频告警(不抛异常);挂到宿主实体(轨道区 / 轨道)任何模组均可。entityPose 的接口契约只承诺对无效 / 已销毁句柄返回 null,所有权纪律依赖「句柄不跨模组传递」。

窗口:entityPose 仅在 tick 分发期间合法,窗口外返回 null 并限频告警。mountTo* 与 destroyEntity 属于装配类操作,仅在非 tick 上下文合法(如 GameStartEvent),tick 分发期间调用被拒绝。查询 entityWorldMatrix / entityVisible / entityAlpha 任意时机合法。

生命周期:随游玩场景存续;游玩结束时宿主自动级联销毁全部模组实体,句柄失效(查询返回 null / false / 0 并限频告警)。显式 destroyEntity 同样级联子树。

确定性:禁随机、禁墙钟(时间取 GameplayTickEvent#musicTimeMs())、禁跨帧持有 EntityPose 引用;与 TrackPoseAdjuster 同一口径。纯视觉,判定引擎零消费。

offsetX()

签名:

java
double offsetX();

行为:本 tick 的水平偏移(实体本地坐标,像素)。每 tick 开始时复位为 0;未写即恒等。

示例:

java
double dx = pose.offsetX();

setOffsetX(double)

签名:

java
void setOffsetX(double x);

行为:写入本 tick 的水平偏移(实体本地坐标,像素),绝对覆盖当前值。

示例:

java
pose.setOffsetX(40.0);

offsetY()

签名:

java
double offsetY();

行为:本 tick 的垂直偏移(实体本地坐标,像素)。每 tick 开始时复位为 0。

示例:

java
double dy = pose.offsetY();

setOffsetY(double)

签名:

java
void setOffsetY(double y);

行为:写入本 tick 的垂直偏移(实体本地坐标,像素),绝对覆盖当前值。

示例:

java
pose.setOffsetY(-18.0);

translate(double, double)

签名:

java
EntityPose translate(double dx, double dy);

行为:在当前标量偏移上叠加 (dx, dy)(实体本地坐标,像素),返回 this 便于链式书写。纯视觉。

示例:

java
pose.translate(40.0, 25.0);

rotateZ(double, double, double)

签名:

java
EntityPose rotateZ(double degrees, double pivotX, double pivotY);

行为:追加「绕平行 Z 轴旋转」op(画布平面内,度;正值 = 屏幕顺时针)。pivotX/pivotY 为实体本地坐标。op 保序,返回 this。

示例:

java
pose.rotateZ(12.0, 0.0, 0.0);

rotateX(double, double, double)

签名:

java
EntityPose rotateX(double degrees, double pivotY, double pivotZ);

行为:追加「绕平行 X 轴旋转」op(度,轴过本地 (任意 x, pivotY, pivotZ))。op 保序,返回 this。

示例:

java
pose.rotateX(8.0, 0.0, 0.0);

rotateY(double, double, double)

签名:

java
EntityPose rotateY(double degrees, double pivotX, double pivotZ);

行为:追加「绕平行 Y 轴旋转」op(度,轴过本地 (pivotX, 任意 y, pivotZ))。op 保序,返回 this。

示例:

java
pose.rotateY(-6.0, 0.0, 0.0);

translate3D(double, double, double)

签名:

java
EntityPose translate3D(double dx, double dy, double dz);

行为:追加三轴平移 op(像素,+z 向屏幕内;在标量 translate 之外、进 op 列表并保序)。返回 this。

示例:

java
pose.translate3D(0.0, 0.0, 60.0);

scale(double, double, double, double)

签名:

java
EntityPose scale(double sx, double sy, double pivotX, double pivotY);

行为:追加「以本地圆心缩放」op,等价于 translate(p) · scale(sx, sy) · translate(-p);pivotX/pivotY 为实体本地坐标。op 保序,返回 this。

示例:

java
pose.scale(1.1, 1.1, 0.0, 0.0);

完整消费示例(装配在 GameStartEvent,每帧位姿在 GameplayTickEvent.Post,查询在渲染回调):

java
// onInit 内保存 ModContext,并订阅 GameStartEvent / GameplayTickEvent.Post
private GameStateAccess gameState() {
    return modCtx == null ? null : modCtx.capabilities().get(GameStateAccess.class);
}

// GameStartEvent:非 tick 上下文,创建 + 挂载
GameStateAccess gs = gameState();
if (gs == null) {
    return;   // 非游玩场景
}
SceneEntity entity = gs.createEntity("my_entity");
gs.mountToTrack(entity, 2);

// GameplayTickEvent.Post:tick 窗口,每帧重写位姿
EntityPose pose = gs.entityPose(entity);
if (pose != null) {
    double t = evt.musicTimeMs() / 1000.0;
    pose.translate(40.0 * Math.sin(t), 0.0)
        .rotateZ(15.0, 0.0, 0.0);
}

// 渲染回调:读取本 tick 落盘后的世界矩阵(16 元素,列主序,防御性拷贝)
double[] world = gs.entityWorldMatrix(entity);

线程:渲染线程(tick 分发、实体查询与位姿写入均在其上)。

稳定性:2026-10-16 新增:2.x 内只增不破。