GameTestInfo.java

net.minecraft.gametest.framework.GameTestInfo

信息

  • 全限定名:net.minecraft.gametest.framework.GameTestInfo
  • 类型:public class
  • 包:net.minecraft.gametest.framework
  • 源码路径:src/main/java/net/minecraft/gametest/framework/GameTestInfo.java
  • 起始行号:L31
  • 职责:

    TODO

字段/常量

  • test

    • 类型: Holder.Reference<GameTestInstance>
    • 修饰符: private final
    • 源码定位: L32
    • 说明:

      TODO

  • testBlockPos

    • 类型: BlockPos
    • 修饰符: private
    • 源码定位: L33
    • 说明:

      TODO

  • level

    • 类型: ServerLevel
    • 修饰符: private final
    • 源码定位: L34
    • 说明:

      TODO

  • listeners

    • 类型: Collection<GameTestListener>
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

  • timeoutTicks

    • 类型: int
    • 修饰符: private final
    • 源码定位: L36
    • 说明:

      TODO

  • sequences

    • 类型: Collection<GameTestSequence>
    • 修饰符: private final
    • 源码定位: L37
    • 说明:

      TODO

  • runAtTickTimeMap

    • 类型: Object2LongMap<Runnable>
    • 修饰符: private final
    • 源码定位: L38
    • 说明:

      TODO

  • placedStructure

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L39
    • 说明:

      TODO

  • chunksLoaded

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L40
    • 说明:

      TODO

  • tickCount

    • 类型: int
    • 修饰符: private
    • 源码定位: L41
    • 说明:

      TODO

  • started

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L42
    • 说明:

      TODO

  • retryOptions

    • 类型: RetryOptions
    • 修饰符: private final
    • 源码定位: L43
    • 说明:

      TODO

  • timer

    • 类型: Stopwatch
    • 修饰符: private final
    • 源码定位: L44
    • 说明:

      TODO

  • done

    • 类型: boolean
    • 修饰符: private
    • 源码定位: L45
    • 说明:

      TODO

  • extraRotation

    • 类型: Rotation
    • 修饰符: private final
    • 源码定位: L46
    • 说明:

      TODO

  • error

    • 类型: GameTestException
    • 修饰符: private
    • 源码定位: L47
    • 说明:

      TODO

  • testInstanceBlockEntity

    • 类型: TestInstanceBlockEntity
    • 修饰符: private
    • 源码定位: L48
    • 说明:

      TODO

内部类/嵌套类型

构造器

public GameTestInfo(Holder.Reference<GameTestInstance> test, Rotation extraRotation, ServerLevel level, RetryOptions retryOptions) @ L50

  • 构造器名:GameTestInfo
  • 源码定位:L50
  • 修饰符:public

参数:

  • test: Holder.Reference
  • extraRotation: Rotation
  • level: ServerLevel
  • retryOptions: RetryOptions

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void setTestBlockPos(BlockPos testBlockPos) @ L58

  • 方法名:setTestBlockPos
  • 源码定位:L58
  • 返回类型:void
  • 修饰符:public

参数:

  • testBlockPos: BlockPos

说明:

TODO

public GameTestInfo startExecution(int tickDelay) @ L62

  • 方法名:startExecution
  • 源码定位:L62
  • 返回类型:GameTestInfo
  • 修饰符:public

参数:

  • tickDelay: int

说明:

TODO

public void placeStructure() @ L67

  • 方法名:placeStructure
  • 源码定位:L67
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void tick(GameTestRunner runner) @ L83

  • 方法名:tick
  • 源码定位:L83
  • 返回类型:void
  • 修饰符:public

参数:

  • runner: GameTestRunner

说明:

TODO

private void tickInternal() @ L115

  • 方法名:tickInternal
  • 源码定位:L115
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private void startTest() @ L156

  • 方法名:startTest
  • 源码定位:L156
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public void setRunAtTickTime(long time, Runnable assertAtTickTime) @ L172

  • 方法名:setRunAtTickTime
  • 源码定位:L172
  • 返回类型:void
  • 修饰符:public

参数:

  • time: long
  • assertAtTickTime: Runnable

说明:

TODO

public Identifier id() @ L176

  • 方法名:id
  • 源码定位:L176
  • 返回类型:Identifier
  • 修饰符:public

参数:

说明:

TODO

public BlockPos getTestBlockPos() @ L180

  • 方法名:getTestBlockPos
  • 源码定位:L180
  • 返回类型:BlockPos
  • 修饰符:public

参数:

说明:

TODO

public BlockPos getTestOrigin() @ L184

  • 方法名:getTestOrigin
  • 源码定位:L184
  • 返回类型:BlockPos
  • 修饰符:public

参数:

说明:

TODO

public AABB getStructureBounds() @ L188

  • 方法名:getStructureBounds
  • 源码定位:L188
  • 返回类型:AABB
  • 修饰符:public

参数:

说明:

TODO

public TestInstanceBlockEntity getTestInstanceBlockEntity() @ L193

  • 方法名:getTestInstanceBlockEntity
  • 源码定位:L193
  • 返回类型:TestInstanceBlockEntity
  • 修饰符:public

参数:

说明:

TODO

public ServerLevel getLevel() @ L211

  • 方法名:getLevel
  • 源码定位:L211
  • 返回类型:ServerLevel
  • 修饰符:public

参数:

说明:

TODO

public boolean hasSucceeded() @ L215

  • 方法名:hasSucceeded
  • 源码定位:L215
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean hasFailed() @ L219

  • 方法名:hasFailed
  • 源码定位:L219
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean hasStarted() @ L223

  • 方法名:hasStarted
  • 源码定位:L223
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean isDone() @ L227

  • 方法名:isDone
  • 源码定位:L227
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public long getRunTime() @ L231

  • 方法名:getRunTime
  • 源码定位:L231
  • 返回类型:long
  • 修饰符:public

参数:

说明:

TODO

private void finish() @ L235

  • 方法名:finish
  • 源码定位:L235
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public void succeed() @ L244

  • 方法名:succeed
  • 源码定位:L244
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public void fail(Component message) @ L253

  • 方法名:fail
  • 源码定位:L253
  • 返回类型:void
  • 修饰符:public

参数:

  • message: Component

说明:

TODO

public void fail(GameTestException error) @ L257

  • 方法名:fail
  • 源码定位:L257
  • 返回类型:void
  • 修饰符:public

参数:

  • error: GameTestException

说明:

TODO

public GameTestException getError() @ L261

  • 方法名:getError
  • 源码定位:L261
  • 返回类型:GameTestException
  • 修饰符:public

参数:

说明:

TODO

public String toString() @ L265

  • 方法名:toString
  • 源码定位:L265
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

public void addListener(GameTestListener listener) @ L270

  • 方法名:addListener
  • 源码定位:L270
  • 返回类型:void
  • 修饰符:public

参数:

  • listener: GameTestListener

说明:

TODO

public GameTestInfo prepareTestStructure() @ L274

  • 方法名:prepareTestStructure
  • 源码定位:L274
  • 返回类型:GameTestInfo
  • 修饰符:public

参数:

说明:

TODO

private TestInstanceBlockEntity createTestInstanceBlock(BlockPos testPos, Rotation rotation, ServerLevel level) @ L285

  • 方法名:createTestInstanceBlock
  • 源码定位:L285
  • 返回类型:TestInstanceBlockEntity
  • 修饰符:private

参数:

  • testPos: BlockPos
  • rotation: Rotation
  • level: ServerLevel

说明:

TODO

int getTick() @ L299

  • 方法名:getTick
  • 源码定位:L299
  • 返回类型:int
  • 修饰符:package-private

参数:

说明:

TODO

GameTestSequence createSequence() @ L303

  • 方法名:createSequence
  • 源码定位:L303
  • 返回类型:GameTestSequence
  • 修饰符:package-private

参数:

说明:

TODO

public boolean isRequired() @ L309

  • 方法名:isRequired
  • 源码定位:L309
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public boolean isOptional() @ L313

  • 方法名:isOptional
  • 源码定位:L313
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public Identifier getStructure() @ L317

  • 方法名:getStructure
  • 源码定位:L317
  • 返回类型:Identifier
  • 修饰符:public

参数:

说明:

TODO

public Rotation getRotation() @ L321

  • 方法名:getRotation
  • 源码定位:L321
  • 返回类型:Rotation
  • 修饰符:public

参数:

说明:

TODO

public GameTestInstance getTest() @ L325

  • 方法名:getTest
  • 源码定位:L325
  • 返回类型:GameTestInstance
  • 修饰符:public

参数:

说明:

TODO

public Holder.Reference<GameTestInstance> getTestHolder() @ L329

  • 方法名:getTestHolder
  • 源码定位:L329
  • 返回类型:Holder.Reference
  • 修饰符:public

参数:

说明:

TODO

public int getTimeoutTicks() @ L333

  • 方法名:getTimeoutTicks
  • 源码定位:L333
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public boolean isFlaky() @ L337

  • 方法名:isFlaky
  • 源码定位:L337
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

public int maxAttempts() @ L341

  • 方法名:maxAttempts
  • 源码定位:L341
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public int requiredSuccesses() @ L345

  • 方法名:requiredSuccesses
  • 源码定位:L345
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public RetryOptions retryOptions() @ L349

  • 方法名:retryOptions
  • 源码定位:L349
  • 返回类型:RetryOptions
  • 修饰符:public

参数:

说明:

TODO

public Stream<GameTestListener> getListeners() @ L353

  • 方法名:getListeners
  • 源码定位:L353
  • 返回类型:Stream
  • 修饰符:public

参数:

说明:

TODO

public GameTestInfo copyReset() @ L357

  • 方法名:copyReset
  • 源码定位:L357
  • 返回类型:GameTestInfo
  • 修饰符:public

参数:

说明:

TODO

代码

public class GameTestInfo {
    private final Holder.Reference<GameTestInstance> test;
    private @Nullable BlockPos testBlockPos;
    private final ServerLevel level;
    private final Collection<GameTestListener> listeners = Lists.newArrayList();
    private final int timeoutTicks;
    private final Collection<GameTestSequence> sequences = Lists.newCopyOnWriteArrayList();
    private final Object2LongMap<Runnable> runAtTickTimeMap = new Object2LongOpenHashMap<>();
    private boolean placedStructure;
    private boolean chunksLoaded;
    private int tickCount;
    private boolean started;
    private final RetryOptions retryOptions;
    private final Stopwatch timer = Stopwatch.createUnstarted();
    private boolean done;
    private final Rotation extraRotation;
    private @Nullable GameTestException error;
    private @Nullable TestInstanceBlockEntity testInstanceBlockEntity;
 
    public GameTestInfo(Holder.Reference<GameTestInstance> test, Rotation extraRotation, ServerLevel level, RetryOptions retryOptions) {
        this.test = test;
        this.level = level;
        this.retryOptions = retryOptions;
        this.timeoutTicks = test.value().maxTicks();
        this.extraRotation = extraRotation;
    }
 
    public void setTestBlockPos(@Nullable BlockPos testBlockPos) {
        this.testBlockPos = testBlockPos;
    }
 
    public GameTestInfo startExecution(int tickDelay) {
        this.tickCount = -(this.test.value().setupTicks() + tickDelay + 1);
        return this;
    }
 
    public void placeStructure() {
        if (!this.placedStructure) {
            TestInstanceBlockEntity test = this.getTestInstanceBlockEntity();
            if (!test.placeStructure()) {
                this.fail(Component.translatable("test.error.structure.failure", test.getTestName().getString()));
            }
 
            this.placedStructure = true;
            test.encaseStructure();
            BoundingBox boundingBox = test.getTestBoundingBox();
            this.level.getBlockTicks().clearArea(boundingBox);
            this.level.clearBlockEvents(boundingBox);
            this.listeners.forEach(listener -> listener.testStructureLoaded(this));
        }
    }
 
    public void tick(GameTestRunner runner) {
        if (!this.isDone()) {
            if (!this.placedStructure) {
                this.fail(Component.translatable("test.error.ticking_without_structure"));
            }
 
            if (this.testInstanceBlockEntity == null) {
                this.fail(Component.translatable("test.error.missing_block_entity"));
            }
 
            if (this.error != null) {
                this.finish();
            } else {
                if (!this.chunksLoaded
                    && !this.testInstanceBlockEntity.getStructureBoundingBox().intersectingChunks().allMatch(this.level::areEntitiesActuallyLoadedAndTicking)) {
                    return;
                }
 
                this.chunksLoaded = true;
            }
 
            this.tickInternal();
            if (this.isDone()) {
                if (this.error != null) {
                    this.listeners.forEach(listener -> listener.testFailed(this, runner));
                } else {
                    this.listeners.forEach(listener -> listener.testPassed(this, runner));
                }
            }
        }
    }
 
    private void tickInternal() {
        this.tickCount++;
        if (this.tickCount >= 0) {
            if (!this.started) {
                this.startTest();
            }
 
            ObjectIterator<Entry<Runnable>> it = this.runAtTickTimeMap.object2LongEntrySet().iterator();
 
            while (it.hasNext()) {
                Entry<Runnable> entry = it.next();
                if (entry.getLongValue() <= this.tickCount) {
                    try {
                        entry.getKey().run();
                    } catch (GameTestException var4) {
                        this.fail(var4);
                    } catch (Exception var5) {
                        this.fail(new UnknownGameTestException(var5));
                    }
 
                    it.remove();
                }
            }
 
            if (this.tickCount > this.timeoutTicks) {
                if (this.sequences.isEmpty()) {
                    this.fail(new GameTestTimeoutException(Component.translatable("test.error.timeout.no_result", this.test.value().maxTicks())));
                } else {
                    this.sequences.forEach(ticker -> ticker.tickAndFailIfNotComplete(this.tickCount));
                    if (this.error == null) {
                        this.fail(
                            new GameTestTimeoutException(Component.translatable("test.error.timeout.no_sequences_finished", this.test.value().maxTicks()))
                        );
                    }
                }
            } else {
                this.sequences.forEach(ticker -> ticker.tickAndContinue(this.tickCount));
            }
        }
    }
 
    private void startTest() {
        if (!this.started) {
            this.started = true;
            this.timer.start();
            this.getTestInstanceBlockEntity().setRunning();
 
            try {
                this.test.value().run(new GameTestHelper(this));
            } catch (GameTestException var2) {
                this.fail(var2);
            } catch (Exception var3) {
                this.fail(new UnknownGameTestException(var3));
            }
        }
    }
 
    public void setRunAtTickTime(long time, Runnable assertAtTickTime) {
        this.runAtTickTimeMap.put(assertAtTickTime, time);
    }
 
    public Identifier id() {
        return this.test.key().identifier();
    }
 
    public @Nullable BlockPos getTestBlockPos() {
        return this.testBlockPos;
    }
 
    public BlockPos getTestOrigin() {
        return this.testInstanceBlockEntity.getStartCorner();
    }
 
    public AABB getStructureBounds() {
        TestInstanceBlockEntity blockEntity = this.getTestInstanceBlockEntity();
        return blockEntity.getStructureBounds();
    }
 
    public TestInstanceBlockEntity getTestInstanceBlockEntity() {
        if (this.testInstanceBlockEntity == null) {
            if (this.testBlockPos == null) {
                throw new IllegalStateException("This GameTestInfo has no position");
            }
 
            if (this.level.getBlockEntity(this.testBlockPos) instanceof TestInstanceBlockEntity blockEntity) {
                this.testInstanceBlockEntity = blockEntity;
            }
 
            if (this.testInstanceBlockEntity == null) {
                throw new IllegalStateException("Could not find a test instance block entity at the given coordinate " + this.testBlockPos);
            }
        }
 
        return this.testInstanceBlockEntity;
    }
 
    public ServerLevel getLevel() {
        return this.level;
    }
 
    public boolean hasSucceeded() {
        return this.done && this.error == null;
    }
 
    public boolean hasFailed() {
        return this.error != null;
    }
 
    public boolean hasStarted() {
        return this.started;
    }
 
    public boolean isDone() {
        return this.done;
    }
 
    public long getRunTime() {
        return this.timer.elapsed(TimeUnit.MILLISECONDS);
    }
 
    private void finish() {
        if (!this.done) {
            this.done = true;
            if (this.timer.isRunning()) {
                this.timer.stop();
            }
        }
    }
 
    public void succeed() {
        if (this.error == null) {
            this.finish();
            AABB bounds = this.getStructureBounds();
            List<Entity> entities = this.getLevel().getEntitiesOfClass(Entity.class, bounds.inflate(1.0), mob -> !(mob instanceof Player));
            entities.forEach(e -> e.remove(Entity.RemovalReason.DISCARDED));
        }
    }
 
    public void fail(Component message) {
        this.fail(new GameTestAssertException(message, this.tickCount));
    }
 
    public void fail(GameTestException error) {
        this.error = error;
    }
 
    public @Nullable GameTestException getError() {
        return this.error;
    }
 
    @Override
    public String toString() {
        return this.id().toString();
    }
 
    public void addListener(GameTestListener listener) {
        this.listeners.add(listener);
    }
 
    public @Nullable GameTestInfo prepareTestStructure() {
        TestInstanceBlockEntity testInstanceBlock = this.createTestInstanceBlock(Objects.requireNonNull(this.testBlockPos), this.extraRotation, this.level);
        if (testInstanceBlock != null) {
            this.testInstanceBlockEntity = testInstanceBlock;
            this.placeStructure();
            return this;
        } else {
            return null;
        }
    }
 
    private @Nullable TestInstanceBlockEntity createTestInstanceBlock(BlockPos testPos, Rotation rotation, ServerLevel level) {
        level.setBlockAndUpdate(testPos, Blocks.TEST_INSTANCE_BLOCK.defaultBlockState());
        if (level.getBlockEntity(testPos) instanceof TestInstanceBlockEntity blockEntity) {
            ResourceKey<GameTestInstance> test = this.getTestHolder().key();
            Vec3i size = TestInstanceBlockEntity.getStructureSize(level, test).orElse(new Vec3i(1, 1, 1));
            blockEntity.set(
                new TestInstanceBlockEntity.Data(Optional.of(test), size, rotation, false, TestInstanceBlockEntity.Status.CLEARED, Optional.empty())
            );
            return blockEntity;
        } else {
            return null;
        }
    }
 
    int getTick() {
        return this.tickCount;
    }
 
    GameTestSequence createSequence() {
        GameTestSequence sequence = new GameTestSequence(this);
        this.sequences.add(sequence);
        return sequence;
    }
 
    public boolean isRequired() {
        return this.test.value().required();
    }
 
    public boolean isOptional() {
        return !this.test.value().required();
    }
 
    public Identifier getStructure() {
        return this.test.value().structure();
    }
 
    public Rotation getRotation() {
        return this.test.value().info().rotation().getRotated(this.extraRotation);
    }
 
    public GameTestInstance getTest() {
        return this.test.value();
    }
 
    public Holder.Reference<GameTestInstance> getTestHolder() {
        return this.test;
    }
 
    public int getTimeoutTicks() {
        return this.timeoutTicks;
    }
 
    public boolean isFlaky() {
        return this.test.value().maxAttempts() > 1;
    }
 
    public int maxAttempts() {
        return this.test.value().maxAttempts();
    }
 
    public int requiredSuccesses() {
        return this.test.value().requiredSuccesses();
    }
 
    public RetryOptions retryOptions() {
        return this.retryOptions;
    }
 
    public Stream<GameTestListener> getListeners() {
        return this.listeners.stream();
    }
 
    public GameTestInfo copyReset() {
        GameTestInfo i = new GameTestInfo(this.test, this.extraRotation, this.level, this.retryOptions());
        if (this.testBlockPos != null) {
            i.setTestBlockPos(this.testBlockPos);
        }
 
        return i;
    }
}

引用的其他类

  • BlockPos

    • 引用位置: 参数/字段/返回值
  • Holder

    • 引用位置: 参数/字段/返回值
  • Vec3i

    • 引用位置: 构造调用
    • 关联成员: Vec3i()
  • GameTestAssertException

    • 引用位置: 构造调用
    • 关联成员: GameTestAssertException()
  • GameTestException

    • 引用位置: 参数/字段/返回值
  • GameTestHelper

    • 引用位置: 构造调用
    • 关联成员: GameTestHelper()
  • GameTestInstance

    • 引用位置: 参数/字段/返回值
  • GameTestListener

    • 引用位置: 参数/字段/返回值
  • GameTestRunner

    • 引用位置: 参数
  • GameTestSequence

    • 引用位置: 字段/构造调用/返回值
    • 关联成员: GameTestSequence()
  • GameTestTimeoutException

    • 引用位置: 构造调用
    • 关联成员: GameTestTimeoutException()
  • RetryOptions

    • 引用位置: 参数/字段/返回值
  • UnknownGameTestException

    • 引用位置: 构造调用
    • 关联成员: UnknownGameTestException()
  • Component

    • 引用位置: 参数/方法调用
    • 关联成员: Component.translatable()
  • Identifier

    • 引用位置: 返回值
  • ServerLevel

    • 引用位置: 参数/字段/返回值
  • Stopwatch

    • 引用位置: 字段/方法调用
    • 关联成员: Stopwatch.createUnstarted()
  • Rotation

    • 引用位置: 参数/字段/返回值
  • TestInstanceBlockEntity

    • 引用位置: 字段/方法调用/构造调用/返回值
    • 关联成员: Data(), TestInstanceBlockEntity.Data(), TestInstanceBlockEntity.getStructureSize()
  • AABB

    • 引用位置: 返回值