From 47f0d9858b69c0064909dae69b72aed4cc5ae87a Mon Sep 17 00:00:00 2001 From: YoyoNow Date: Mon, 26 Oct 2026 09:34:05 +0100 Subject: [PATCH] Place lobby particle entries relative to the body Entries get a World/Body setting. In body mode offsets, heights and wings follow the body's facing and lie along the body while gliding or swimming, so wings stay on the back. Rings circle the body but keep their world angle, so they do not turn with the player. New wings default to body; presets and rewards stay in world mode and look exactly as before. --- .../de/steamwar/lobby/LobbySystem.properties | 3 + .../steamwar/lobby/LobbySystem_de.properties | 3 + .../de/steamwar/lobby/particle/BodyFrame.java | 95 +++++++++++++++++++ .../lobby/particle/ParticleTickData.java | 11 ++- .../src/de/steamwar/lobby/particle/TODOs.md | 1 + .../lobby/particle/design/Designs.java | 4 +- .../particle/design/EntryParameters.java | 9 +- .../lobby/particle/elements/BodyRelative.java | 37 ++++++++ .../lobby/particle/elements/Circle.java | 6 ++ .../lobby/particle/elements/DoubleCircle.java | 8 ++ .../particle/elements/LocationMutator.java | 11 +++ .../particle/elements/TrippleCircle.java | 9 ++ .../lobby/particle/elements/Wing.java | 12 +++ .../particle/elements/custom/YOffset.java | 6 +- .../lobby/particle/gui/EntryEditor.java | 3 +- .../lobby/particle/slot/ParticleEntry.java | 3 + .../steamwar/lobby/particle/slot/Presets.java | 3 +- 17 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/BodyFrame.java create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/TODOs.md create mode 100644 LobbySystem/src/de/steamwar/lobby/particle/elements/BodyRelative.java 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) {