Skip to content

Commit 307b3fa

Browse files
committed
fix(game): reset rings and score on landing, sync isFlying from player.isGliding()
- ElytraPhysicsSystem now syncs flight.setFlying(player.isGliding()) every tick so landing is detected correctly (previously setFlying(false) was never called) - New LandingResetSystem: on flying→notFlying transition for unfinished players, resets RingTrackerComponent + ScoreComponent and clears the actionbar (runs after ElytraPhysicsSystem, before ScoreDisplaySystem) - ScoreDisplaySystem clears its tick/hash cache when not flying so the next takeoff renders the HUD immediately without a stale-hash delay - HudComponent.clearActionbar() sends Component.empty() to dismiss the last message
1 parent 76a74d5 commit 307b3fa

5 files changed

Lines changed: 79 additions & 2 deletions

File tree

server/src/main/java/net/elytrarace/server/ecs/component/HudComponent.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@ public void showRingPassed(int passed, int total) {
157157
1.5f));
158158
}
159159

160+
/** Clears the actionbar immediately (sends an empty component). */
161+
public void clearActionbar() {
162+
player.sendActionBar(net.kyori.adventure.text.Component.empty());
163+
}
164+
160165
/** Hides the boss bar. Call before removing the entity. */
161166
public void cleanup() {
162167
if (cupProgressBar != null) {

server/src/main/java/net/elytrarace/server/ecs/system/ElytraPhysicsSystem.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ public void process(Entity entity, float deltaTime) {
5252
}
5353

5454
var player = playerRef.getPlayer();
55+
flight.setFlying(player.isGliding());
56+
if (!flight.isFlying()) {
57+
return;
58+
}
59+
5560
var pos = player.getPosition();
5661
flight.setPitch(pos.pitch());
5762
flight.setYaw(pos.yaw());
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package net.elytrarace.server.ecs.system;
2+
3+
import net.elytrarace.common.ecs.Component;
4+
import net.elytrarace.common.ecs.Entity;
5+
import net.elytrarace.server.ecs.component.ElytraFlightComponent;
6+
import net.elytrarace.server.ecs.component.HudComponent;
7+
import net.elytrarace.server.ecs.component.RingTrackerComponent;
8+
import net.elytrarace.server.ecs.component.ScoreComponent;
9+
10+
import java.util.HashMap;
11+
import java.util.Map;
12+
import java.util.Set;
13+
import java.util.UUID;
14+
15+
/**
16+
* Resets a player's ring progress and score when they land mid-race.
17+
* <p>
18+
* Landing is defined as the flying flag transitioning from {@code true} to
19+
* {@code false}. {@link ElytraPhysicsSystem} syncs this flag from
20+
* {@code player.isGliding()} every tick, so it always reflects the real state.
21+
* <p>
22+
* Reset is skipped for players who have already finished the map
23+
* ({@link ScoreComponent#hasFinished()}), so a legitimate finish does not wipe
24+
* the earned medal tier or completion time.
25+
* <p>
26+
* Must run <em>after</em> {@link ElytraPhysicsSystem} (flying state synced)
27+
* and <em>before</em> {@link ScoreDisplaySystem} (actionbar cleared before next render).
28+
*/
29+
public class LandingResetSystem implements net.elytrarace.common.ecs.System {
30+
31+
private final Map<UUID, Boolean> prevFlying = new HashMap<>();
32+
33+
@Override
34+
public Set<Class<? extends Component>> getRequiredComponents() {
35+
return Set.of(ElytraFlightComponent.class, RingTrackerComponent.class,
36+
ScoreComponent.class, HudComponent.class);
37+
}
38+
39+
@Override
40+
public void process(Entity entity, float deltaTime) {
41+
var flight = entity.getComponent(ElytraFlightComponent.class);
42+
UUID id = entity.getId();
43+
boolean was = prevFlying.getOrDefault(id, false);
44+
boolean is = flight.isFlying();
45+
prevFlying.put(id, is);
46+
47+
if (!was || is) {
48+
return; // not a landing transition
49+
}
50+
51+
var score = entity.getComponent(ScoreComponent.class);
52+
if (score.hasFinished()) {
53+
return; // legitimate finish — preserve medal + time
54+
}
55+
56+
entity.getComponent(RingTrackerComponent.class).reset();
57+
score.reset();
58+
entity.getComponent(HudComponent.class).clearActionbar();
59+
}
60+
}

server/src/main/java/net/elytrarace/server/ecs/system/ScoreDisplaySystem.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ public Set<Class<? extends Component>> getRequiredComponents() {
5353
public void process(Entity entity, float deltaTime) {
5454
var flight = entity.getComponent(ElytraFlightComponent.class);
5555
if (!flight.isFlying()) {
56+
// Clear cached state so the next takeoff renders immediately
57+
UUID cleared = entity.getId();
58+
tickCounters.remove(cleared);
59+
lastDisplayHash.remove(cleared);
5660
return;
5761
}
5862

server/src/main/java/net/elytrarace/server/game/GameOrchestrator.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import net.elytrarace.server.ecs.system.ElytraPhysicsSystem;
2424
import net.elytrarace.server.ecs.system.FireworkBoostSystem;
2525
import net.elytrarace.server.ecs.system.OutOfBoundsSystem;
26+
import net.elytrarace.server.ecs.system.LandingResetSystem;
2627
import net.elytrarace.server.ecs.system.RingCollisionSystem;
2728
import net.elytrarace.server.ecs.system.RingEffectSystem;
2829
import net.elytrarace.server.ecs.system.RingVisualizationSystem;
@@ -125,11 +126,13 @@ public void startGame(CupDefinition cup) {
125126
// Register ECS systems — order matters:
126127
// 1. RingCollisionSystem reads previousPosition from the LAST tick (before physics updates it)
127128
// 2. CompletionDetectionSystem classifies finish times once all rings are passed
128-
// 3. ElytraPhysicsSystem advances server-tracked velocity and updates previousPosition
129-
// 4. FireworkBoostSystem overrides velocity with boost formula when burning
129+
// 3. ElytraPhysicsSystem syncs isFlying from player.isGliding(), advances velocity
130+
// 4. LandingResetSystem detects flying→notFlying, resets rings/score for unfinished players
131+
// 5. FireworkBoostSystem overrides velocity with boost formula when burning
130132
entityManager.addSystem(new RingCollisionSystem(entityManager));
131133
entityManager.addSystem(new CompletionDetectionSystem(entityManager));
132134
entityManager.addSystem(new ElytraPhysicsSystem());
135+
entityManager.addSystem(new LandingResetSystem());
133136
entityManager.addSystem(new FireworkBoostSystem());
134137
entityManager.addSystem(new OutOfBoundsSystem(entityManager, playerService));
135138
entityManager.addSystem(new RingEffectSystem());

0 commit comments

Comments
 (0)