package com.example.tests;
import com.frotty27.hrtk.api.annotation.HytaleSuite;
import com.frotty27.hrtk.api.annotation.WorldTest;
import com.frotty27.hrtk.api.annotation.Tag;
import com.frotty27.hrtk.api.annotation.DisplayName;
import com.frotty27.hrtk.api.annotation.Order;
import com.frotty27.hrtk.api.assert_.HytaleAssert;
import com.frotty27.hrtk.api.assert_.WorldAssert;
import com.frotty27.hrtk.api.context.WorldTestContext;
import com.frotty27.hrtk.api.lifecycle.IsolationStrategy;
@HytaleSuite(value = "World Surface Tests", isolation = IsolationStrategy.DEDICATED_WORLD)
@Tag("world")
public class WorldSurfaceTests {
@WorldTest
@Order(1)
@DisplayName("Spawn a Trork_Warrior at specific coordinates")
void spawnEntityAtPosition(WorldTestContext ctx) {
// Spawn a Trork_Warrior at coordinates (10, 64, 10).
// spawnNPC uses the NPCPlugin to create a fully initialized entity
// with all components defined for that role (health, AI, model, etc.).
Object entity = ctx.spawnNPC("Trork_Warrior", 10, 64, 10);
ctx.waitTicks(1);
HytaleAssert.assertNotNull("Entity reference should not be null", entity);
HytaleAssert.assertTrue(
"Entity should exist in the world after spawning",
ctx.entityExists(entity)
);
}
@WorldTest
@Order(2)
@DisplayName("Verify entity spawns at the correct position")
void entityPositionMatchesSpawnCoordinates(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Trork_Warrior", 25, 64, 30);
ctx.waitTicks(1);
// getPosition returns a double array [x, y, z].
// We use a tolerance of 0.5 because the entity may settle slightly
// due to physics (gravity, ground snapping).
double[] pos = ctx.getPosition(entity);
HytaleAssert.assertNotNull("Position should not be null", pos);
HytaleAssert.assertEquals(25.0, pos[0], 0.5);
HytaleAssert.assertEquals(64.0, pos[1], 0.5);
HytaleAssert.assertEquals(30.0, pos[2], 0.5);
}
@WorldTest
@Order(3)
@DisplayName("Set entity position and verify it moved")
void setPositionMovesEntity(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Trork_Warrior", 0, 64, 0);
ctx.waitTicks(1);
// Teleport the entity to a new position.
ctx.setPosition(entity, 100, 70, 100);
ctx.waitTicks(1);
double[] pos = ctx.getPosition(entity);
HytaleAssert.assertEquals(100.0, pos[0], 0.5);
HytaleAssert.assertEquals(70.0, pos[1], 0.5);
HytaleAssert.assertEquals(100.0, pos[2], 0.5);
}
@WorldTest
@Order(4)
@DisplayName("Place a block and verify its type")
void setAndGetBlock(WorldTestContext ctx) {
// setBlock places a block at the given coordinates.
// The type ID is the block's asset name without a namespace prefix.
ctx.setBlock(5, 64, 5, "Rock_Sandstone");
WorldAssert.assertBlockAt(ctx.getWorld(), 5, 64, 5, "Rock_Sandstone");
WorldAssert.assertBlockNotAt(ctx.getWorld(), 5, 64, 5, "Empty");
}
@WorldTest
@Order(5)
@DisplayName("Fill a region to build a flat arena floor")
void fillRegionBuildsArena(WorldTestContext ctx) {
// fillRegion batches all block placements into a single world-thread dispatch.
// This is ideal for setting up test arenas - the entire floor is placed
// atomically in one tick, so you can assert immediately after.
ctx.fillRegion(0, 60, 0, 20, 60, 20, "Rock_Sandstone");
// Spot-check corners and center to confirm the fill worked.
WorldAssert.assertBlockAt(ctx.getWorld(), 0, 60, 0, "Rock_Sandstone");
WorldAssert.assertBlockAt(ctx.getWorld(), 20, 60, 20, "Rock_Sandstone");
WorldAssert.assertBlockAt(ctx.getWorld(), 10, 60, 10, "Rock_Sandstone");
}
@WorldTest
@Order(6)
@DisplayName("Despawn entity and verify removal")
void despawnedEntityNoLongerExists(WorldTestContext ctx) {
Object entity = ctx.spawnNPC("Trork_Warrior", 0, 64, 0);
ctx.waitTicks(1);
HytaleAssert.assertTrue("Entity should exist before despawn", ctx.entityExists(entity));
ctx.despawn(entity);
ctx.waitTicks(1);
HytaleAssert.assertFalse(
"Entity should not exist after despawn",
ctx.entityExists(entity)
);
}
@WorldTest
@Order(7)
@DisplayName("World tick advances correctly with waitTicks")
void worldTickAdvances(WorldTestContext ctx) {
// waitTicks blocks the test thread until N world ticks have elapsed.
// This is essential for testing time-dependent behavior.
Object entity = ctx.spawnNPC("Kweebec_Sapling", 5, 64, 5);
ctx.waitTicks(10);
// After 10 ticks, the entity should still exist and the world should be alive.
HytaleAssert.assertTrue("Entity should persist across ticks", ctx.entityExists(entity));
}
}