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 |