Add /reset to start over from scratch and hint at it in the endless stage
This commit is contained in:
1 parent
e2c574bf0b
commit
249cd0c08a
5 files changed
+69
-17
No files matched your search
@@ -3,6 +3,8 @@ package eu.mhsl.minecraft.endlessjumper;
|
||||
import eu.mhsl.minecraft.endlessjumper.generator.JumpGenerator;
|
||||
import net.minestom.server.Auth;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.PlayerSkin;
|
||||
@@ -20,7 +22,6 @@ import net.minestom.server.event.player.PlayerUseItemEvent;
|
||||
import net.minestom.server.event.player.PlayerUseItemOnBlockEvent;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
import net.minestom.server.instance.InstanceManager;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
|
||||
@@ -32,26 +33,20 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class EndlessJumper {
|
||||
private static final Pos START = new Pos(0, 100, 0);
|
||||
private static final Pos SPAWN = START.add(0.5, 1, 0.5);
|
||||
private static final Map<Player, JumpGenerator> games = new ConcurrentHashMap<>();
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
MinecraftServer server = MinecraftServer.init(new Auth.Velocity(readForwardingSecret()));
|
||||
Progress.load();
|
||||
InstanceManager instanceManager = MinecraftServer.getInstanceManager();
|
||||
GlobalEventHandler eventHandler = MinecraftServer.getGlobalEventHandler();
|
||||
PlayerSkin skin = PlayerSkin.fromUsername("Notch");
|
||||
|
||||
eventHandler.addListener(AsyncPlayerConfigurationEvent.class, event -> {
|
||||
final Player p = event.getPlayer();
|
||||
p.setRespawnPoint(START.add(0.5, 1.5, 0.5));
|
||||
|
||||
final InstanceContainer world = instanceManager.createInstanceContainer();
|
||||
world.setBlock(START, Block.DIAMOND_BLOCK);
|
||||
// Tageszeit steuert der jeweilige Abschnitt
|
||||
world.defaultClock().pause();
|
||||
|
||||
p.setRespawnPoint(SPAWN);
|
||||
p.setSkin(skin);
|
||||
event.setSpawningInstance(world);
|
||||
event.setSpawningInstance(createWorld());
|
||||
});
|
||||
|
||||
eventHandler.addListener(PlayerSpawnEvent.class, event -> {
|
||||
@@ -94,13 +89,46 @@ public class EndlessJumper {
|
||||
games.remove(p);
|
||||
ScoreTab.leave(p);
|
||||
// jede Partie hat eine eigene Welt: nach dem Verlassen freigeben
|
||||
Instance world = p.getInstance();
|
||||
if(world != null) MinecraftServer.getSchedulerManager().scheduleNextTick(() -> instanceManager.unregisterInstance(world));
|
||||
releaseLater(p.getInstance());
|
||||
});
|
||||
|
||||
Command reset = new Command("reset");
|
||||
reset.setDefaultExecutor((sender, context) -> {
|
||||
if(sender instanceof Player player) resetGame(player);
|
||||
});
|
||||
MinecraftServer.getCommandManager().register(reset);
|
||||
|
||||
server.start("0.0.0.0", 25501);
|
||||
}
|
||||
|
||||
private static InstanceContainer createWorld() {
|
||||
InstanceContainer world = MinecraftServer.getInstanceManager().createInstanceContainer();
|
||||
world.setBlock(START, Block.DIAMOND_BLOCK);
|
||||
// Tageszeit steuert der jeweilige Abschnitt
|
||||
world.defaultClock().pause();
|
||||
return world;
|
||||
}
|
||||
|
||||
private static void releaseLater(Instance world) {
|
||||
if(world != null) MinecraftServer.getSchedulerManager().scheduleNextTick(() -> MinecraftServer.getInstanceManager().unregisterInstance(world));
|
||||
}
|
||||
|
||||
/** /reset: Fortschritt, Strecke, Score und Joker zurücksetzen und in einer frischen Welt bei 0 beginnen. */
|
||||
private static void resetGame(Player player) {
|
||||
JumpGenerator old = games.remove(player);
|
||||
if(old != null) old.close();
|
||||
Progress.reset(player.getUuid());
|
||||
|
||||
Instance oldWorld = player.getInstance();
|
||||
InstanceContainer world = createWorld();
|
||||
player.setVelocity(Vec.ZERO);
|
||||
player.setInstance(world, SPAWN).thenRun(() -> {
|
||||
Jokers.giveStart(player);
|
||||
games.put(player, new JumpGenerator(START, 0, player, world));
|
||||
releaseLater(oldWorld);
|
||||
});
|
||||
}
|
||||
|
||||
private static void useJoker(Player player, ItemStack item) {
|
||||
JumpGenerator generator = games.get(player);
|
||||
if(generator != null && Jokers.BRIDGE.matches(item) && generator.useBridge()) Jokers.BRIDGE.take(player);
|
||||
|
||||
@@ -40,6 +40,11 @@ public class Progress {
|
||||
writer.execute(Progress::write);
|
||||
}
|
||||
|
||||
public static void reset(UUID player) {
|
||||
checkpoints.remove(player.toString());
|
||||
writer.execute(Progress::write);
|
||||
}
|
||||
|
||||
/** Erst in eine Temp-Datei, dann atomar umbenennen: ein Absturz hinterlässt nie eine halbe Datei. */
|
||||
private static void write() {
|
||||
try {
|
||||
|
||||
@@ -75,6 +75,11 @@ public class BlockPalette {
|
||||
return STAGES.getFirst();
|
||||
}
|
||||
|
||||
/** Der letzte Abschnitt geht endlos weiter. */
|
||||
public static boolean isEndless(Stage stage) {
|
||||
return stage == STAGES.getLast();
|
||||
}
|
||||
|
||||
public static Block getRandom(int index, Random random) {
|
||||
List<Block> blocks = stageAt(index).blocks();
|
||||
return blocks.get(random.nextInt(blocks.size()));
|
||||
|
||||
@@ -53,6 +53,7 @@ public class JumpGenerator {
|
||||
|
||||
private static final TextColor COMBO_COLOR = TextColor.color(255, 69, 0);
|
||||
private static final Title CHECKPOINT_TITLE = Title.title(Component.empty(), Component.text("Checkpoint", NamedTextColor.GREEN));
|
||||
private static final Component ENDLESS_HINT = Component.text(" · /reset für einen Neustart", NamedTextColor.DARK_GRAY);
|
||||
private static final Title FINALE_TITLE = Title.title(Component.text("Geschafft!", NamedTextColor.GOLD), Component.text("Du hast das End erreicht", NamedTextColor.YELLOW));
|
||||
private static final Sound CHECKPOINT_SOUND = Sound.sound(SoundEvent.ENTITY_PLAYER_LEVELUP, Sound.Source.BLOCK, 0.3f, 1f);
|
||||
private static final Sound STAGE_SOUND = Sound.sound(SoundEvent.UI_TOAST_CHALLENGE_COMPLETE, Sound.Source.MASTER, 0.4f, 1f);
|
||||
@@ -154,13 +155,14 @@ public class JumpGenerator {
|
||||
|
||||
// Abschnitt dauerhaft in der Actionbar (Titel werden von der Combo-Anzeige überschrieben)
|
||||
BlockPalette.Stage stage = BlockPalette.stageAt(index);
|
||||
if(stage != BlockPalette.stageAt(previous)) {
|
||||
boolean newStage = stage != BlockPalette.stageAt(previous);
|
||||
if(newStage) {
|
||||
this.atmosphere.enter(stage);
|
||||
this.player.playSound(STAGE_SOUND);
|
||||
this.player.sendActionBar(Component.text(stage.name(), NamedTextColor.GOLD));
|
||||
} else {
|
||||
this.player.sendActionBar(Component.text(stage.name(), NamedTextColor.GRAY));
|
||||
}
|
||||
Component stageText = Component.text(stage.name(), newStage ? NamedTextColor.GOLD : NamedTextColor.GRAY);
|
||||
if(BlockPalette.isEndless(stage)) stageText = stageText.append(ENDLESS_HINT);
|
||||
this.player.sendActionBar(stageText);
|
||||
|
||||
if(previous < FINALE_AT && index >= FINALE_AT) this.celebrate();
|
||||
|
||||
@@ -348,6 +350,11 @@ public class JumpGenerator {
|
||||
})).delay(TaskSchedule.seconds(8)).schedule();
|
||||
}
|
||||
|
||||
/** Beendet alles, was an den Spieler gebunden weiterläuft (Partikel, Musik). */
|
||||
public void close() {
|
||||
this.atmosphere.stop();
|
||||
}
|
||||
|
||||
/** Streckenblöcke und ihr Licht sind geschützt, alles andere (Brücke, Rettung) darf abgebaut werden. */
|
||||
public boolean isBreakable(Point pos) {
|
||||
return !this.world.getBlock(pos).compare(Block.LIGHT) && !this.courseIndex.containsKey(BlockKey.of(pos));
|
||||
|
||||
@@ -23,6 +23,7 @@ class StageAtmosphere {
|
||||
private final Instance world;
|
||||
private BlockPalette.Stage stage;
|
||||
private Task timeTransition;
|
||||
private final Task ambient;
|
||||
|
||||
StageAtmosphere(Player player, Instance world, BlockPalette.Stage initial) {
|
||||
this.player = player;
|
||||
@@ -32,7 +33,13 @@ class StageAtmosphere {
|
||||
this.world.refreshTime();
|
||||
this.playMusic();
|
||||
// an den Spieler gebunden, endet also mit ihm
|
||||
player.scheduler().buildTask(this::spawnAmbient).repeat(TaskSchedule.tick(4)).schedule();
|
||||
this.ambient = player.scheduler().buildTask(this::spawnAmbient).repeat(TaskSchedule.tick(4)).schedule();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
this.ambient.cancel();
|
||||
if(this.timeTransition != null) this.timeTransition.cancel();
|
||||
this.player.stopSound(SoundStop.source(Sound.Source.MUSIC));
|
||||
}
|
||||
|
||||
void enter(BlockPalette.Stage next) {
|
||||
|
||||
Reference in new issue
Block a user