Components
Komponenty v ECS architektuře Hytale.
---
Co je Komponenta?
Komponenta je čistě datová struktura bez logiky. Obsahuje pouze data a gettery/settery.
// Komponenta = pouze data
public class HealthComponent implements Component {
private int currentHealth;
private int maxHealth; // Pouze gettery a settery
public int getCurrentHealth() { return currentHealth; }
public void setCurrentHealth(int health) { this.currentHealth = health; }
public int getMaxHealth() { return maxHealth; }
public void setMaxHealth(int max) { this.maxHealth = max; }
@Override
public Component clone() {
HealthComponent copy = new HealthComponent();
copy.currentHealth = this.currentHealth;
copy.maxHealth = this.maxHealth;
return copy;
}
}
Logika patří do Systémů, ne do Komponent!
---
Vestavěné Komponenty
Player Komponenty
| Komponenta | Popis |
|------------|-------|
| Player | Základní player data |
| PlayerRef | Reference na hráče (UUID, username) |
| TransformComponent | Pozice a rotace |
| HeadRotation | Rotace hlavy |
Entity Komponenty
| Komponenta | Popis |
|------------|-------|
| NetworkId | Síťové ID entity |
| BoundingBox | Kolizní box |
| ModelComponent | 3D model |
| Nameplate | Jmenovka nad entitou |
State Komponenty
| Komponenta | Popis |
|------------|-------|
| MovementStatesComponent | Stav pohybu |
| EffectControllerComponent | Aktivní efekty |
| KnockbackComponent | Knockback fyzika |
Speciální Komponenty
| Komponenta | Popis |
|------------|-------|
| Intangible | Entity nelze interagovat |
| HiddenFromAdventurePlayers | Skrytá v adventure módu |
| Container | Inventář/kontejner |
---
Registrace Vlastní Komponenty
1. Definice Komponenty
public class CustomStatsComponent implements Component { private int kills;
private int deaths;
private long playTime;
public CustomStatsComponent() {
this.kills = 0;
this.deaths = 0;
this.playTime = 0;
}
// Gettery
public int getKills() { return kills; }
public int getDeaths() { return deaths; }
public long getPlayTime() { return playTime; }
// Settery
public void setKills(int kills) { this.kills = kills; }
public void setDeaths(int deaths) { this.deaths = deaths; }
public void setPlayTime(long time) { this.playTime = time; }
// Utility metody
public void incrementKills() { this.kills++; }
public void incrementDeaths() { this.deaths++; }
public double getKDRatio() {
return deaths == 0 ? kills : (double) kills / deaths;
}
// Povinná metoda clone()
@Nonnull
@Override
public Component clone() {
CustomStatsComponent copy = new CustomStatsComponent();
copy.kills = this.kills;
copy.deaths = this.deaths;
copy.playTime = this.playTime;
return copy;
}
}
2. Registrace v Pluginu
public class MyPlugin extends JavaPlugin { private static MyPlugin instance;
private ComponentType customStatsType;
public MyPlugin(JavaPluginInit init) {
super(init);
}
public static MyPlugin get() {
return instance;
}
@Override
protected void setup() {
instance = this;
// Registrace komponenty
this.customStatsType = getEntityStoreRegistry().registerComponent(
CustomStatsComponent.class,
CustomStatsComponent::new // Factory pro nové instance
);
}
// Getter pro ComponentType
public ComponentType getCustomStatsType() {
return customStatsType;
}
}
3. Použití Komponenty
// Získání ComponentType
ComponentType statsType =
MyPlugin.get().getCustomStatsType();// Čtení komponenty
CustomStatsComponent stats = store.getComponent(ref, statsType);
if (stats != null) {
int kills = stats.getKills();
}
// Přidání komponenty k entitě
store.addComponent(ref, statsType, new CustomStatsComponent());
// Zajištění že komponenta existuje (vytvoří pokud neexistuje)
CustomStatsComponent stats = store.ensureAndGetComponent(ref, statsType);
---
Přístup ke Komponentám
Základní Přístup
// Vždy kontroluj null!
Player player = store.getComponent(ref, Player.getComponentType());
if (player == null) {
return; // Entita nemá Player komponentu
}// Nyní bezpečné použití
String name = player.getName();
Kontrola Existence
// Metoda 1: Kontrola null
Player player = store.getComponent(ref, Player.getComponentType());
if (player != null) {
// Použij player
}// Metoda 2: hasComponent (méně efektivní - dvojí lookup)
if (store.hasComponent(ref, Player.getComponentType())) {
Player player = store.getComponent(ref, Player.getComponentType());
}
Doporučeno: Použij metodu 1 - jednoduchý lookup a null kontrola.
Více Komponent Najednou
Player player = store.getComponent(ref, Player.getComponentType());
TransformComponent transform = store.getComponent(ref, TransformComponent.getComponentType());
CustomStatsComponent stats = store.getComponent(ref, MyPlugin.get().getCustomStatsType());if (player != null && transform != null && stats != null) {
// Všechny komponenty existují
Vector3d position = transform.getPosition();
int kills = stats.getKills();
}
---
Store Operace
Čtení
// Získej komponentu
T component = store.getComponent(ref, componentType);// Kontrola existence
boolean has = store.hasComponent(ref, componentType);
Zápis
// Přidej komponentu
store.addComponent(ref, componentType, component);// Nastav/přepiš komponentu
store.setComponent(ref, componentType, component);
// Zajisti existenci a získej
T component = store.ensureAndGetComponent(ref, componentType);
// Odeber komponentu
store.removeComponent(ref, componentType);
V CommandBuffer (pro systémy)
@Override
public void handle(..., CommandBuffer commandBuffer, ...) {
// Použij commandBuffer pro modifikace během iterace
commandBuffer.addComponent(ref, componentType, newComponent);
commandBuffer.removeComponent(ref, componentType);
}
---
ComponentType
ComponentType je identifikátor typu komponenty.
Vestavěné Typy
// Získání přes statickou metodu
ComponentType playerType = Player.getComponentType();
ComponentType playerRefType = PlayerRef.getComponentType();
ComponentType transformType = TransformComponent.getComponentType();
Vlastní Typy
// Registrace vrací ComponentType
ComponentType myType =
getEntityStoreRegistry().registerComponent(MyComponent.class, MyComponent::new);// Uložení v pluginu pro pozdější použití
public ComponentType getMyComponentType() {
return myType;
}
---
Příklad: TeleportHistory (z TeleportPlugin)
public class TeleportHistory implements Component { private final List history = new ArrayList<>();
public void append(World world, Vector3d position, Vector3f rotation, String description) {
history.add(new TeleportEntry(world.getName(), position, rotation, description));
}
public TeleportEntry getLastEntry() {
return history.isEmpty() ? null : history.get(history.size() - 1);
}
@Nonnull
@Override
public Component clone() {
TeleportHistory copy = new TeleportHistory();
copy.history.addAll(this.history);
return copy;
}
public record TeleportEntry(String worldName, Vector3d position, Vector3f rotation, String description) {}
}
// Registrace
this.teleportHistoryComponentType = EntityStore.REGISTRY.registerComponent(
TeleportHistory.class,
TeleportHistory::new
);
// Použití
TeleportHistory history = store.ensureAndGetComponent(ref, TeleportHistory.getComponentType());
history.append(world, previousPos, previousRotation, "Teleport to spawn");
---
Příklad: WarpComponent (z TeleportPlugin)
// Record komponenta - immutable
public static record WarpComponent(Warp warp) implements Component { public static ComponentType getComponentType() {
return TeleportPlugin.get().warpComponentType;
}
@Nonnull
@Override
public Component clone() {
return new WarpComponent(this.warp);
}
}
---
Shrnutí
| Operace | Metoda |
|---------|--------|
| Čtení | store.getComponent(ref, type) |
| Kontrola | store.hasComponent(ref, type) |
| Přidání | store.addComponent(ref, type, comp) |
| Nastavení | store.setComponent(ref, type, comp) |
| Zajištění | store.ensureAndGetComponent(ref, type) |
| Odebrání | store.removeComponent(ref, type) |
| Registrace | getEntityStoreRegistry().registerComponent(...) |