Skip to content

Commit

Permalink
Update to 1.21, optimise world loading, add credits
Browse files Browse the repository at this point in the history
  • Loading branch information
emortaldev committed Aug 6, 2024
1 parent 648d1e0 commit afc67dc
Show file tree
Hide file tree
Showing 13 changed files with 180 additions and 35 deletions.
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ repositories {
}

dependencies {
implementation("dev.emortal.minestom:game-sdk:fe89a3a")
implementation("dev.emortal.minestom:game-sdk:24f5059")

implementation("dev.hollowcube:polar:1.7.2")
implementation("dev.hollowcube:polar:1.11.1")
implementation("net.kyori:adventure-text-minimessage:4.16.0")
}

Expand Down
4 changes: 3 additions & 1 deletion run/maps/city/spawns.json → run/maps/city/map_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
"z": 0.5,
"yaw": -90.0,
"pitch": 0.0
}
},
"name": "City",
"credits": ["emortaldev", "Iternalplayer"]
}
4 changes: 3 additions & 1 deletion run/maps/ruins/spawns.json → run/maps/ruins/map_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
"z": 0.5,
"yaw": -90.0,
"pitch": 0.0
}
},
"name": "Ruins",
"credits": []
}
12 changes: 11 additions & 1 deletion src/main/java/dev/emortal/minestom/parkourtag/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@

import dev.emortal.minestom.gamesdk.MinestomGameServer;
import dev.emortal.minestom.gamesdk.config.GameSdkConfig;
import dev.emortal.minestom.parkourtag.commands.CreditsCommand;
import dev.emortal.minestom.parkourtag.map.MapManager;
import net.minestom.server.MinecraftServer;

public final class Main {

public static void main(String[] args) {
MinestomGameServer.create(() -> {
MinestomGameServer server = MinestomGameServer.create(() -> {
MapManager mapManager = new MapManager();

// TODO: Fix signs
// MinecraftServer.getBlockManager().registerHandler("minecraft:sign", SignHandler::new);
// for (Block value : Block.values()) {
// if (value.name().endsWith("sign")) MinecraftServer.getBlockManager().registerHandler(value.namespace(), SignHandler::new);
// }

return GameSdkConfig.builder()
.minPlayers(ParkourTagGame.MIN_PLAYERS)
.maxGames(10)
.gameCreator(info -> new ParkourTagGame(info, mapManager.getMap(info.mapId())))
.build();
});

MinecraftServer.getCommandManager().register(new CreditsCommand(server.getGameProvider()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import dev.emortal.minestom.parkourtag.listeners.parkourtag.ParkourTagDoubleJumpListener;
import dev.emortal.minestom.parkourtag.listeners.parkourtag.ParkourTagTickListener;
import dev.emortal.minestom.parkourtag.map.LoadedMap;
import dev.emortal.minestom.parkourtag.map.MapSpawns;
import dev.emortal.minestom.parkourtag.map.MapData;
import io.micrometer.core.instrument.Gauge;
import io.micrometer.core.instrument.Metrics;
import net.kyori.adventure.bossbar.BossBar;
Expand Down Expand Up @@ -250,7 +250,7 @@ private void beginGame() {
holderEntity.setNoGravity(true);
((AreaEffectCloudMeta) holderEntity.getEntityMeta()).setRadius(0f);

MapSpawns spawns = this.map.spawns();
MapData spawns = this.map.mapData();
holderEntity.setInstance(this.map.instance(), spawns.tagger().add(0, 0.1, 0)).thenRun(() -> {
for (Player tagger : taggers) {
holderEntity.addPassenger(tagger);
Expand Down Expand Up @@ -450,6 +450,10 @@ private void victory(Set<Player> winners) {
return this.gameStage;
}

public @NotNull LoadedMap getMap() {
return map;
}

@Override
public void cleanUp() {
this.map.instance().scheduleNextTick(MinecraftServer.getInstanceManager()::unregisterInstance);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.emortal.minestom.parkourtag.blockhandler;

import net.minestom.server.instance.block.BlockHandler;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.NamespaceID;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.List;

public final class SignHandler implements BlockHandler {

@Override
public @NotNull Collection<Tag<?>> getBlockEntityTags() {
return List.of(
Tag.Boolean("is_waxed"),
Tag.NBT("front_text"),
Tag.NBT("back_text")
);
}

@Override
public @NotNull NamespaceID getNamespaceId() {
return NamespaceID.from("minecraft:sign");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dev.emortal.minestom.parkourtag.commands;

import dev.emortal.minestom.gamesdk.game.Game;
import dev.emortal.minestom.gamesdk.game.GameProvider;
import dev.emortal.minestom.parkourtag.ParkourTagGame;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.command.CommandSender;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.CommandContext;
import net.minestom.server.command.builder.condition.Conditions;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public final class CreditsCommand extends Command {
private static final @NotNull Component UNKNOWN_MESSAGE = Component.text("We're not sure who made this map", NamedTextColor.RED);

private final @NotNull GameProvider gameProvider;

public CreditsCommand(@NotNull GameProvider gameProvider) {
super("credits");
this.gameProvider = gameProvider;

super.setCondition(Conditions::playerOnly);
super.setDefaultExecutor(this::execute);
}

private @Nullable ParkourTagGame getGame(@NotNull CommandSender sender) {
Game game = this.gameProvider.findGame((Player) sender);
if (game == null) {
sender.sendMessage("You are not in a game!");
return null;
}

return (ParkourTagGame) game;
}

private void execute(@NotNull CommandSender sender, @NotNull CommandContext context) {
ParkourTagGame game = this.getGame(sender);
if (game == null) return;

String[] mapUsernames = game.getMap().mapData().credits();
if (mapUsernames.length == 0) {
sender.sendMessage(UNKNOWN_MESSAGE);
return;
}

TextComponent.Builder message = Component.text();
message.append(Component.text("You're currently playing on ", NamedTextColor.LIGHT_PURPLE));
message.append(Component.text(game.getMap().mapData().name(), NamedTextColor.LIGHT_PURPLE));
message.append(Component.text(", created by:", NamedTextColor.LIGHT_PURPLE));

for (String mapUsername : mapUsernames) {
message.append(Component.newline());
message.append(Component.text(" - "));
message.append(Component.text(mapUsername));
}

sender.sendMessage(message.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
import net.minestom.server.event.Event;
import net.minestom.server.event.EventNode;
import net.minestom.server.event.entity.EntityAttackEvent;
import net.minestom.server.item.firework.FireworkEffect;
import net.minestom.server.item.firework.FireworkEffectType;
import net.minestom.server.item.component.FireworkExplosion;
import net.minestom.server.network.packet.server.play.HitAnimationPacket;
import net.minestom.server.sound.SoundEvent;
import net.minestom.server.tag.Tag;
Expand Down Expand Up @@ -106,12 +105,12 @@ public static void registerListener(EventNode<Event> eventNode, ParkourTagGame g
target.setVelocity(attacker.getPosition().direction().mul(15.0));

// Firework death effect
FireworkEffect randomColorEffect = new FireworkEffect(
false,
false,
FireworkEffectType.LARGE_BALL,
FireworkExplosion randomColorEffect = new FireworkExplosion(
FireworkExplosion.Shape.LARGE_BALL,
List.of(new Color(java.awt.Color.HSBtoRGB(random.nextFloat(), 1f, 1f))),
List.of()
List.of(),
false,
false
);
FireworkUtils.showFirework(game.getPlayers(), e.getInstance(), target.getPosition().add(0, 1.5, 0), List.of(randomColorEffect));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;

public record LoadedMap(@NotNull Instance instance, @NotNull MapSpawns spawns) {
public record LoadedMap(@NotNull Instance instance, @NotNull MapData mapData) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
import net.minestom.server.coordinate.Pos;
import org.jetbrains.annotations.NotNull;

public record MapSpawns(@NotNull Pos tagger, @NotNull Pos goon) {
public record MapData(@NotNull Pos tagger, @NotNull Pos goon, @NotNull String name, @NotNull String[] credits) {
}
35 changes: 22 additions & 13 deletions src/main/java/dev/emortal/minestom/parkourtag/map/MapManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import dev.emortal.minestom.parkourtag.utils.NoopChunkLoader;
import net.hollowcube.polar.PolarLoader;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.world.DimensionType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -18,17 +20,19 @@
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;

public final class MapManager {
private static final Logger LOGGER = LoggerFactory.getLogger(MapManager.class);
private static final Gson GSON = new Gson();

private static final DimensionType DIMENSION_TYPE = DimensionType.builder(NamespaceID.from("emortalmc:parkourtag"))
.skylightEnabled(true)
private static final DimensionType DIMENSION_TYPE = DimensionType.builder()
.hasSkylight(true)
// .ambientLight(1.0f)
.build();

Expand All @@ -44,30 +48,35 @@ public final class MapManager {
private final Map<String, PreLoadedMap> preLoadedMaps;

public MapManager() {
MinecraftServer.getDimensionTypeManager().addDimension(DIMENSION_TYPE);
DynamicRegistry.Key<DimensionType> dimension = MinecraftServer.getDimensionTypeRegistry().register("emortalmc:parkourtag", DIMENSION_TYPE);

Map<String, PreLoadedMap> maps = new HashMap<>();
for (String mapName : ENABLED_MAPS) {
Path mapPath = MAPS_PATH.resolve(mapName);
Path polarPath = mapPath.resolve("map.polar");
Path spawnsPath = mapPath.resolve("spawns.json");
Path spawnsPath = mapPath.resolve("map_data.json");

try {
MapSpawns spawns = GSON.fromJson(new JsonReader(Files.newBufferedReader(spawnsPath)), MapSpawns.class);
LOGGER.info("Loaded spawns for map {}: [{}]", mapName, spawns);
MapData spawns = GSON.fromJson(new JsonReader(Files.newBufferedReader(spawnsPath)), MapData.class);
LOGGER.info("Loaded mapData for map {}: [{}]", mapName, spawns);

PolarLoader polarLoader = new PolarLoader(polarPath);

InstanceContainer instance = MinecraftServer.getInstanceManager().createInstanceContainer(DIMENSION_TYPE, polarLoader);
InstanceContainer instance = MinecraftServer.getInstanceManager().createInstanceContainer(dimension, polarLoader);
instance.setTimeRate(0);
instance.setTimeUpdate(null);
instance.setTimeSynchronizationTicks(0);

// Do some preloading!
List<CompletableFuture<Chunk>> futures = new ArrayList<>();
for (int x = -CHUNK_LOADING_RADIUS; x < CHUNK_LOADING_RADIUS; x++) {
for (int z = -CHUNK_LOADING_RADIUS; z < CHUNK_LOADING_RADIUS; z++) {
instance.loadChunk(x, z);
futures.add(instance.loadChunk(x, z));
}
}
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).thenRun(() -> {
// Replace polar loader after all chunks are loaded to save memory
instance.setChunkLoader(new NoopChunkLoader());
});

maps.put(mapName, new PreLoadedMap(instance, spawns));
} catch (IOException exception) {
Expand Down Expand Up @@ -99,16 +108,16 @@ public MapManager() {
return map.load(randomMapId);
}

private record PreLoadedMap(@NotNull InstanceContainer rootInstance, @NotNull MapSpawns spawns) {
private record PreLoadedMap(@NotNull InstanceContainer rootInstance, @NotNull MapData mapData) {

@NotNull LoadedMap load(@NotNull String mapId) {
Instance shared = MinecraftServer.getInstanceManager().createSharedInstance(this.rootInstance());

shared.setTag(MAP_ID_TAG, mapId);
shared.setTimeRate(0);
shared.setTimeUpdate(null);
shared.setTimeSynchronizationTicks(0);

return new LoadedMap(shared, this.spawns());
return new LoadedMap(shared, this.mapData());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
import net.minestom.server.entity.Player;
import net.minestom.server.entity.metadata.projectile.FireworkRocketMeta;
import net.minestom.server.instance.Instance;
import net.minestom.server.item.ItemMeta;
import net.minestom.server.item.ItemComponent;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.item.firework.FireworkEffect;
import net.minestom.server.item.metadata.FireworkMeta;
import net.minestom.server.item.component.FireworkExplosion;
import net.minestom.server.item.component.FireworkList;
import net.minestom.server.network.packet.server.play.EntityStatusPacket;
import net.minestom.server.utils.PacketUtils;

Expand All @@ -19,9 +19,8 @@

public class FireworkUtils {

public static void showFirework(Set<Player> players, Instance instance, Pos position, List<FireworkEffect> effects) {
ItemMeta fwMeta = new FireworkMeta.Builder().effects(effects).build();
ItemStack fwItem = ItemStack.builder(Material.FIREWORK_ROCKET).meta(fwMeta).build();
public static void showFirework(Set<Player> players, Instance instance, Pos position, List<FireworkExplosion> effects) {
ItemStack fwItem = ItemStack.builder(Material.FIREWORK_ROCKET).set(ItemComponent.FIREWORKS, new FireworkList((byte) 0, effects)).build();

Entity firework = new Entity(EntityType.FIREWORK_ROCKET);
((FireworkRocketMeta) firework.getEntityMeta()).setFireworkInfo(fwItem);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package dev.emortal.minestom.parkourtag.utils;

import net.minestom.server.instance.Chunk;
import net.minestom.server.instance.IChunkLoader;
import net.minestom.server.instance.Instance;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.concurrent.CompletableFuture;

public class NoopChunkLoader implements IChunkLoader {
@Override
public @NotNull CompletableFuture<@Nullable Chunk> loadChunk(@NotNull Instance instance, int chunkX, int chunkZ) {
return CompletableFuture.completedFuture(null);
}

@Override
public @NotNull CompletableFuture<Void> saveChunk(@NotNull Chunk chunk) {
return CompletableFuture.completedFuture(null);
}

@Override
public boolean supportsParallelSaving() {
return true;
}

@Override
public boolean supportsParallelLoading() {
return true;
}
}

0 comments on commit afc67dc

Please sign in to comment.