HyCodeYourTale

Damage System

Damage System

Detailní dokumentace k damage systému v Hytale.

---

Přehled Architektury

Damage System

├── DamageModule (Plugin)
│ ├── DeathComponent
│ └── SystemGroups (Gather, Filter, Inspect)

├── Damage (Event)
│ ├── Source (Entity, Command, Environment)
│ ├── DamageCause
│ └── MetaStore (particles, sound, knockback)

├── DamageSystems
│ ├── ApplyDamage
│ ├── FallDamage
│ ├── ArmorReduction
│ └── Knockback

└── DamageDataComponent
└── Combat tracking

---

DamageModule

Hlavní plugin pro damage systém:

public class DamageModule extends JavaPlugin {
public static final PluginManifest MANIFEST = PluginManifest.corePlugin(DamageModule.class)
.depends(EntityModule.class)
.depends(EntityStatsModule.class)
.depends(EntityUIModule.class)
.build();

// Singleton
public static DamageModule get() { return instance; }

// Component types
public ComponentType getDeathComponentType();
public ComponentType getDeferredCorpseRemovalComponentType();

// System groups pro ordering
public SystemGroup getGatherDamageGroup(); // Sbírání damage
public SystemGroup getFilterDamageGroup(); // Filtrování damage
public SystemGroup getInspectDamageGroup(); // Inspekce damage
}

Závislost v manifest.json

{
"Dependencies": {
"Hytale:DamageModule": "*"
}
}

---

Damage Event

Hlavní třída pro damage eventy:

public class Damage extends CancellableEcsEvent implements IMetaStore {
// Meta registry pro extra data
public static final MetaRegistry META_REGISTRY = new MetaRegistry<>();

// Meta klíče
public static final MetaKey HIT_LOCATION;
public static final MetaKey HIT_ANGLE;
public static final MetaKey IMPACT_PARTICLES;
public static final MetaKey IMPACT_SOUND_EFFECT;
public static final MetaKey CAMERA_EFFECT;
public static final MetaKey DEATH_ICON;
public static final MetaKey BLOCKED;
public static final MetaKey STAMINA_DRAIN_MULTIPLIER;
public static final MetaKey KNOCKBACK_COMPONENT;

// Null source pro neznámý zdroj
public static final Damage.Source NULL_SOURCE;

// Základní vlastnosti
private final float initialAmount;
private int damageCauseIndex;
private Damage.Source source;
private float amount;

// Konstruktory
public Damage(Damage.Source source, DamageCause damageCause, float amount);
public Damage(Damage.Source source, int damageCauseIndex, float amount);

// Gettery/Settery
public float getAmount();
public void setAmount(float amount);
public float getInitialAmount();
public Damage.Source getSource();
public void setSource(Damage.Source source);
public int getDamageCauseIndex();
public DamageCause getCause();

// Death message
public Message getDeathMessage(Ref targetRef, ComponentAccessor accessor);
}

---

Damage Sources

EntitySource

Damage od entity (hráč, mob):

public static class EntitySource implements Damage.Source {
protected final Ref sourceRef;

public EntitySource(Ref sourceRef) {
this.sourceRef = sourceRef;
}

public Ref getRef() {
return sourceRef;
}

@Override
public Message getDeathMessage(Damage info, Ref targetRef, ComponentAccessor accessor) {
// "Killed by [entity name]"
return Message.translation("server.general.killedBy").param("damageSource", displayName);
}
}

ProjectileSource

Damage od projektilu (šíp, spell):

public static class ProjectileSource extends Damage.EntitySource {
protected final Ref projectile;

public ProjectileSource(Ref shooter, Ref projectile) {
super(shooter);
this.projectile = projectile;
}

public Ref getProjectile() {
return projectile;
}
}

CommandSource

Damage z příkazu:

public static class CommandSource implements Damage.Source {
private final CommandSender commandSender;
private final String commandName;

public CommandSource(CommandSender commandSender, AbstractCommand cmd) {
this(commandSender, cmd.getName());
}

@Override
public Message getDeathMessage(Damage info, Ref targetRef, ComponentAccessor accessor) {
return Message.translation("server.general.killedByCommand")
.param("displayName", commandSender.getDisplayName())
.param("commandName", commandName);
}
}

EnvironmentSource

Damage z prostředí (pád, utopení):

public static class EnvironmentSource implements Damage.Source {
private final String type;

public EnvironmentSource(String type) {
this.type = type;
}

public String getType() {
return type;
}
}

---

Vyvolání Damage

Přes DamageSystems

// Nejjednodušší způsob
DamageSystems.executeDamage(ref, componentAccessor, damage);

// V systému s CommandBuffer
DamageSystems.executeDamage(index, archetypeChunk, commandBuffer, damage);

// S reference
DamageSystems.executeDamage(ref, commandBuffer, damage);

Vytvoření Damage Instance

// Z entity
Ref attackerRef = ...;
Damage damage = new Damage(
new Damage.EntitySource(attackerRef),
DamageCause.getAssetMap().getAsset("Combat"),
10.0f // amount
);

// Z prostředí
Damage fallDamage = new Damage(
new Damage.EnvironmentSource("fall"),
DamageCause.getAssetMap().getAsset("Fall"),
15.0f
);

// S knockbackem
KnockbackComponent knockback = new KnockbackComponent(direction, force);
damage.getMeta(Damage.KNOCKBACK_COMPONENT).set(knockback);

---

DamageDataComponent

Komponenta pro sledování combat dat:

public class DamageDataComponent implements Component {
// Čas poslední combat akce
private Instant lastCombatAction = Instant.MIN;

// Čas posledního obdrženého damage
private Instant lastDamageTime = Instant.MIN;

// Aktuální wielding interakce
private WieldingInteraction currentWielding;

// Čas posledního charge
private Instant lastChargeTime;

// Gettery
public Instant getLastCombatAction();
public Instant getLastDamageTime();
public Instant getLastChargeTime();
public WieldingInteraction getCurrentWielding();

// Settery
public void setLastCombatAction(Instant lastCombatAction);
public void setLastDamageTime(Instant lastDamageTime);
public void setCurrentWielding(WieldingInteraction currentWielding);

// ComponentType
public static ComponentType getComponentType() {
return EntityModule.get().getDamageDataComponentType();
}
}

Použití DamageDataComponent

// Získání komponenty
DamageDataComponent damageData = store.getComponent(ref, DamageDataComponent.getComponentType());

if (damageData != null) {
// Kontrola doby od posledního damage
Instant lastDamage = damageData.getLastDamageTime();
Duration elapsed = Duration.between(lastDamage, Instant.now());

if (elapsed.toMillis() < 500) {
// Damage immunity period
return;
}

// Aktualizace
damageData.setLastDamageTime(Instant.now());
}

---

DamageSystems

Vestavěné systémy pro zpracování damage:

ApplyDamage

Hlavní systém aplikující damage na health:

public static class ApplyDamage extends DamageEventSystem {
@Override
public void handle(int index, ArchetypeChunk archetypeChunk,
Store store, CommandBuffer commandBuffer,
Damage damage) {

EntityStatMap statMap = archetypeChunk.getComponent(index, EntityStatMap.getComponentType());
int healthStat = DefaultEntityStatTypes.getHealth();

// Kontrola smrti
boolean isDead = archetypeChunk.getArchetype().contains(DeathComponent.getComponentType());
if (isDead) {
damage.setCancelled(true);
return;
}

// Zaokrouhlení damage
damage.setAmount((float)Math.round(damage.getAmount()));

// Odečtení health
float newValue = statMap.subtractStatValue(healthStat, damage.getAmount());

// Smrt pokud health <= 0
if (newValue <= healthValue.getMin()) {
DeathComponent.tryAddComponent(commandBuffer, archetypeChunk.getReferenceTo(index), damage);
}
}
}

Další Systémy

// Fall damage
DamageSystems.FallDamagePlayers
DamageSystems.FallDamageNPCs

// Armor reduction
DamageSystems.ArmorDamageReduction
DamageSystems.ArmorKnockbackReduction

// Wielding (blocking) reduction
DamageSystems.WieldingDamageReduction
DamageSystems.WieldingKnockbackReduction

// Filtering
DamageSystems.FilterUnkillable
DamageSystems.PlayerDamageFilterSystem
DamageSystems.FilterPlayerWorldConfig
DamageSystems.FilterNPCWorldConfig

// Tracking
DamageSystems.RecordLastCombat
DamageSystems.TrackLastDamage

// Effects
DamageSystems.ApplyParticles
DamageSystems.ApplySoundEffects
DamageSystems.HitAnimation

// Armor/Stamina damage
DamageSystems.DamageArmor
DamageSystems.DamageStamina
DamageSystems.DamageAttackerTool

// UI
DamageSystems.PlayerHitIndicators
DamageSystems.ReticleEvents
DamageSystems.EntityUIEvents

---

Custom Damage System

Základní DamageEventSystem

public class MyDamageSystem extends DamageEventSystem {

@Override
public Query getQuery() {
return PlayerRef.getComponentType(); // Pouze hráči
}

@Override
public void handle(int index, ArchetypeChunk chunk,
Store store, CommandBuffer commandBuffer,
Damage damage) {

Ref ref = chunk.getReferenceTo(index);
Player player = store.getComponent(ref, Player.getComponentType());

if (player != null) {
// Zpráva hráči
player.sendMessage(Message.raw(String.format(
"Obdržel jsi %.0f damage!", damage.getAmount()
)));

// Zrušení damage
// damage.setCancelled(true);
}
}
}

// Registrace
@Override
protected void setup() {
getEntityStoreRegistry().registerSystem(new MyDamageSystem());
}

System Ordering

public class MyFilterSystem extends DamageEventSystem {
private static final Set> DEPENDENCIES = Set.of(
// Po gather fázi
new SystemGroupDependency<>(Order.AFTER, DamageModule.get().getGatherDamageGroup()),
// V rámci filter fáze
new SystemGroupDependency<>(Order.PART_OF, DamageModule.get().getFilterDamageGroup()),
// Před apply damage
new SystemDependency<>(Order.BEFORE, DamageSystems.ApplyDamage.class)
);

@Override
public Set> getDependencies() {
return DEPENDENCIES;
}

@Override
public void handle(..., Damage damage) {
// Modifikace damage před aplikací
damage.setAmount(damage.getAmount() * 0.9f); // 10% redukce
}
}

---

Damage Meta

Particles

// Nastavení impact particles
Damage.Particles particles = new Damage.Particles(
modelParticles, // ModelParticle[]
worldParticles, // WorldParticle[]
32.0 // View distance
);
damage.getMeta(Damage.IMPACT_PARTICLES).set(particles);

Sound Effects

// Impact sound
Damage.SoundEffect sound = new Damage.SoundEffect(soundEventIndex);
damage.getMeta(Damage.IMPACT_SOUND_EFFECT).set(sound);

Camera Effect

// Camera shake
Damage.CameraEffect camera = new Damage.CameraEffect(cameraEffectIndex);
damage.getMeta(Damage.CAMERA_EFFECT).set(camera);

Knockback

// Knockback
KnockbackComponent knockback = new KnockbackComponent(direction, force);
damage.getMeta(Damage.KNOCKBACK_COMPONENT).set(knockback);

---

Shrnutí

| Třída | Účel |
|-------|------|
| DamageModule | Hlavní plugin pro damage |
| Damage | Event třída pro damage |
| Damage.Source | Zdroj damage |
| DamageDataComponent | Combat tracking komponenta |
| DamageSystems | Vestavěné damage systémy |
| DamageEventSystem | Base třída pro custom systémy |

| Damage.Source | Popis |
|---------------|-------|
| EntitySource | Damage od entity |
| ProjectileSource | Damage od projektilu |
| CommandSource | Damage z příkazu |
| EnvironmentSource | Damage z prostředí |

| MetaKey | Typ | Popis |
|---------|-----|-------|
| HIT_LOCATION | Vector4d | Místo zásahu |
| KNOCKBACK_COMPONENT | KnockbackComponent | Knockback data |
| IMPACT_PARTICLES | Particles | Efekt částic |
| IMPACT_SOUND_EFFECT | SoundEffect | Zvukový efekt |
| BLOCKED | Boolean | Byl damage zablokován |

Last updated: 20. ledna 2026