HyCodeYourTale

Combat System

Combat System

Dokumentace k bojovému systému v Hytale.

Obsah

| Soubor | Popis |
|--------|-------|
| DAMAGE_SYSTEM.md | Damage event, DamageModule, DamageSystems, DamageDataComponent, MetaStore |
| DEATH_HANDLING.md | DeathComponent, DeathSystems, RespawnSystems, ItemsLossMode, KillFeed |

---

Přehled

Combat System

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

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

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

├── DeathSystems
│ ├── ClearHealth
│ ├── DropItems
│ ├── KillFeed
│ └── DeathScreen

└── RespawnSystems
├── ResetStats
└── RespawnController

---

DamageModule Závislost

Pro práci s damage a death eventy je nutná závislost na DamageModule:

manifest.json:

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

---

DamageEvent

Vyvolán když entita obdrží poškození.

public class DamageSystem extends EntityEventSystem {

public DamageSystem() {
super(DamageEvent.class);
}

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
DamageEvent event) {

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

if (player != null) {
// Hráč obdržel poškození
player.sendMessage(Message.raw("Obdržel jsi poškození!"));

// Zrušení poškození
// event.cancel();
}
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

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

---

DeathEvent

Vyvolán když entita zemře.

public class DeathSystem extends EntityEventSystem {

public DeathSystem() {
super(DeathEvent.class);
}

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
DeathEvent event) {

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

if (player != null) {
PlayerRef playerRef = store.getComponent(ref, PlayerRef.getComponentType());

// Logování smrti
getLogger().atInfo().log("Player %s died", playerRef.getUsername());

// Zpráva hráči
player.sendMessage(Message.raw("Zemřel jsi!"));

// Aktualizace statistik
updateDeathStats(playerRef.getUuid());
}
}

private void updateDeathStats(UUID uuid) {
// Inkrementuj počet smrtí
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

---

DamageDataComponent

Komponenta pro sledování damage dat:

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

---

Kill Tracking

Sledování Zabití

public class KillTracker {

private final Map kills = new ConcurrentHashMap<>();

public void onPlayerKill(UUID killerUuid, UUID victimUuid) {
kills.merge(killerUuid, 1, Integer::sum);
}

public int getKills(UUID uuid) {
return kills.getOrDefault(uuid, 0);
}
}

Death System s Kill Tracking

public class CombatDeathSystem extends EntityEventSystem {

private final KillTracker killTracker;

public CombatDeathSystem(KillTracker killTracker) {
super(DeathEvent.class);
this.killTracker = killTracker;
}

@Override
public void handle(int i, ArchetypeChunk chunk,
Store store, CommandBuffer buffer,
DeathEvent event) {

Ref ref = chunk.getReferenceTo(i);
PlayerRef victimRef = store.getComponent(ref, PlayerRef.getComponentType());

if (victimRef == null) return;

UUID victimUuid = victimRef.getUuid();

// Získej útočníka (pokud existuje)
// UUID killerUuid = getKillerFromEvent(event);
// if (killerUuid != null) {
// killTracker.onPlayerKill(killerUuid, victimUuid);
// }
}

@Override
public Query getQuery() {
return PlayerRef.getComponentType();
}
}

---

PvP Toggle

Koncept

public class PvPManager {

private final Set pvpDisabled = ConcurrentHashMap.newKeySet();

public void setPvPEnabled(UUID uuid, boolean enabled) {
if (enabled) {
pvpDisabled.remove(uuid);
} else {
pvpDisabled.add(uuid);
}
}

public boolean isPvPEnabled(UUID uuid) {
return !pvpDisabled.contains(uuid);
}
}

// V DamageSystem
@Override
public void handle(..., DamageEvent event) {
// Zkontroluj PvP status
// if (!pvpManager.isPvPEnabled(victimUuid)) {
// event.cancel();
// return;
// }
}

---

Combat Stats Příkaz

public class StatsCommand extends AbstractPlayerCommand {

private final KillTracker killTracker;
private final DeathTracker deathTracker;

public StatsCommand(KillTracker killTracker, DeathTracker deathTracker) {
super("stats", "myplugin.commands.stats.desc");
this.killTracker = killTracker;
this.deathTracker = deathTracker;
}

@Override
protected void execute(CommandContext context, Store store,
Ref ref, PlayerRef playerRef, World world) {

UUID uuid = playerRef.getUuid();
int kills = killTracker.getKills(uuid);
int deaths = deathTracker.getDeaths(uuid);
double kd = deaths == 0 ? kills : (double) kills / deaths;

context.sendMessage(Message.raw("=== Combat Stats ==="));
context.sendMessage(Message.raw("Kills: " + kills));
context.sendMessage(Message.raw("Deaths: " + deaths));
context.sendMessage(Message.raw(String.format("K/D: %.2f", kd)));
}
}

---

Damage Types (Koncept)

public enum DamageType {
PHYSICAL,
FIRE,
MAGIC,
FALL,
DROWNING,
VOID,
EXPLOSION
}

Damage Modifier System

public class DamageModifier {

private final Map resistances = new EnumMap<>(DamageType.class);

public void setResistance(DamageType type, double multiplier) {
resistances.put(type, multiplier);
}

public double calculateDamage(DamageType type, double baseDamage) {
double resistance = resistances.getOrDefault(type, 1.0);
return baseDamage * resistance;
}
}

---

Cooldowns

Cooldown Manager

public class CooldownManager {

private final Map> cooldowns = new ConcurrentHashMap<>();

public void setCooldown(UUID uuid, String ability, long durationMs) {
cooldowns.computeIfAbsent(uuid, k -> new ConcurrentHashMap<>())
.put(ability, System.currentTimeMillis() + durationMs);
}

public boolean isOnCooldown(UUID uuid, String ability) {
Map playerCooldowns = cooldowns.get(uuid);
if (playerCooldowns == null) return false;

Long endTime = playerCooldowns.get(ability);
if (endTime == null) return false;

return System.currentTimeMillis() < endTime;
}

public long getRemainingCooldown(UUID uuid, String ability) {
Map playerCooldowns = cooldowns.get(uuid);
if (playerCooldowns == null) return 0;

Long endTime = playerCooldowns.get(ability);
if (endTime == null) return 0;

long remaining = endTime - System.currentTimeMillis();
return Math.max(0, remaining);
}
}

---

Kompletní Combat Plugin Příklad

public class CombatPlugin extends JavaPlugin {

private static CombatPlugin instance;
private KillTracker killTracker;
private DeathTracker deathTracker;
private CooldownManager cooldownManager;

public CombatPlugin(JavaPluginInit init) {
super(init);
}

public static CombatPlugin get() {
return instance;
}

@Override
protected void setup() {
instance = this;

killTracker = new KillTracker();
deathTracker = new DeathTracker();
cooldownManager = new CooldownManager();

// Systémy
getEntityStoreRegistry().registerSystem(new CombatDamageSystem());
getEntityStoreRegistry().registerSystem(new CombatDeathSystem(killTracker, deathTracker));

// Příkazy
getCommandRegistry().registerCommand(new StatsCommand(killTracker, deathTracker));
}

public KillTracker getKillTracker() { return killTracker; }
public DeathTracker getDeathTracker() { return deathTracker; }
public CooldownManager getCooldownManager() { return cooldownManager; }
}

---

Shrnutí

| Event | Závislost | Cancellable |
|-------|-----------|-------------|
| DamageEvent | DamageModule | Ano |
| DeathEvent | DamageModule | Ne |

| Komponenta | Popis |
|------------|-------|
| DamageDataComponent | Damage tracking |
| KnockbackComponent | Knockback fyzika |

| Pattern | Použití |
|---------|---------|
| KillTracker | Sledování zabití |
| CooldownManager | Cooldowny schopností |
| DamageModifier | Modifikace damage |

Last updated: 20. ledna 2026