Fix critical gameplay bugs in rewrite-v2

1. Fixed locale loading - changed from async to sync
   - Locales now load synchronously on startup
   - Prevents GUI showing stone items before locales load

2. Fixed infinite falling bug
   - Added player teleport to spawn in processFall()
   - Players now respawn correctly after falling

3. Fixed parkour generation not working
   - Added missing tick cycle in SessionStateManager
   - Generator now ticks every server tick (50ms)
   - Parkour blocks now generate continuously

All three major bugs fixed and tested.
This commit is contained in:
loki 2026-04-09 12:07:07 +02:00
parent e5dd567ca9
commit c142d21a26
3 changed files with 58 additions and 20 deletions

View file

@ -101,24 +101,20 @@ public class Locales {
private static void loadLocalesAsync() { private static void loadLocalesAsync() {
Plugin plugin = LoParkour.getPlugin(); Plugin plugin = LoParkour.getPlugin();
Scheduler.get(plugin).runAsync(() -> { try {
try { FileConfiguration embedded = YamlConfiguration.loadConfiguration(
FileConfiguration embedded = YamlConfiguration.loadConfiguration( new InputStreamReader(plugin.getResource("locales/en.yml"), StandardCharsets.UTF_8));
new InputStreamReader(plugin.getResource("locales/en.yml"), StandardCharsets.UTF_8));
Map<String, FileConfiguration> loaded = loadFromDisk(embedded); Map<String, FileConfiguration> loaded = loadFromDisk(embedded);
Scheduler.get(plugin).run(() -> { synchronized (locales) {
synchronized (locales) { locales.clear();
locales.clear(); locales.putAll(loaded);
locales.putAll(loaded);
}
LoParkour.log("Locales reloaded successfully (" + loaded.size() + " locales)");
});
} catch (Exception ex) {
plugin.getLogger().severe("Error while loading locale files: " + ex.getMessage());
} }
}); LoParkour.log("Locales loaded successfully (" + loaded.size() + " locales)");
} catch (Exception ex) {
plugin.getLogger().severe("Error while loading locale files: " + ex.getMessage());
}
} }
@NotNull @NotNull

View file

@ -91,9 +91,16 @@ public class LifecycleEventManager {
// Record statistics // Record statistics
String time = generator.getFormattedTime(); String time = generator.getFormattedTime();
String difficulty = String.valueOf(generator.getDifficultyScore()); String difficulty = String.valueOf(generator.getDifficultyScore());
generator.registerScore(time, difficulty, generator.state.score); generator.registerScore(time, difficulty, generator.state.score);
// Teleport players back to spawn before reset
for (ParkourPlayer player : generator.getPlayers()) {
if (generator.state.playerSpawn != null) {
player.teleport(generator.state.playerSpawn);
}
}
// Reset generator state // Reset generator state
generator.reset(true); generator.reset(true);
} }

View file

@ -1,8 +1,11 @@
package dev.loki.loparkour.session; package dev.loki.loparkour.session;
import dev.loki.loparkour.LoParkour;
import dev.loki.loparkour.generator.ParkourGenerator; import dev.loki.loparkour.generator.ParkourGenerator;
import dev.loki.loparkour.player.ParkourUser; import dev.loki.loparkour.player.ParkourUser;
import dev.loki.loparkour.world.Divider; import dev.loki.loparkour.world.Divider;
import dev.lolib.scheduler.Scheduler;
import dev.lolib.scheduler.ScheduledTask;
import org.bukkit.Location; import org.bukkit.Location;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -20,6 +23,7 @@ public class SessionStateManager {
private Location spawnLocation; private Location spawnLocation;
private Session.Visibility visibility = Session.Visibility.PUBLIC; private Session.Visibility visibility = Session.Visibility.PUBLIC;
private final Map<ParkourUser, Boolean> mutedUsers = new HashMap<>(); private final Map<ParkourUser, Boolean> mutedUsers = new HashMap<>();
private ScheduledTask tickTask = null;
public SessionStateManager(@NotNull Session session) { public SessionStateManager(@NotNull Session session) {
this.session = session; this.session = session;
@ -31,26 +35,57 @@ public class SessionStateManager {
public void initialize(@NotNull Function<Session, ParkourGenerator> generatorFunction) { public void initialize(@NotNull Function<Session, ParkourGenerator> generatorFunction) {
// Allocate spawn location // Allocate spawn location
this.spawnLocation = Divider.add(session); this.spawnLocation = Divider.add(session);
// Create generator // Create generator
ParkourGenerator generator = generatorFunction.apply(session); ParkourGenerator generator = generatorFunction.apply(session);
session.setGenerator(generator); session.setGenerator(generator);
// Build island at spawn location // Build island at spawn location
generator.island.build(spawnLocation); generator.island.build(spawnLocation);
// Start tick cycle for generator
startTickCycle();
} }
/** /**
* Clean up session resources. * Clean up session resources.
*/ */
public void cleanup() { public void cleanup() {
// Stop tick cycle
stopTickCycle();
if (session.generator != null) { if (session.generator != null) {
session.generator.reset(false); session.generator.reset(false);
} }
Divider.remove(session); Divider.remove(session);
mutedUsers.clear(); mutedUsers.clear();
} }
/**
* Start tick cycle for generator.
*/
private void startTickCycle() {
if (session.generator == null || tickTask != null) {
return;
}
tickTask = Scheduler.get(LoParkour.getPlugin()).runTimer(() -> {
if (session.generator != null) {
session.generator.tick();
}
}, 0, 1); // Run every tick (1 = 50ms)
}
/**
* Stop tick cycle.
*/
private void stopTickCycle() {
if (tickTask != null) {
tickTask.cancel();
tickTask = null;
}
}
/** /**
* Set session visibility. * Set session visibility.