HyCodeYourTale

Effect Types

Effect Types

Dokumentace k typům efektů a jejich definici v Hytale.

---

Entity Effect Asset

Efekty jsou definovány jako assety typu EntityEffect. Každý efekt má unikátní ID a konfiguraci.

Hlavní třída

// com.hypixel.hytale.server.core.asset.type.entityeffect.config.EntityEffect

// Získání assetu efektu
EntityEffect entityEffect = EntityEffect.getAssetMap().getAsset("Burn");

// Získání indexu efektu
int effectIndex = EntityEffect.getAssetMap().getIndex("Burn");

// Metody EntityEffect:
entityEffect.getId(); // String - ID efektu
entityEffect.getDuration(); // float - délka trvání
entityEffect.isInfinite(); // boolean - nekonečný efekt
entityEffect.isDebuff(); // boolean - je to debuff
entityEffect.isInvulnerable(); // boolean - činí nezranitelným
entityEffect.getOverlapBehavior(); // OverlapBehavior - chování při překryvu
entityEffect.getRemovalBehavior(); // RemovalBehavior - chování při odebrání
entityEffect.getDamageCalculator(); // DamageCalculator - kalkulátor damage
entityEffect.getDamageCalculatorCooldown(); // float - cooldown mezi damage
entityEffect.getEntityStats(); // Int2FloatMap - stat modifikátory
entityEffect.getValueType(); // ChangeStatBehaviour - typ změny
entityEffect.getModelChange(); // String - změna modelu
entityEffect.getStatusEffectIcon(); // String - ikona efektu
entityEffect.getLocale(); // String - lokalizační klíč
entityEffect.getStatModifierEffects(); // DamageEffects - vizuální efekty při stat změně
entityEffect.getDamageEffects(); // DamageEffects - vizuální efekty při damage

---

OverlapBehavior

Chování efektu při aplikaci na entitu, která již má stejný efekt aktivní.

// com.hypixel.hytale.server.core.asset.type.entityeffect.config.OverlapBehavior

public enum OverlapBehavior {
EXTEND, // Prodlouží trvání existujícího efektu
OVERWRITE, // Přepíše existující efekt novým
IGNORE // Ignoruje nový efekt, ponechá existující
}

Použití

// Při aplikaci efektu s konkrétním chováním
effectController.addEffect(
entityRef,
entityEffect,
duration,
OverlapBehavior.EXTEND, // Prodlouží existující efekt
componentAccessor
);

---

RemovalBehavior

Chování efektu při jeho odstranění.

// com.hypixel.hytale.server.core.asset.type.entityeffect.config.RemovalBehavior

public enum RemovalBehavior {
COMPLETE, // Úplně odstraní efekt
INFINITE, // Odstraní jen infinite flag, efekt může expirovat
DURATION // Nastaví duration na 0, efekt bude odstraněn při dalším ticku
}

---

ActiveEntityEffect

Aktivní instance efektu na entitě.

// com.hypixel.hytale.server.core.entity.effect.ActiveEntityEffect

public class ActiveEntityEffect implements Damage.Source {

// Hlavní properties
String entityEffectId; // ID efektu
int entityEffectIndex; // Index v asset mapě
float initialDuration; // Počáteční trvání
float remainingDuration; // Zbývající trvání
boolean infinite; // Nekonečný efekt
boolean debuff; // Je debuff
String statusEffectIcon; // Ikona
boolean invulnerable; // Činí nezranitelným

// Damage tracking
float sinceLastDamage; // Čas od posledního damage
boolean hasBeenDamaged; // Již způsobil damage
DamageCalculatorSystems.Sequence sequentialHits; // Sekvence hitů

// Metody
public int getEntityEffectIndex();
public float getInitialDuration();
public float getRemainingDuration();
public boolean isInfinite();
public boolean isDebuff();
public boolean isInvulnerable();

// Tick - volá se každý frame
public void tick(
CommandBuffer commandBuffer,
Ref ref,
EntityEffect entityEffect,
EntityStatMap entityStatMapComponent,
float dt
);
}

CODEC pro serializaci

public static final BuilderCodec CODEC = BuilderCodec.builder(...)
.append("EntityEffectId", Codec.STRING, ...)
.append("InitialDuration", Codec.FLOAT, ...)
.append("RemainingDuration", Codec.FLOAT, ...)
.append("SinceLastDamage", Codec.FLOAT, ...)
.append("HasBeenDamaged", Codec.BOOLEAN, ...)
.append("SequentialHits", DamageCalculatorSystems.Sequence.CODEC, ...)
.append("Infinite", Codec.BOOLEAN, ...)
.append("Debuff", Codec.BOOLEAN, ...)
.append("StatusEffectIcon", Codec.STRING, ...)
.append("Invulnerable", Codec.BOOLEAN, ...)
.build();

---

TargetEntityEffect

Konfigurace efektu pro cílovou entitu (používá se v interakcích a combat systému).

// com.hypixel.hytale.server.core.modules.interaction.interaction.config.server.combat.TargetEntityEffect

public class TargetEntityEffect {
float duration; // Délka efektu
double chance = 1.0; // Šance na aplikaci (0.0-1.0)
Object2DoubleMap entityTypeDurationModifiers; // Modifikátory délky podle typu entity
OverlapBehavior overlapBehavior = OverlapBehavior.IGNORE;

// Gettery
public float getDuration();
public double getChance();
public Object2DoubleMap getEntityTypeDurationModifiers();
public OverlapBehavior getOverlapBehavior();
}

CODEC

public static final BuilderCodec CODEC = BuilderCodec.builder(...)
.addField("Duration", Codec.DOUBLE, ...)
.addField("Chance", Codec.DOUBLE, ...)
.addField("EntityTypeDurationModifiers", Object2DoubleMapCodec, ...)
.addField("OverlapBehavior", OverlapBehavior.CODEC, ...)
.build();

---

Stat Modifikátory

Efekty mohou modifikovat entity staty pomocí DefaultModifiers.EFFECT.

// com.hypixel.hytale.server.core.modules.entitystats.modifier.DefaultModifiers

public interface DefaultModifiers {
String EFFECT = "Effect"; // Modifikátor z efektů
String ARMOR = "Armor"; // Modifikátor z armor
String WEAPON_MODIFIER_PREFIX = "*Weapon_";
String UTILITY_MODIFIER_PREFIX = "*Utility_";
}

Zpracování stat změn

// V ActiveEntityEffect.tick()
private static void tickStatChanges(
CommandBuffer commandBuffer,
Ref ref,
EntityEffect entityEffect,
EntityStatMap entityStatMapComponent,
int cyclesToRun
) {
Int2FloatMap entityStats = entityEffect.getEntityStats();
if (entityStats != null && cyclesToRun > 0) {
// Vizuální efekty při změně statů
DamageEffects statModifierEffects = entityEffect.getStatModifierEffects();
if (statModifierEffects != null) {
statModifierEffects.spawnAtEntity(commandBuffer, ref);
}

// Aplikace stat změn
entityStatMapComponent.processStatChanges(
EntityStatMap.Predictable.ALL,
entityStats,
entityEffect.getValueType(),
ChangeStatBehaviour.Add
);
}
}

---

Damage z Efektů

Efekty mohou způsobovat periodický damage.

// V ActiveEntityEffect
private void tickDamage(
CommandBuffer commandBuffer,
Ref ref,
EntityEffect entityEffect,
int cyclesToRun
) {
DamageCalculator damageCalculator = entityEffect.getDamageCalculator();
if (damageCalculator != null && cyclesToRun > 0) {
Object2FloatMap relativeDamage =
damageCalculator.calculateDamage((double)this.initialDuration);

if (relativeDamage != null && !relativeDamage.isEmpty()) {
World world = commandBuffer.getExternalData().getWorld();
DamageEffects damageEffects = entityEffect.getDamageEffects();

Damage[] hits = DamageCalculatorSystems.queueDamageCalculator(
world, relativeDamage, ref, commandBuffer, this, null
);

for (Damage damageEvent : hits) {
DamageCalculatorSystems.DamageSequence damageSequence =
new DamageCalculatorSystems.DamageSequence(this.sequentialHits, damageCalculator);
damageEvent.putMetaObject(DamageCalculatorSystems.DAMAGE_SEQUENCE, damageSequence);

if (damageEffects != null) {
damageEffects.addToDamage(damageEvent);
}

commandBuffer.invoke(ref, damageEvent);
}
}
}
}

Death Message

// ActiveEntityEffect implementuje Damage.Source
@Override
public Message getDeathMessage(Damage info, Ref targetRef, ComponentAccessor componentAccessor) {
EntityEffect entityEffect = EntityEffect.getAssetMap().getAsset(this.entityEffectIndex);
Message damageCauseMessage;

if (entityEffect != null) {
String locale = entityEffect.getLocale();
String reason = locale != null ? locale : entityEffect.getId().toLowerCase(Locale.ROOT);
damageCauseMessage = Message.translation("server.general.damageCauses." + reason);
} else {
damageCauseMessage = Message.translation("server.general.damageCauses.unknown");
}

return Message.translation("server.general.killedBy")
.param("damageSource", damageCauseMessage);
}

---

Model Change

Efekty mohou změnit model entity.

// V EffectControllerComponent
public void setModelChange(
Ref ownerRef,
EntityEffect entityEffect,
int entityEffectIndex,
ComponentAccessor componentAccessor
) {
if (this.originalModel == null) {
if (entityEffect.getModelChange() != null) {
ModelComponent modelComponent = componentAccessor.getComponent(
ownerRef, ModelComponent.getComponentType()
);

// Uložení původního modelu
this.originalModel = modelComponent.getModel();
this.activeModelChangeEntityEffectIndex = entityEffectIndex;

// Nastavení nového modelu
ModelAsset modelAsset = ModelAsset.getAssetMap().getAsset(entityEffect.getModelChange());
Model scaledModel = Model.createRandomScaleModel(modelAsset);
componentAccessor.putComponent(
ownerRef,
ModelComponent.getComponentType(),
new ModelComponent(scaledModel)
);
}
}
}

// Reset při odstranění efektu
public void tryResetModelChange(Ref ownerRef, int activeEffectIndex, ComponentAccessor componentAccessor) {
if (this.originalModel != null && this.activeModelChangeEntityEffectIndex == activeEffectIndex) {
componentAccessor.putComponent(
ownerRef,
ModelComponent.getComponentType(),
new ModelComponent(this.originalModel)
);

// Reset player skin pokud existuje
PlayerSkinComponent playerSkinComponent = componentAccessor.getComponent(
ownerRef, PlayerSkinComponent.getComponentType()
);
if (playerSkinComponent != null) {
playerSkinComponent.setNetworkOutdated();
}

this.originalModel = null;
}
}

---

Speciální Efekty

Burn (oheň)

Burn efekt má speciální podmínku - je automaticky odstraněn když je entita ve vodě.

// V LivingEntityEffectSystem.canApplyEffect()
if ("Burn".equals(entityEffect.getId())) {
// Získání pozice a bounding boxu
Ref chunkRef = transformComponent.getChunkRef();
if (chunkRef != null && chunkRef.isValid()) {
LocalCachedChunkAccessor chunkAccessor = LocalCachedChunkAccessor.atChunkCoords(...);

// Kontrola všech bloků v bounding boxu
return boundingBox.forEachBlock(position, chunkAccessor, (x, y, z, _chunkAccessor) -> {
WorldChunk localChunk = _chunkAccessor.getChunkIfInMemory(...);
return localChunk == null ? true : !localChunk.getBlockType(x, y, z).getId().contains("Fluid_Water");
});
}
return false;
}

---

Shrnutí

| Třída | Účel |
|-------|------|
| EntityEffect | Asset definující efekt |
| ActiveEntityEffect | Aktivní instance efektu na entitě |
| EffectControllerComponent | Komponenta spravující všechny efekty |
| OverlapBehavior | Chování při překryvu efektů |
| RemovalBehavior | Chování při odebrání efektů |
| TargetEntityEffect | Konfigurace cílového efektu |

| Enum Hodnota | OverlapBehavior | Popis |
|--------------|-----------------|-------|
| EXTEND | Prodlouží | Přidá dobu trvání k existujícímu |
| OVERWRITE | Přepíše | Nahradí existující efekt |
| IGNORE | Ignoruje | Ponechá existující, nepřidá nový |

| Enum Hodnota | RemovalBehavior | Popis |
|--------------|-----------------|-------|
| COMPLETE | Kompletní | Úplně odstraní efekt |
| INFINITE | Infinite | Odstraní jen infinite flag |
| DURATION | Duration | Nastaví duration na 0 |

Last updated: 20. ledna 2026