Skip to main content
HRTK provides two assertion classes for testing game mechanics related to entity stats and combat: StatsAssert for stat values, modifiers, and health; and CombatAssert for combat-specific checks like damage thresholds and knockback.

StatsAssert Methods

MethodDescription
assertStatEquals(store, ref, statType, expected, tolerance)Stat value equals expected (within tolerance)
assertStatEquals(store, ref, statType, expected)Stat value equals expected (tolerance 0.01)
assertStatBetween(store, ref, statType, min, max)Stat value is within range (inclusive)
assertStatAtMax(store, ref, statType)Stat is at its maximum
assertStatAtMin(store, ref, statType)Stat is at its minimum
assertHealthEquals(store, ref, expected)Entity health equals expected (tolerance 0.01)
assertHealthAtMax(store, ref)Entity health is at maximum
assertAlive(store, ref)Health > 0 and no DeathComponent
assertDead(store, ref)Entity has DeathComponent
assertHasModifier(store, ref, statType, modifierId)Stat has a named modifier
assertNoModifier(store, ref, statType, modifierId)Stat lacks a named modifier

CombatAssert Methods

MethodDescription
assertDead(store, ref)Delegates to StatsAssert.assertDead
assertAlive(store, ref)Delegates to StatsAssert.assertAlive
assertHealthEquals(store, ref, expected)Delegates to StatsAssert.assertHealthEquals
assertHealthBelow(store, ref, threshold)Assert health is strictly below threshold
assertHasKnockback(store, ref)Assert entity has KnockbackComponent

Basic Health Checks

import com.frotty27.hrtk.api.annotation.CombatTest;
import com.frotty27.hrtk.api.assert_.StatsAssert;
import com.frotty27.hrtk.api.assert_.CombatAssert;

@CombatTest
void spawnedEntityIsAlive(WorldTestContext ctx) {
    Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0);
    ctx.waitTicks(1);

    Object store = ctx.getStore();
    StatsAssert.assertAlive(store, entity);
    CombatAssert.assertAlive(store, entity); // Same check, convenience alias
}

Stat Value Assertions

@CombatTest
void healthStartsAtMax(WorldTestContext ctx) {
    Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0);
    ctx.waitTicks(1);

    Object store = ctx.getStore();
    StatsAssert.assertHealthAtMax(store, entity);
}

Damage and Death

@CombatTest
void damageReducesHealth(WorldTestContext ctx) {
    Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0);
    ctx.waitTicks(1);

    Object store = ctx.getStore();

    // Apply damage through your game logic
    applyDamage(ctx, entity, 10.0f);
    ctx.waitTicks(1);

    CombatAssert.assertHealthBelow(store, entity, 100.0f);
}
@CombatTest
void lethalDamageCausesDeath(WorldTestContext ctx) {
    Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0);
    ctx.waitTicks(1);

    applyDamage(ctx, entity, 99999.0f);
    ctx.waitTicks(5); // Allow death processing

    Object store = ctx.getStore();
    StatsAssert.assertDead(store, entity);
}
@CombatTest
void hitAppliesKnockback(WorldTestContext ctx) {
    Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0);
    ctx.waitTicks(1);

    performMeleeAttack(ctx, entity);
    ctx.waitTicks(1);

    Object store = ctx.getStore();
    CombatAssert.assertHasKnockback(store, entity);
}

Stat Modifiers

Modifiers are named effects that alter a stat’s value. Use assertHasModifier and assertNoModifier to verify modifiers are applied or removed correctly.
@CombatTest
void armorReducesDamage(WorldTestContext ctx) {
    Object entity = ctx.spawnEntity("hytale:kweebec", 0, 64, 0);
    ctx.waitTicks(1);

    // Apply armor modifier
    applyArmorModifier(ctx, entity, "iron_armor_defense");
    ctx.waitTicks(1);

    Object store = ctx.getStore();
    StatsAssert.assertHasModifier(store, entity, getDefenseStatType(), "iron_armor_defense");
}

How It Works

Both StatsAssert and CombatAssert use reflection to access Hytale’s stat system:
  1. Find the EntityStatMap component on the entity
  2. Look up the stat entry for the given StatType
  3. Call get(), getMax(), getMin() on the stat entry
  4. For health shortcuts, resolve the HEALTH stat type from the StatTypes class
The health-related methods (assertHealthEquals, assertAlive, assertDead) automatically locate the HEALTH stat type by scanning known class paths. This works with standard Hytale server builds.

Isolation Recommendation

Combat and stat tests almost always mutate entity state. Use IsolationStrategy.DEDICATED_WORLD:
@HytaleSuite(value = "Combat Tests", isolation = IsolationStrategy.DEDICATED_WORLD)
@Tag("combat")
public class CombatTests { }

Next Steps