20 KiB
title, type, weight
| title | type | weight |
|---|---|---|
| Particles | docs | 1 |
The particle system in Hytale provides rich visual effects through configurable emitters and renderers. Create explosions, trails, auras, and complex visual effects with precise control over behavior and appearance.
Package: com.hypixel.hytale.server.core.asset.type.particle
{{< cards cols="3" >}} {{< card link="#spawning-particles" title="Spawning" subtitle="Create particle effects" icon="sparkles" >}} {{< card link="#particle-system-configuration" title="Configuration" subtitle="System and spawner setup" icon="adjustments" >}} {{< card link="#particle-attractors" title="Attractors" subtitle="Forces and movement" icon="arrow-circle-right" >}} {{< /cards >}}
Spawning Particles
ParticleUtil Methods
{{< tabs items="Basic,Advanced,WorldParticle" >}} {{< tab >}}
import com.hypixel.hytale.server.core.universe.world.ParticleUtil;
// Basic spawn at position (auto-finds nearby players)
ParticleUtil.spawnParticleEffect(
"explosion_small", // Particle system ID
position, // Vector3d position
componentAccessor
);
// Spawn for specific players
ParticleUtil.spawnParticleEffect(
"magic_trail",
position,
playerRefs, // List<Ref<EntityStore>>
componentAccessor
);
Broadcast Distance: DEFAULT_PARTICLE_DISTANCE = 75 blocks
{{< /tab >}} {{< tab >}}
// With source entity reference
ParticleUtil.spawnParticleEffect(
"attack_swing",
position,
sourceEntityRef, // Entity that spawned this
playerRefs,
componentAccessor
);
// With rotation control
ParticleUtil.spawnParticleEffect(
"directional_beam",
position,
yaw, pitch, roll, // Rotation angles
sourceEntityRef,
playerRefs,
componentAccessor
);
// With scale and color
ParticleUtil.spawnParticleEffect(
"colored_burst",
position,
yaw, pitch, roll,
2.0f, // Scale multiplier
new Color(255, 100, 50, 255), // RGBA color
playerRefs,
componentAccessor
);
{{< /tab >}} {{< tab >}}
import com.hypixel.hytale.server.core.asset.type.particle.config.WorldParticle;
// Full control with WorldParticle wrapper
WorldParticle worldParticle = new WorldParticle(
"my_particle_system",
new Color(255, 100, 50, 255), // RGBA color override
1.5f, // Scale multiplier
new Vector3f(0, 1, 0), // Position offset
new Direction(0, 0, 0) // Rotation offset
);
ParticleUtil.spawnParticleEffect(
worldParticle,
position,
sourceRef,
playerRefs,
componentAccessor
);
{{< /tab >}} {{< /tabs >}}
Particle System Configuration
ParticleSystem Class
The root configuration for a particle effect:
public class ParticleSystem {
protected String id; // Unique identifier
protected ParticleSpawnerGroup[] spawners; // Spawner configurations
protected float lifeSpan; // System lifetime (seconds)
protected float cullDistance; // Distance before culling
protected float boundingRadius; // Collision bounding box
protected boolean isImportant; // Network priority flag
}
| Field | Type | Description |
|---|---|---|
id |
String | Unique identifier for the particle system |
spawners |
ParticleSpawnerGroup[] | Array of spawner configurations |
lifeSpan |
float | How long the system lives (seconds) |
cullDistance |
float | Distance at which particles are culled |
boundingRadius |
float | Bounding sphere for culling calculations |
isImportant |
boolean | If true, prioritized in network sync |
ParticleSpawner Configuration
Controls how individual particles are emitted:
{{< tabs items="Properties,Emission,Movement,Rendering" >}} {{< tab >}}
public class ParticleSpawner {
protected String id;
protected EmitShape shape;
protected RangeVector3f emitOffset;
protected boolean useEmitDirection;
protected Range totalParticles;
protected float lifeSpan;
protected int maxConcurrentParticles;
protected Rangef particleLifeSpan;
protected Rangef spawnRate;
protected boolean spawnBurst;
protected InitialVelocity initialVelocity;
protected ParticleAttractor[] attractors;
protected FXRenderMode renderMode;
protected float lightInfluence;
protected Particle particle;
}
{{< /tab >}} {{< tab >}}
Emission Properties:
| Property | Type | Description |
|---|---|---|
shape |
EmitShape | Sphere or Cube emission shape |
emitOffset |
RangeVector3f | Random offset range from origin |
useEmitDirection |
boolean | Use spawn direction for velocity |
totalParticles |
Range | Min/max total particles to emit |
spawnRate |
Rangef | Particles per second |
spawnBurst |
boolean | Emit all at once vs over time |
Example emission setup:
// Burst explosion - all at once
spawner.setSpawnBurst(true);
spawner.setTotalParticles(new Range(50, 100));
// Continuous stream
spawner.setSpawnBurst(false);
spawner.setSpawnRate(new Rangef(10, 20)); // 10-20 per second
spawner.setLifeSpan(5.0f); // Emit for 5 seconds
{{< /tab >}} {{< tab >}}
Movement Properties:
| Property | Type | Description |
|---|---|---|
initialVelocity |
InitialVelocity | Starting velocity configuration |
attractors |
ParticleAttractor[] | Forces applied to particles |
Initial Velocity:
public class InitialVelocity {
protected float speed; // Base speed
protected float speedVariance; // Random variance
protected Vector3f direction; // Base direction
protected float coneAngle; // Spread angle (degrees)
}
{{< /tab >}} {{< tab >}}
Rendering Properties:
| Property | Type | Description |
|---|---|---|
renderMode |
FXRenderMode | How particles are blended |
lightInfluence |
float | How much lighting affects particles |
particle |
Particle | Texture and animation config |
{{< /tab >}} {{< /tabs >}}
Emit Shapes
Control the volume from which particles spawn:
public enum EmitShape {
Sphere, // Emit from spherical volume
Cube // Emit from cubic volume
}
{{< tabs items="Sphere,Cube" >}} {{< tab >}}
Spherical Emission:
Particles spawn within a spherical volume, with direction pointing outward from center:
// Configure spherical emission
spawner.setShape(EmitShape.Sphere);
spawner.setEmitOffset(new RangeVector3f(
new Rangef(-1, 1), // X range (radius)
new Rangef(-1, 1), // Y range (radius)
new Rangef(-1, 1) // Z range (radius)
));
// Use emit direction for outward velocity
spawner.setUseEmitDirection(true);
Best for: Explosions, bursts, radial effects
{{< /tab >}} {{< tab >}}
Cubic Emission:
Particles spawn within an axis-aligned box volume:
// Configure cubic emission
spawner.setShape(EmitShape.Cube);
spawner.setEmitOffset(new RangeVector3f(
new Rangef(-2, 2), // X range
new Rangef(0, 3), // Y range (above ground)
new Rangef(-2, 2) // Z range
));
Best for: Area effects, rain, ground effects
{{< /tab >}} {{< /tabs >}}
Render Modes
Determine how particles blend with the scene:
public enum FXRenderMode {
BlendLinear, // Standard transparency blending
BlendAdd, // Additive blending (bright/glowing)
Erosion, // Erosion/dissolve effect
Distortion // Distortion/refraction effect
}
{{< tabs items="BlendLinear,BlendAdd,Erosion,Distortion" >}} {{< tab >}}
BlendLinear
Standard alpha blending. Best for:
- Smoke
- Dust
- Clouds
- Solid-looking particles
spawner.setRenderMode(FXRenderMode.BlendLinear);
{{< /tab >}} {{< tab >}}
BlendAdd
Additive blending - particles add light to the scene. Best for:
- Fire
- Sparks
- Magic effects
- Glowing particles
- Light beams
spawner.setRenderMode(FXRenderMode.BlendAdd);
{{< callout type="info" >}}
Use BlendAdd for any glowing or luminous effects. Multiple overlapping particles will create brighter spots.
{{< /callout >}}
{{< /tab >}} {{< tab >}}
Erosion
Creates dissolving/eroding visual effect. Best for:
- Disintegration
- Dissolve transitions
- Energy dissipation
spawner.setRenderMode(FXRenderMode.Erosion);
{{< /tab >}} {{< tab >}}
Distortion
Refracts the background, creating heat-shimmer effects. Best for:
- Heat waves
- Portals
- Energy fields
- Underwater effects
spawner.setRenderMode(FXRenderMode.Distortion);
{{< callout type="warning" >}} Distortion effects are more GPU-intensive. Use sparingly. {{< /callout >}}
{{< /tab >}} {{< /tabs >}}
Particle Attractors
Apply forces to particles for dynamic movement:
public class ParticleAttractor {
protected Vector3f position; // Local attractor position
protected Vector3f radialAxis; // Radial force direction
protected float radius; // Influence radius
// Accelerations (continuous forces)
protected float radialAcceleration; // Outward/inward acceleration
protected float radialTangentAcceleration; // Tangential (orbit) acceleration
protected Vector3f linearAcceleration; // Direct linear acceleration
// Impulses (one-time forces)
protected float radialImpulse; // Outward/inward impulse
protected float radialTangentImpulse; // Tangential impulse
protected Vector3f linearImpulse; // Direct linear impulse
// Damping
protected Vector3f dampingMultiplier; // Velocity reduction per frame
}
Force Types
{{< tabs items="Radial,Tangential,Linear,Damping" >}} {{< tab >}}
Radial Forces:
Push particles toward or away from the attractor position:
ParticleAttractor attractor = new ParticleAttractor();
attractor.setPosition(new Vector3f(0, 0, 0)); // Center of system
// Outward explosion
attractor.setRadialAcceleration(10.0f); // Positive = outward
// Inward pull (black hole effect)
attractor.setRadialAcceleration(-5.0f); // Negative = inward
// Instant outward burst
attractor.setRadialImpulse(20.0f);
{{< /tab >}} {{< tab >}}
Tangential Forces:
Create swirling/orbiting motion around the attractor:
ParticleAttractor attractor = new ParticleAttractor();
attractor.setPosition(new Vector3f(0, 0, 0));
attractor.setRadialAxis(new Vector3f(0, 1, 0)); // Orbit around Y axis
// Clockwise swirl
attractor.setRadialTangentAcceleration(5.0f);
// Counter-clockwise
attractor.setRadialTangentAcceleration(-5.0f);
{{< /tab >}} {{< tab >}}
Linear Forces:
Apply constant directional force (like gravity or wind):
ParticleAttractor attractor = new ParticleAttractor();
// Gravity (downward)
attractor.setLinearAcceleration(new Vector3f(0, -9.8f, 0));
// Wind (horizontal)
attractor.setLinearAcceleration(new Vector3f(2.0f, 0, 0));
// Upward buoyancy
attractor.setLinearAcceleration(new Vector3f(0, 3.0f, 0));
{{< /tab >}} {{< tab >}}
Damping:
Slow particles down over time:
ParticleAttractor attractor = new ParticleAttractor();
// Uniform damping (air resistance)
attractor.setDampingMultiplier(new Vector3f(0.98f, 0.98f, 0.98f));
// Strong horizontal damping, weak vertical
attractor.setDampingMultiplier(new Vector3f(0.9f, 0.99f, 0.9f));
// No damping (particles maintain velocity)
attractor.setDampingMultiplier(new Vector3f(1.0f, 1.0f, 1.0f));
{{< callout type="info" >}} Damping values < 1.0 slow particles. Values of 0.98-0.99 give realistic air resistance. {{< /callout >}}
{{< /tab >}} {{< /tabs >}}
Particle Visual Configuration
Configure particle appearance and animation:
public class Particle {
protected String texture; // Texture atlas path
protected Size frameSize; // Frame dimensions
protected ParticleUVOption uvOption; // None, Animated, Random
protected SoftParticle softParticle; // Soft particle blending
protected float softParticlesFadeFactor; // 0.1 to 2.0
// Animation
protected ParticleAnimationFrame initialAnimationFrame;
protected Map<Integer, ParticleAnimationFrame> animation;
}
Animation Options
public enum ParticleUVOption {
None, // Single static frame
Animated, // Play through frames in sequence
Random // Random frame per particle
}
Animation Frames
public class ParticleAnimationFrame {
protected int frame; // Frame number in atlas
protected Rangef scale; // Size range
protected Rangef alpha; // Transparency range (0-1)
protected Color color; // Color tint
protected Rangef rotation; // Rotation range (degrees)
}
Accessing Particle Assets
// Get particle system by ID
ParticleSystem system = ParticleSystem.getAssetMap().getAsset("explosion_large");
// Get spawner configuration
ParticleSpawner spawner = ParticleSpawner.getAssetMap().getAsset("fire_spawner");
// Use in command arguments
// ArgTypes.PARTICLE_SYSTEM for command parameters
Common Patterns
Event-Based Particles
{{< callout type="warning" >}}
Note: The examples below are simplified. Entity doesn't have a direct getPosition() method. In real code, obtain position via TransformComponent from the entity's store. Example:
TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType());
Vector3d position = transform.getPosition();
{{< /callout >}}
{{< tabs items="Block Break,Combat,Death" >}} {{< tab >}}
@Subscribe
public void onBlockBreak(BreakBlockEvent event) {
// Use getTargetBlock() - not getPosition()
Vector3i blockPos = event.getTargetBlock();
Vector3d pos = new Vector3d(
blockPos.x + 0.5,
blockPos.y + 0.5,
blockPos.z + 0.5
);
// Spawn break particles at block center
ParticleUtil.spawnParticleEffect(
"block_break_particles",
pos,
componentAccessor
);
}
{{< /tab >}} {{< tab >}}
@Subscribe
public void onEntityDamage(EntityDamageEvent event) {
Entity target = event.getTarget();
Vector3d hitPos = target.getPosition().add(0, 1, 0);
// Blood/damage effect
ParticleUtil.spawnParticleEffect(
"damage_hit",
hitPos,
componentAccessor
);
// Critical hit special effect
if (event.isCritical()) {
ParticleUtil.spawnParticleEffect(
"critical_hit_sparks",
hitPos,
0, 0, 0, // rotation
1.5f, // larger scale
new Color(255, 215, 0, 255), // gold color
getNearbyPlayers(hitPos, 50),
componentAccessor
);
}
}
{{< /tab >}} {{< tab >}}
@Subscribe
public void onEntityDeath(EntityDeathEvent event) {
Entity entity = event.getEntity();
Vector3d deathPos = entity.getPosition();
// Death particles
ParticleUtil.spawnParticleEffect(
"entity_death_poof",
deathPos,
componentAccessor
);
// Soul rising effect for players
if (entity instanceof Player) {
ParticleUtil.spawnParticleEffect(
"soul_ascend",
deathPos.add(0, 0.5, 0),
componentAccessor
);
}
}
{{< /tab >}} {{< /tabs >}}
Continuous Effects
{{< tabs items="Player Trail,Aura,Area Effect" >}} {{< tab >}}
// Spawn particle trail at player position
public void spawnTrailEffect(Player player, Store<EntityStore> store,
ComponentAccessor<EntityStore> componentAccessor) {
if (hasTrailEffect(player)) {
// Get position from TransformComponent
Ref<EntityStore> entityRef = player.getReference();
TransformComponent transform = store.getComponent(entityRef, TransformComponent.getComponentType());
if (transform != null) {
Vector3d position = transform.getPosition();
ParticleUtil.spawnParticleEffect(
"magic_trail",
position,
componentAccessor
);
}
}
}
{{< callout type="warning" >}}
Note: Player doesn't have a getPosition() method. Get position via TransformComponent from the entity store.
{{< /callout >}}
{{< /tab >}} {{< tab >}}
// Persistent aura around player
public class AuraManager {
private final Map<UUID, Boolean> activeAuras = new HashMap<>();
private Store<EntityStore> store;
private ComponentAccessor<EntityStore> componentAccessor;
public void enableAura(Player player) {
// Use player.getPlayerRef().getUuid() - not player.getUuid()
activeAuras.put(player.getPlayerRef().getUuid(), true);
}
@Subscribe
public void onTick(ServerTickEvent event) {
for (Map.Entry<UUID, Boolean> entry : activeAuras.entrySet()) {
if (entry.getValue()) {
Player player = getPlayer(entry.getKey());
if (player != null) {
// Get position from TransformComponent
Ref<EntityStore> entityRef = player.getReference();
TransformComponent transform = store.getComponent(
entityRef, TransformComponent.getComponentType());
if (transform != null) {
Vector3d pos = transform.getPosition();
ParticleUtil.spawnParticleEffect(
"magic_aura",
new Vector3d(pos.getX(), pos.getY() + 1, pos.getZ()),
componentAccessor
);
}
}
}
}
}
}
{{< /tab >}} {{< tab >}}
// Area healing effect
public void createHealingZone(Vector3d center, double radius, int durationTicks) {
// Spawn ring particles
for (int i = 0; i < 16; i++) {
double angle = (2 * Math.PI * i) / 16;
Vector3d pos = center.add(
Math.cos(angle) * radius,
0.1,
Math.sin(angle) * radius
);
ParticleUtil.spawnParticleEffect(
"healing_sparkle",
pos,
componentAccessor
);
}
// Central pillar effect
ParticleUtil.spawnParticleEffect(
"healing_pillar",
center,
componentAccessor
);
}
{{< /tab >}} {{< /tabs >}}
Performance Guidelines
{{< callout type="warning" >}} Performance Notes:
- Default broadcast distance: 75 blocks (
DEFAULT_PARTICLE_DISTANCE) - Particles use
SpawnParticleSystempacket (ID: 152) - Set
isImportant = truefor critical visual feedback - Limit particle count for client performance
- Use
maxConcurrentParticlesto cap active particles {{< /callout >}}
Optimization Tips
| Tip | Description |
|---|---|
| Limit total particles | Keep under 100-200 for burst effects |
Use appropriate cullDistance |
Don't render particles too far away |
| Batch spawns | Spawn multiple particles in same tick |
Use spawnBurst wisely |
Bursts are cheaper than continuous |
| Consider player count | More players = more network traffic |
// Good: Efficient particle spawning
public void spawnEfficiently(Vector3d position) {
// Only spawn for nearby players
List<PlayerRef> nearbyPlayers = getNearbyPlayers(position, 50);
if (!nearbyPlayers.isEmpty()) {
ParticleUtil.spawnParticleEffect(
"my_effect",
position,
nearbyPlayers, // Limited audience
componentAccessor
);
}
}
Related Topics
- [Entity Effects]({{< relref "entity-effects" >}}) - Status effects with visual components
- [Networking]({{< relref "/advanced/networking" >}}) - How particles are broadcast
- [Events]({{< relref "/core-concepts/events" >}}) - Triggering particles from events