diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties index 5e419fc3..e691bbf9 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem.properties @@ -142,6 +142,7 @@ PARTICLE_PARAM_OFFSET_X = §fOffset X PARTICLE_PARAM_OFFSET_Y = §fOffset Y PARTICLE_PARAM_OFFSET_Z = §fOffset Z PARTICLE_PARAM_INTERVAL = §fEvery n ticks +PARTICLE_PARAM_PLACEMENT = §fRelative to PARTICLE_PARAM_TICK_MODE = §fShown PARTICLE_PARAM_MOVEMENT = §fMovement PARTICLE_PARAM_GLIDING = §fElytra @@ -160,6 +161,8 @@ PARTICLE_PARAM_WING_SIZE = §fWing size PARTICLE_CHOICE_TICKMODE_MOVE = §fWhile moving PARTICLE_CHOICE_TICKMODE_ALWAYS = §fAlways +PARTICLE_CHOICE_PLACEMENT_WORLD = §fWorld (X east, Y up, Z south) +PARTICLE_CHOICE_PLACEMENT_BODY = §fBody (X right, Y up, Z forward) PARTICLE_CHOICE_MOVEMENT_ANY = §fAny movement PARTICLE_CHOICE_MOVEMENT_MOVING = §fOnly while moving PARTICLE_CHOICE_MOVEMENT_STANDING_STILL = §fOnly while standing still diff --git a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties index df313e50..146f66c1 100644 --- a/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties +++ b/LobbySystem/src/de/steamwar/lobby/LobbySystem_de.properties @@ -142,6 +142,7 @@ PARTICLE_PARAM_OFFSET_X = §fVersatz X PARTICLE_PARAM_OFFSET_Y = §fVersatz Y PARTICLE_PARAM_OFFSET_Z = §fVersatz Z PARTICLE_PARAM_INTERVAL = §fAlle n Ticks +PARTICLE_PARAM_PLACEMENT = §fAusgerichtet an PARTICLE_PARAM_TICK_MODE = §fAnzeige PARTICLE_PARAM_MOVEMENT = §fBewegung PARTICLE_PARAM_GLIDING = §fElytra @@ -160,6 +161,8 @@ PARTICLE_PARAM_WING_SIZE = §fFlügelgröße PARTICLE_CHOICE_TICKMODE_MOVE = §fBeim Bewegen PARTICLE_CHOICE_TICKMODE_ALWAYS = §fImmer +PARTICLE_CHOICE_PLACEMENT_WORLD = §fWelt (X Osten, Y oben, Z Süden) +PARTICLE_CHOICE_PLACEMENT_BODY = §fKörper (X rechts, Y oben, Z vorne) PARTICLE_CHOICE_MOVEMENT_ANY = §fJede Bewegung PARTICLE_CHOICE_MOVEMENT_MOVING = §fNur beim Bewegen PARTICLE_CHOICE_MOVEMENT_STANDING_STILL = §fNur beim Stehen diff --git a/LobbySystem/src/de/steamwar/lobby/particle/BodyFrame.java b/LobbySystem/src/de/steamwar/lobby/particle/BodyFrame.java new file mode 100644 index 00000000..68c5de0d --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/BodyFrame.java @@ -0,0 +1,95 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.lobby.particle; + +import lombok.Getter; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.entity.Pose; +import org.bukkit.util.Vector; + +// The player's body as a coordinate system: origin at the feet, up towards the head, forward out of the chest. +// Standing it turns with the body; gliding or swimming the body lies along the look direction. +@Getter +public class BodyFrame { + + private static final Vector WORLD_UP = new Vector(0, 1, 0); + private static final double HALF_BODY = 0.9; + + private final Location origin; + private final Vector right; + private final Vector up; + private final Vector forward; + // Reference directions of rings around the body; they do not turn with the body + private final Vector ringStart; + private final Vector ringSide; + + private BodyFrame(Location origin, Vector right, Vector up, Vector forward) { + this.origin = origin; + this.right = right; + this.up = up; + this.forward = forward; + + // World east projected onto the plane around the body, so a standing ring matches the world ring + Vector start = new Vector(1, 0, 0).subtract(up.clone().multiply(up.getX())); + if (start.lengthSquared() < 1e-6) { + start = new Vector(0, 0, 1).subtract(up.clone().multiply(up.getZ())); + } + this.ringStart = start.normalize(); + this.ringSide = up.clone().crossProduct(ringStart); + } + + public static BodyFrame of(Player player) { + Location location = player.getLocation(); + Pose pose = player.getPose(); + if (pose == Pose.FALL_FLYING || pose == Pose.SWIMMING) { + Vector up = location.getDirection().normalize(); + Vector right = up.clone().crossProduct(WORLD_UP); + if (right.lengthSquared() < 1e-6) { + right = horizontal(player.getBodyYaw()).crossProduct(WORLD_UP); + } + right.normalize(); + Vector forward = up.clone().crossProduct(right).normalize(); + // The lying body is centred in its short hitbox, its feet lie behind the centre + Location origin = location.clone().add(0, player.getHeight() / 2, 0).subtract(up.clone().multiply(HALF_BODY)); + return new BodyFrame(origin, right, up, forward); + } + + Vector forward = horizontal(player.getBodyYaw()); + Vector right = forward.clone().crossProduct(WORLD_UP).normalize(); + return new BodyFrame(location, right, WORLD_UP.clone(), forward); + } + + private static Vector horizontal(float yaw) { + double radians = Math.toRadians(yaw); + return new Vector(-Math.sin(radians), 0, Math.cos(radians)); + } + + public Vector local(double right, double up, double forward) { + return this.right.clone().multiply(right) + .add(this.up.clone().multiply(up)) + .add(this.forward.clone().multiply(forward)); + } + + // A point on a ring around the up axis; angle 0 and the turning direction match the world rings + public Vector ring(double distance, double angle) { + return ringStart.clone().multiply(Math.cos(angle) * distance).add(ringSide.clone().multiply(Math.sin(angle) * distance)); + } +} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/ParticleTickData.java b/LobbySystem/src/de/steamwar/lobby/particle/ParticleTickData.java index f5f7cb37..569af6fa 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/ParticleTickData.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/ParticleTickData.java @@ -41,6 +41,8 @@ public class ParticleTickData { private final List viewers; private boolean onlySelf = false; private boolean onlyOthers = false; + // Set for entries placed relative to the body, null for world placement + private BodyFrame frame; public ParticleTickData withLocation(Location location) { ParticleTickData particleTickData = copy(); @@ -48,6 +50,13 @@ public class ParticleTickData { return particleTickData; } + public ParticleTickData withFrame(BodyFrame frame) { + ParticleTickData particleTickData = copy(); + particleTickData.frame = frame; + particleTickData.location = frame.getOrigin().clone(); + return particleTickData; + } + public ParticleTickData onlySelf() { ParticleTickData particleTickData = copy(); particleTickData.onlySelf = true; @@ -68,6 +77,6 @@ public class ParticleTickData { } public ParticleTickData copy() { - return new ParticleTickData(world, player, location, deg, isMoving, viewers, onlySelf, onlyOthers); + return new ParticleTickData(world, player, location, deg, isMoving, viewers, onlySelf, onlyOthers, frame); } } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/TODOs.md b/LobbySystem/src/de/steamwar/lobby/particle/TODOs.md new file mode 100644 index 00000000..823a020f --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/TODOs.md @@ -0,0 +1 @@ +Relative zur rotation den spielers und co \ No newline at end of file diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java index cfa4a419..4210da24 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/Designs.java @@ -94,14 +94,14 @@ public class Designs { return values.get(WING_IMAGE).getVectors().length; } - // Wings spawn a particle on every pixel of the image, so they start sparse + // Wings spawn a particle on every pixel of the image, so they start sparse, and sit on the back even while gliding @Override public void applyDefaults(ParameterValues values) { values.set(EntryParameters.COUNT, 1) .set(EntryParameters.SPEED, 0.0) .set(EntryParameters.TICK_MODE, EntryParameters.TickMode.ALWAYS) .set(EntryParameters.INTERVAL, 20) - .set(EntryParameters.GLIDING, EntryParameters.Gliding.NOT_GLIDING); + .set(EntryParameters.PLACEMENT, EntryParameters.Placement.BODY); } }; diff --git a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java index 8a3f7f65..69e73263 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/design/EntryParameters.java @@ -37,6 +37,12 @@ public class EntryParameters { ALWAYS, } + // Body places offsets, heights, rings and wings around the player's body, even while gliding or swimming + public enum Placement { + WORLD, + BODY, + } + public enum Movement { ANY(element -> element), MOVING(element -> data -> { @@ -183,6 +189,7 @@ public class EntryParameters { public final DoubleParameter OFFSET_Y = new DoubleParameter("offsetY", "PARTICLE_PARAM_OFFSET_Y", 0, -3, 3, 0.1); public final DoubleParameter OFFSET_Z = new DoubleParameter("offsetZ", "PARTICLE_PARAM_OFFSET_Z", 0, -3, 3, 0.1); public final IntParameter INTERVAL = new IntParameter("interval", "PARTICLE_PARAM_INTERVAL", 1, 1, 100); + public final ChoiceParameter PLACEMENT = ChoiceParameter.ofEnum("placement", "PARTICLE_PARAM_PLACEMENT", Placement.WORLD); public final ChoiceParameter TICK_MODE = ChoiceParameter.ofEnum("tickMode", "PARTICLE_PARAM_TICK_MODE", TickMode.MOVE); public final ChoiceParameter MOVEMENT = ChoiceParameter.ofEnum("movement", "PARTICLE_PARAM_MOVEMENT", Movement.ANY); public final ChoiceParameter GLIDING = ChoiceParameter.ofEnum("gliding", "PARTICLE_PARAM_GLIDING", Gliding.ANY); @@ -192,7 +199,7 @@ public class EntryParameters { public final List> ALL = List.of( PARTICLE, COUNT, SPREAD_X, SPREAD_Y, SPREAD_Z, SPEED, COLORS, BLOCK, - OFFSET_X, OFFSET_Y, OFFSET_Z, INTERVAL, TICK_MODE, + OFFSET_X, OFFSET_Y, OFFSET_Z, PLACEMENT, INTERVAL, TICK_MODE, MOVEMENT, GLIDING, GROUND, SNEAK, VISIBILITY ); } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/BodyRelative.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/BodyRelative.java new file mode 100644 index 00000000..3b623a54 --- /dev/null +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/BodyRelative.java @@ -0,0 +1,37 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2026 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.lobby.particle.elements; + +import de.steamwar.lobby.particle.BodyFrame; +import de.steamwar.lobby.particle.ParticleElement; +import de.steamwar.lobby.particle.ParticleTickData; + +// Places everything inside relative to the player's body instead of the world +public class BodyRelative extends DelegatingParticleElement { + + public BodyRelative(ParticleElement particleElement) { + super(particleElement); + } + + @Override + public void tick(ParticleTickData particleTickData) { + particleElement.tick(particleTickData.withFrame(BodyFrame.of(particleTickData.getPlayer()))); + } +} diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/Circle.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/Circle.java index e95af976..4dfb7d8e 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/Circle.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/Circle.java @@ -19,6 +19,7 @@ package de.steamwar.lobby.particle.elements; +import de.steamwar.lobby.particle.BodyFrame; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleTickData; import org.bukkit.Location; @@ -50,6 +51,11 @@ public class Circle extends DelegatingParticleElement { @Override public void tick(ParticleTickData particleTickData) { Location location = particleTickData.getLocation(); + BodyFrame frame = particleTickData.getFrame(); + if (frame != null) { + particleElement.tick(particleTickData.withLocation(location.clone().add(frame.ring(distance, (particleTickData.getDeg() * speed) % 360 + phase)))); + return; + } Vector vector = new Vector(distance, 0, 0); vector.rotateAroundY((particleTickData.getDeg() * speed) % 360 + phase); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/DoubleCircle.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/DoubleCircle.java index 117fb2a6..b594527e 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/DoubleCircle.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/DoubleCircle.java @@ -19,6 +19,7 @@ package de.steamwar.lobby.particle.elements; +import de.steamwar.lobby.particle.BodyFrame; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleTickData; import de.steamwar.lobby.particle.ParticleTickType; @@ -57,6 +58,13 @@ public class DoubleCircle extends Circle { @Override public void tick(ParticleTickData particleTickData) { Location location = particleTickData.getLocation(); + BodyFrame frame = particleTickData.getFrame(); + if (frame != null) { + double angle = (particleTickData.getDeg() * speed) % 360; + particleElement.tick(particleTickData.withLocation(location.clone().add(frame.ring(distance, angle)))); + second.tick(particleTickData.withLocation(location.clone().add(frame.ring(distance, angle + Math.PI)))); + return; + } Vector vector = new Vector(distance, 0, 0); vector.rotateAroundY((particleTickData.getDeg() * speed) % 360); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/LocationMutator.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/LocationMutator.java index b83ecf0f..1b62071f 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/LocationMutator.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/LocationMutator.java @@ -19,15 +19,19 @@ package de.steamwar.lobby.particle.elements; +import de.steamwar.lobby.particle.BodyFrame; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleTickData; import org.bukkit.Location; +import org.bukkit.util.Vector; import java.util.function.UnaryOperator; public class LocationMutator extends DelegatingParticleElement { private UnaryOperator mutator; + // Set for plain offsets, which turn into right/up/forward when placed relative to the body + private Vector offset; public LocationMutator(ParticleElement particleElement, UnaryOperator mutator) { super(particleElement); @@ -36,10 +40,17 @@ public class LocationMutator extends DelegatingParticleElement { public LocationMutator(ParticleElement particleElement, double vx, double vy, double vz) { this(particleElement, location -> location.add(vx, vy, vz)); + this.offset = new Vector(vx, vy, vz); } @Override public void tick(ParticleTickData particleTickData) { + BodyFrame frame = particleTickData.getFrame(); + if (frame != null && offset != null) { + Location location = particleTickData.getLocation().clone().add(frame.local(offset.getX(), offset.getY(), offset.getZ())); + particleElement.tick(particleTickData.withLocation(location)); + return; + } ParticleTickData nParticleTickData = particleTickData.withLocation(mutator.apply(particleTickData.getLocation())); particleElement.tick(nParticleTickData); } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/TrippleCircle.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/TrippleCircle.java index 39425c1e..75019032 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/TrippleCircle.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/TrippleCircle.java @@ -19,6 +19,7 @@ package de.steamwar.lobby.particle.elements; +import de.steamwar.lobby.particle.BodyFrame; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleTickData; import de.steamwar.lobby.particle.ParticleTickType; @@ -59,6 +60,14 @@ public class TrippleCircle extends Circle { @Override public void tick(ParticleTickData particleTickData) { Location location = particleTickData.getLocation(); + BodyFrame frame = particleTickData.getFrame(); + if (frame != null) { + double angle = (particleTickData.getDeg() * speed) % 360; + particleElement.tick(particleTickData.withLocation(location.clone().add(frame.ring(distance, angle)))); + second.tick(particleTickData.withLocation(location.clone().add(frame.ring(distance, angle + Math.toRadians(120))))); + third.tick(particleTickData.withLocation(location.clone().add(frame.ring(distance, angle + Math.toRadians(240))))); + return; + } Vector vector = new Vector(distance, 0, 0); vector.rotateAroundY((particleTickData.getDeg() * speed) % 360); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java index 1c8f1322..7c9e9d8d 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/Wing.java @@ -19,6 +19,7 @@ package de.steamwar.lobby.particle.elements; +import de.steamwar.lobby.particle.BodyFrame; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleTickData; import de.steamwar.lobby.particle.WingDesign; @@ -38,6 +39,17 @@ public class Wing extends DelegatingParticleElement { @Override public void tick(ParticleTickData particleTickData) { + BodyFrame frame = particleTickData.getFrame(); + if (frame != null) { + // Half a block behind the back, so the wings stay on the back even while gliding + double sneak = particleTickData.getPlayer().isSneaking() ? 0.5 : 0; + Location base = particleTickData.getLocation(); + for (Vector dVector : wingDesign.getVectors()) { + Vector local = frame.local(dVector.getX() * size, 0.6 + dVector.getY() * size - sneak, -0.5); + particleElement.tick(particleTickData.withLocation(base.clone().add(local))); + } + return; + } for (Vector dVector : wingDesign.getVectors()) { Vector vector = new Vector(dVector.getX() * size, 0.6 + dVector.getY() * size - (particleTickData.getPlayer().isSneaking() ? 0.5 : 0), 0.5); vector.rotateAroundY(Math.toRadians(particleTickData.getPlayer().getLocation().getYaw() * -1)); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/elements/custom/YOffset.java b/LobbySystem/src/de/steamwar/lobby/particle/elements/custom/YOffset.java index 15375522..09f36493 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/elements/custom/YOffset.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/elements/custom/YOffset.java @@ -19,9 +19,11 @@ package de.steamwar.lobby.particle.elements.custom; +import de.steamwar.lobby.particle.BodyFrame; import de.steamwar.lobby.particle.ParticleElement; import de.steamwar.lobby.particle.ParticleTickData; import de.steamwar.lobby.particle.elements.DelegatingParticleElement; +import org.bukkit.Location; public class YOffset extends DelegatingParticleElement { @@ -66,7 +68,9 @@ public class YOffset extends DelegatingParticleElement { y = minY + (maxY - minY) * value; } } - ParticleTickData current = particleTickData.withLocation(particleTickData.getLocation().clone().add(0, y, 0)); + BodyFrame frame = particleTickData.getFrame(); + Location location = particleTickData.getLocation().clone(); + ParticleTickData current = particleTickData.withLocation(frame == null ? location.add(0, y, 0) : location.add(frame.getUp().clone().multiply(y))); particleElement.tick(current); } } diff --git a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java index 5dd3d5ba..9eb99fe2 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/gui/EntryEditor.java @@ -67,6 +67,7 @@ class EntryEditor { Map.entry(OFFSET_Z, Material.SPECTRAL_ARROW), Map.entry(INTERVAL, Material.CLOCK), Map.entry(TICK_MODE, Material.REPEATER), + Map.entry(PLACEMENT, Material.PLAYER_HEAD), Map.entry(MOVEMENT, Material.LEATHER_BOOTS), Map.entry(GLIDING, Material.ELYTRA), Map.entry(GROUND, Material.GRASS_BLOCK), @@ -122,7 +123,7 @@ class EntryEditor { })); } row(inventory, context, ROW_SHAPE, design.getParameters()); - row(inventory, context, ROW_TIMING, List.of(TICK_MODE, INTERVAL, OFFSET_X, OFFSET_Y, OFFSET_Z)); + row(inventory, context, ROW_TIMING, List.of(TICK_MODE, INTERVAL, PLACEMENT, OFFSET_X, OFFSET_Y, OFFSET_Z)); row(inventory, context, ROW_CONDITIONS, List.of(MOVEMENT, GLIDING, GROUND, SNEAK, VISIBILITY)); inventory.setItem(BACK, new SWItem(Material.ARROW, msg("PARTICLE_BACK", player), clickType -> SlotEditor.open(player, index))); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java index d1c3ba04..f41cebd1 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/slot/ParticleEntry.java @@ -79,6 +79,9 @@ public class ParticleEntry { element = withOffset(design.build(values, null)); } + if (values.get(PLACEMENT) == Placement.BODY) { + element = new BodyRelative(element); + } element = values.get(MOVEMENT).wrap(element); element = values.get(GLIDING).wrap(element); element = values.get(GROUND).wrap(element); diff --git a/LobbySystem/src/de/steamwar/lobby/particle/slot/Presets.java b/LobbySystem/src/de/steamwar/lobby/particle/slot/Presets.java index 3a025539..413b9103 100644 --- a/LobbySystem/src/de/steamwar/lobby/particle/slot/Presets.java +++ b/LobbySystem/src/de/steamwar/lobby/particle/slot/Presets.java @@ -122,7 +122,8 @@ public class Presets { .with(Designs.WING_SIZE, size) .with(TICK_MODE, TickMode.ALWAYS) .with(INTERVAL, interval) - .with(GLIDING, Gliding.NOT_GLIDING); + .with(GLIDING, Gliding.NOT_GLIDING) + .with(PLACEMENT, Placement.WORLD); } private ParticleEntry dustWing(Color color, WingDesign image) {