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 |