Initial commit
This commit is contained in:
46
src/main/java/eu/mhsl/minenet/minigames/Main.java
Normal file
46
src/main/java/eu/mhsl/minenet/minigames/Main.java
Normal file
@ -0,0 +1,46 @@
|
||||
package eu.mhsl.minenet.minigames;
|
||||
|
||||
import eu.mhsl.minenet.minigames.command.Commands;
|
||||
import eu.mhsl.minenet.minigames.handler.Listeners;
|
||||
import eu.mhsl.minenet.minigames.lang.Languages;
|
||||
import eu.mhsl.minenet.minigames.server.tasks.TablistUpdateTask;
|
||||
import eu.mhsl.minenet.minigames.server.provider.ByPlayerNameUuidProvider;
|
||||
import io.github.bloepiloepi.pvp.PvpExtension;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.extras.lan.OpenToLAN;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
|
||||
public class Main {
|
||||
/**
|
||||
* Starts minenet minigames services
|
||||
* @param args startflags
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Initialize Minecraft server...");
|
||||
MinecraftServer server = MinecraftServer.init();
|
||||
PvpExtension.init();
|
||||
|
||||
MinecraftServer.setBrandName("minenet");
|
||||
MinecraftServer.setCompressionThreshold(0);
|
||||
System.setProperty("minestom.chunk-view-distance", "12");
|
||||
|
||||
MinecraftServer.getConnectionManager().setUuidProvider(new ByPlayerNameUuidProvider());
|
||||
|
||||
Commands.values();
|
||||
Listeners.values();
|
||||
|
||||
MinecraftServer.getSchedulerManager().scheduleTask(new TablistUpdateTask(), TaskSchedule.tick(20), TaskSchedule.tick(20));
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
Resource.values(); // This initializes and preloads the enum and extracts the resources
|
||||
Languages.getInstance(); //Preload languages into the jvm
|
||||
|
||||
System.out.println("Starting Minecraft server ... ");
|
||||
OpenToLAN.open();
|
||||
//MojangAuth.init(); LET NON MIGRATORS PLAY!
|
||||
server.start("0.0.0.0", 25565);
|
||||
System.gc();
|
||||
|
||||
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> System.out.println("Minecraft server is now running!"));
|
||||
}
|
||||
}
|
41
src/main/java/eu/mhsl/minenet/minigames/Resource.java
Normal file
41
src/main/java/eu/mhsl/minenet/minigames/Resource.java
Normal file
@ -0,0 +1,41 @@
|
||||
package eu.mhsl.minenet.minigames;
|
||||
|
||||
import eu.mhsl.minenet.minigames.util.ResourceUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* Predefined resources which are extracted on Runtime
|
||||
*/
|
||||
public enum Resource {
|
||||
HUB_MAP("maps/hub"),
|
||||
LOBBY_MAP("maps/lobby"),
|
||||
RBB("rbb"),
|
||||
LOCALES("lang"),
|
||||
SCHEMATICS("schematics");
|
||||
|
||||
private final Path path;
|
||||
private final String name;
|
||||
Resource(String name) {
|
||||
this.name = name;
|
||||
this.path = Path.of("resources/" + name);
|
||||
|
||||
try {
|
||||
System.out.print("extracting resource " + name + " ... ");
|
||||
ResourceUtils.extractResource(name);
|
||||
System.out.println("ok");
|
||||
} catch (URISyntaxException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Path getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package eu.mhsl.minenet.minigames.command;
|
||||
|
||||
import eu.mhsl.minenet.minigames.command.admin.*;
|
||||
import eu.mhsl.minenet.minigames.command.user.HubCommand;
|
||||
import eu.mhsl.minenet.minigames.command.user.LeaveCommand;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
|
||||
public enum Commands {
|
||||
HUB(new HubCommand()),
|
||||
LEAVE(new LeaveCommand()),
|
||||
|
||||
DEBUG(new DebugCommand()),
|
||||
FLY(new FlyCommand()),
|
||||
GAMEMODE(new GamemodeCommand()),
|
||||
GC(new GcCommand()),
|
||||
LANGTEST(new LangTestCommand()),
|
||||
ROOM(new RoomCommand()),
|
||||
UPDATE(new UpdateCommand());
|
||||
|
||||
Commands(Command handler) {
|
||||
MinecraftServer.getCommandManager().register(handler);
|
||||
}
|
||||
|
||||
static {
|
||||
MinecraftServer.getCommandManager().setUnknownCommandCallback((sender, command) -> {
|
||||
if(command.isBlank()) return;
|
||||
new ChatMessage(Icon.ERROR).appendStatic("Unknown command").quote(command).send(sender);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ActionBarMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.TitleMessage;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
|
||||
public class DebugCommand extends Command {
|
||||
public DebugCommand() {
|
||||
super("debug");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
setDefaultExecutor((sender, args) -> {
|
||||
new ChatMessage(Icon.CHAT).appendTranslated("sample").send(sender);
|
||||
new ActionBarMessage().appendTranslated("sample").send(sender);
|
||||
new TitleMessage().subtitle(subtitleMessage -> subtitleMessage.appendTranslated("sample")).appendTranslated("sample").send(sender);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class FlyCommand extends Command {
|
||||
public FlyCommand() {
|
||||
super("fly");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
Player p = (Player) sender;
|
||||
p.setVelocity(new Vec(0, 5, 0));
|
||||
p.setFlying(!p.isFlying());
|
||||
p.setAllowFlying(!p.isAllowFlying());
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentType;
|
||||
import net.minestom.server.entity.GameMode;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class GamemodeCommand extends Command {
|
||||
public GamemodeCommand() {
|
||||
super("gamemode", "gm");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
addSyntax((sender, context) -> {
|
||||
((Player) sender).setGameMode(context.get("target"));
|
||||
}, ArgumentType.Enum("target", GameMode.class));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.util.Monitoring;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
|
||||
public class GcCommand extends Command {
|
||||
private static long lastRun = System.currentTimeMillis();
|
||||
public GcCommand() {
|
||||
super("gc");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
long nextRun = (long) (lastRun - (System.currentTimeMillis() - 30*1000)) / 1000;
|
||||
if(nextRun > 0) {
|
||||
new ChatMessage(Icon.ERROR).appendStatic("Please wait ").appendStatic(String.valueOf(nextRun)).appendStatic(" seconds before running GC again!").send(sender);
|
||||
return;
|
||||
}
|
||||
|
||||
lastRun = System.currentTimeMillis();
|
||||
|
||||
long before = Monitoring.getRamUsage();
|
||||
System.gc();
|
||||
long after = Monitoring.getRamUsage();
|
||||
|
||||
new ChatMessage(Icon.SUCCESS).appendStatic("Garbage collector ran successfully!").indent(1).newLine()
|
||||
.appendStatic("before: ").appendStatic(String.valueOf(before)).appendStatic("MB").newLine()
|
||||
.appendStatic("now: ").appendStatic(String.valueOf(after)).appendStatic("MB").indent(1).newLine()
|
||||
.appendStatic("difference: ").appendStatic(String.valueOf(before-after)).appendStatic("MB")
|
||||
.send(sender);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import eu.mhsl.minenet.minigames.lang.Languages;
|
||||
import eu.mhsl.minenet.minigames.lang.Lang;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.command.builder.arguments.ArgumentType;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class LangTestCommand extends Command {
|
||||
public LangTestCommand() {
|
||||
super("langtest");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
sendMessage(Languages.getInstance().getLanguage((Player) sender), "sample").send(sender);
|
||||
});
|
||||
|
||||
var targetString = ArgumentType.String("mapId");
|
||||
|
||||
addSyntax((sender, context) -> {
|
||||
sendMessage(Languages.getInstance().getLanguage((Player) sender), context.get("mapId")).send(sender);
|
||||
}, targetString);
|
||||
}
|
||||
|
||||
private TranslatableMessage sendMessage(Lang lang, String mapId) {
|
||||
return new ChatMessage(Icon.SCIENCE).appendStatic(lang.getLangId()).newLine().appendTranslated(lang.getEntry(mapId));
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class RoomCommand extends Command {
|
||||
public RoomCommand() {
|
||||
super("room");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
TranslatableMessage out = new ChatMessage(Icon.SCIENCE).appendStatic("Rooms:").indent(1).newLine();
|
||||
|
||||
Room.getAllRooms().forEach((roomInstance) -> {
|
||||
out
|
||||
.newLine()
|
||||
.appendStatic("Owner: ").appendStatic(roomInstance.getOwner().getUsername()).newLine()
|
||||
.appendStatic("Players: ").appendStatic(String.valueOf(roomInstance.getAllMembers().size())).indent(1).newLine()
|
||||
.list(roomInstance.getAllMembers().stream().map(Player::getUsername).collect(Collectors.toList())).indent(-1).newLine();
|
||||
});
|
||||
|
||||
out.send(sender);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package eu.mhsl.minenet.minigames.command.admin;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class UpdateCommand extends Command {
|
||||
public UpdateCommand() {
|
||||
super("update");
|
||||
|
||||
setCondition((sender, commandString) -> sender.hasPermission("admin"));
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
((Player) sender).refreshCommands();
|
||||
new ChatMessage(Icon.SUCCESS).appendStatic("Updated command syntax!").send(sender);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package eu.mhsl.minenet.minigames.command.user;
|
||||
|
||||
import eu.mhsl.minenet.minigames.util.MoveInstance;
|
||||
import eu.mhsl.minenet.minigames.instance.hub.HubInstance;
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class HubCommand extends Command {
|
||||
public HubCommand() {
|
||||
super("hub");
|
||||
|
||||
setCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Room);
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
MoveInstance.move((Player) sender, HubInstance.INSTANCE);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.minenet.minigames.command.user;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.Game;
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import net.minestom.server.command.builder.Command;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class LeaveCommand extends Command {
|
||||
public LeaveCommand() {
|
||||
super("leave");
|
||||
|
||||
setCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Game);
|
||||
|
||||
setDefaultExecutor((sender, context) -> {
|
||||
Room.setOwnRoom((Player) sender);
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package eu.mhsl.minenet.minigames.handler;
|
||||
|
||||
import eu.mhsl.minenet.minigames.handler.global.AddEntityToInstanceEventListener;
|
||||
import eu.mhsl.minenet.minigames.handler.global.PlayerChatHandler;
|
||||
import eu.mhsl.minenet.minigames.handler.global.PlayerLoginHandler;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.event.EventListener;
|
||||
|
||||
public enum Listeners {
|
||||
SPAWN(new AddEntityToInstanceEventListener()),
|
||||
CHAT(new PlayerChatHandler()),
|
||||
LOGIN(new PlayerLoginHandler());
|
||||
|
||||
Listeners(EventListener<?> event) {
|
||||
MinecraftServer.getGlobalEventHandler().addListener(event);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package eu.mhsl.minenet.minigames.handler.global;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.hub.HubInstance;
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import eu.mhsl.minenet.minigames.message.type.ActionBarMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.EventListener;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class AddEntityToInstanceEventListener implements EventListener<AddEntityToInstanceEvent> {
|
||||
@Override
|
||||
public @NotNull Class eventType() {
|
||||
return AddEntityToInstanceEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Result run(@NotNull AddEntityToInstanceEvent event) {
|
||||
System.out.println("AddEntityEvent");
|
||||
if(event.getEntity() instanceof Player p) {
|
||||
|
||||
MinecraftServer.getSchedulerManager().scheduleNextTick(p::refreshCommands, ExecutionType.ASYNC);
|
||||
new ActionBarMessage().appendStatic(Component.text("Instance: ", NamedTextColor.DARK_GRAY)).appendStatic(event.getInstance().getUniqueId().toString()).send(p);
|
||||
new ChatMessage(Icon.SCIENCE).appendStatic(Component.text(event.getInstance().getUniqueId().toString())).send(p);
|
||||
|
||||
//p.addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, 20)); //TODO Uncomment, currently buggy causes disconnect see https://github.com/Minestom/Minestom/discussions/1302
|
||||
}
|
||||
|
||||
return Result.SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package eu.mhsl.minenet.minigames.handler.global;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import net.minestom.server.event.EventListener;
|
||||
import net.minestom.server.event.player.PlayerChatEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlayerChatHandler implements EventListener<PlayerChatEvent> {
|
||||
@Override
|
||||
public @NotNull Class<PlayerChatEvent> eventType() {
|
||||
return PlayerChatEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Result run(@NotNull PlayerChatEvent event) {
|
||||
event.setChatFormat(
|
||||
(messages) -> new ChatMessage(Icon.CHAT)
|
||||
.appendStatic(event.getPlayer().getUsername())
|
||||
.pipe()
|
||||
.appendStatic(messages.getMessage())
|
||||
.build(event.getPlayer())
|
||||
);
|
||||
|
||||
return Result.SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package eu.mhsl.minenet.minigames.handler.global;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import eu.mhsl.minenet.minigames.skin.SkinCache;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.EventListener;
|
||||
import net.minestom.server.event.player.PlayerLoginEvent;
|
||||
import eu.mhsl.minenet.minigames.instance.hub.HubInstance;
|
||||
import net.minestom.server.permission.Permission;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlayerLoginHandler implements EventListener<PlayerLoginEvent> {
|
||||
@Override
|
||||
public @NotNull Class<PlayerLoginEvent> eventType() {
|
||||
return PlayerLoginEvent.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Result run(@NotNull PlayerLoginEvent event) {
|
||||
|
||||
Player p = event.getPlayer();
|
||||
|
||||
p.setRespawnPoint(HubInstance.INSTANCE.getSpawn());
|
||||
p.sendMessage(p.getUuid().toString());
|
||||
event.setSpawningInstance(HubInstance.INSTANCE);
|
||||
SkinCache.applySkin(p);
|
||||
|
||||
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
|
||||
Room minetecsRoom = Room.getRoom(MinecraftServer.getConnectionManager().getPlayer("minetec"));
|
||||
if(minetecsRoom != null) {
|
||||
Room.setRoom(event.getPlayer(), minetecsRoom);
|
||||
}
|
||||
}, TaskSchedule.seconds(1), TaskSchedule.stop());
|
||||
|
||||
if(p.getUsername().equalsIgnoreCase("minetec"))
|
||||
p.addPermission(new Permission("admin"));
|
||||
|
||||
return Result.SUCCESS;
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package eu.mhsl.minenet.minigames.instance;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.utils.NamespaceID;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
|
||||
/**
|
||||
* Prebuilt dimensions
|
||||
*/
|
||||
public enum Dimension {
|
||||
OVERWORLD(
|
||||
DimensionType
|
||||
.builder(NamespaceID.from("minenet:fullbright_overworld"))
|
||||
.ambientLight(2.0f)
|
||||
.build()
|
||||
),
|
||||
|
||||
NETHER(
|
||||
DimensionType
|
||||
.builder(NamespaceID.from("minenet:fullbright_nether"))
|
||||
.ambientLight(2.0f)
|
||||
.effects("minecraft:the_nether")
|
||||
.build()
|
||||
),
|
||||
|
||||
THE_END(
|
||||
DimensionType
|
||||
.builder(NamespaceID.from("minenet:fullbright_end"))
|
||||
.ambientLight(2.0f)
|
||||
.effects("minecraft:the_end")
|
||||
.build()
|
||||
);
|
||||
|
||||
public final DimensionType DIMENSION;
|
||||
Dimension(DimensionType dimType) {
|
||||
this.DIMENSION = dimType;
|
||||
|
||||
MinecraftServer.getDimensionTypeManager().addDimension(this.DIMENSION);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package eu.mhsl.minenet.minigames.instance;
|
||||
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
|
||||
public interface Spawnable {
|
||||
Pos getSpawn();
|
||||
}
|
136
src/main/java/eu/mhsl/minenet/minigames/instance/game/Game.java
Normal file
136
src/main/java/eu/mhsl/minenet/minigames/instance/game/Game.java
Normal file
@ -0,0 +1,136 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game;
|
||||
|
||||
import eu.mhsl.minenet.minigames.util.CommonEventHandles;
|
||||
import eu.mhsl.minenet.minigames.instance.Spawnable;
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import io.github.bloepiloepi.pvp.config.PvPConfig;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.event.EventNode;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
|
||||
import net.minestom.server.event.item.ItemDropEvent;
|
||||
import net.minestom.server.event.player.PlayerBlockBreakEvent;
|
||||
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.event.trait.InstanceEvent;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class Game extends InstanceContainer implements Spawnable {
|
||||
|
||||
protected boolean isRunning = false;
|
||||
protected boolean isBeforeBeginning = true;
|
||||
|
||||
protected final Random rnd = new Random(); //TODO better way than ths?
|
||||
|
||||
public Game(DimensionType dimensionType) {
|
||||
super(UUID.randomUUID(), dimensionType);
|
||||
|
||||
MinecraftServer.getInstanceManager().registerInstance(this);
|
||||
|
||||
eventNode()
|
||||
.addListener(PlayerMoveEvent.class, this::onPlayerMove)
|
||||
.addListener(PlayerBlockBreakEvent.class, this::onBlockBreak)
|
||||
.addListener(PlayerBlockPlaceEvent.class, this::onBlockPlace)
|
||||
.addListener(AddEntityToInstanceEvent.class, this::onJoin)
|
||||
.addListener(RemoveEntityFromInstanceEvent.class, this::onLeave)
|
||||
.addListener(ItemDropEvent.class, this::onItemDrop);
|
||||
}
|
||||
|
||||
public void enablePvpConfig(PvPConfig config) {
|
||||
//eventNode().addChild((EventNode<? extends InstanceEvent>) config.createNode());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load and start countdown
|
||||
*/
|
||||
public void load() {
|
||||
scheduler().submitTask(() -> {
|
||||
CompletableFuture<Void> callback = new CompletableFuture<>();
|
||||
this.onLoad(callback);
|
||||
callback.whenComplete((unused, throwable) -> this.start());
|
||||
return TaskSchedule.stop();
|
||||
}, ExecutionType.ASYNC);
|
||||
|
||||
}
|
||||
|
||||
protected void start() {
|
||||
isRunning = true;
|
||||
isBeforeBeginning = false;
|
||||
this.onStart();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
isRunning = false;
|
||||
this.onStop();
|
||||
this.unload();
|
||||
}
|
||||
|
||||
public void unload() {
|
||||
this.onUnload();
|
||||
|
||||
getPlayers().forEach(Room::setOwnRoom);
|
||||
|
||||
scheduler().scheduleTask(() -> {
|
||||
|
||||
System.out.println("stopping game instance " + this.uniqueId);
|
||||
getPlayers().forEach(player -> player.kick("timeout"));
|
||||
|
||||
MinecraftServer.getInstanceManager().unregisterInstance(this);
|
||||
|
||||
}, TaskSchedule.seconds(10), TaskSchedule.stop());
|
||||
}
|
||||
|
||||
protected void onLoad(CompletableFuture<Void> callback) {}
|
||||
protected void onStart() {}
|
||||
protected void onStop() {}
|
||||
protected void onUnload() {}
|
||||
|
||||
|
||||
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
|
||||
|
||||
}
|
||||
|
||||
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent playerBlockBreakEvent) {
|
||||
playerBlockBreakEvent.setCancelled(true);
|
||||
}
|
||||
|
||||
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) {
|
||||
playerBlockPlaceEvent.setCancelled(true);
|
||||
}
|
||||
|
||||
protected void onJoin(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure when overriding to call checkAbandoned to insure no garbage instances
|
||||
* @param removeEntityFromInstanceEvent
|
||||
*/
|
||||
protected void onLeave(@NotNull RemoveEntityFromInstanceEvent removeEntityFromInstanceEvent) {
|
||||
this.checkAbandoned();
|
||||
}
|
||||
|
||||
protected void onItemDrop(@NotNull ItemDropEvent itemDropEvent) {
|
||||
CommonEventHandles.cancel(itemDropEvent);
|
||||
}
|
||||
|
||||
protected void checkAbandoned() {
|
||||
scheduleNextTick((instance) -> {
|
||||
if(instance.getPlayers().size() == 0) this.unload();
|
||||
});
|
||||
}
|
||||
|
||||
public Pos getSpawn() {
|
||||
return new Pos(0,50,0);
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.Game;
|
||||
import eu.mhsl.minenet.minigames.message.Countdown;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.TitleMessage;
|
||||
import eu.mhsl.minenet.minigames.score.Score;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import net.minestom.server.world.DimensionType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class Minigame extends Game {
|
||||
private final String name;
|
||||
private Score score = new Score(this);
|
||||
|
||||
private int timeLimit = 0;
|
||||
private int timePlayed = 0;
|
||||
private boolean preventExit = false;
|
||||
public Minigame(DimensionType dimensionType, String gameName) {
|
||||
super(dimensionType);
|
||||
|
||||
this.name = gameName;
|
||||
}
|
||||
|
||||
public Score getScore() {
|
||||
return this.score;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setTimeLimit(int limit) {
|
||||
this.timeLimit = limit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
super.load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays countdown and starts the game
|
||||
* When overriding make sure to call this::start after countdown!
|
||||
*/
|
||||
protected CompletableFuture<Void> countdownStart() {
|
||||
return new Countdown(TitleMessage.class)
|
||||
.countdown(Audience.audience(getPlayers()), 5, countdownModifier -> {
|
||||
countdownModifier.message = new TitleMessage(Duration.ofMillis(300), Duration.ofMillis(700))
|
||||
.subtitle(subtitleMessage -> {
|
||||
subtitleMessage.appendStatic(Component.text("in ", NamedTextColor.DARK_GREEN))
|
||||
.appendStatic(Component.text(countdownModifier.timeLeft, NamedTextColor.GREEN))
|
||||
.appendStatic(Component.text(" seconds", NamedTextColor.DARK_GREEN));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void start() {
|
||||
countdownStart().thenRun(() -> {
|
||||
super.start();
|
||||
|
||||
if(timeLimit > 0) {
|
||||
scheduler().submitTask(() -> {
|
||||
System.out.println("Countdown running...");
|
||||
if(!isRunning || timeLimit == 0) return TaskSchedule.stop();
|
||||
if(timeLimit <= timePlayed) {
|
||||
stop();
|
||||
return TaskSchedule.stop();
|
||||
}
|
||||
|
||||
int timeLeft = timeLimit - timePlayed;
|
||||
switch (timeLeft) {
|
||||
case 60, 30, 10, 5, 4, 3, 2, 1 ->
|
||||
new ChatMessage(Icon.SCIENCE).appendStatic("Noch " + timeLeft + " Sekunden!").send(getPlayers());
|
||||
}
|
||||
|
||||
timePlayed++;
|
||||
|
||||
return TaskSchedule.seconds(1);
|
||||
}, ExecutionType.SYNC);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() {
|
||||
isRunning = false;
|
||||
this.onStop();
|
||||
|
||||
countdownUnload();
|
||||
}
|
||||
|
||||
protected void countdownUnload() {
|
||||
new TitleMessage(Duration.ofSeconds(1)).appendStatic("Finish").send(getPlayers());
|
||||
scheduler().scheduleTask(this::unload, TaskSchedule.seconds(5), TaskSchedule.stop());
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.deathcube.DeathcubeFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.minerun.MinerunFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.stickfight.StickFightFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.trafficlightrace.TrafficLightRaceFactory;
|
||||
|
||||
public enum MinigameType {
|
||||
DEATHCUBE(new DeathcubeFactory()),
|
||||
STICKFIGHT(new StickFightFactory()),
|
||||
MINERUN(new MinerunFactory()),
|
||||
TRAFFICLIGHTRACE(new TrafficLightRaceFactory());
|
||||
|
||||
private GameFactory factory;
|
||||
MinigameType(GameFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
public GameFactory getFactory() {
|
||||
return this.factory;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ConfigManager {
|
||||
private final ArrayList<Option<?>> items = new ArrayList<>();
|
||||
|
||||
public ConfigManager addOption(Option option) {
|
||||
items.add(option);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ArrayList<Option<?>> getAll() {
|
||||
return items;
|
||||
}
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.config;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.Game;
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import eu.mhsl.minenet.minigames.util.TextUtil;
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.inventory.condition.InventoryConditionResult;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class GameConfigurationInventory extends InteractableInventory {
|
||||
private final Map<Integer, Option<?>> map = new HashMap<>();
|
||||
|
||||
public GameConfigurationInventory(GameFactory factory) {
|
||||
super(InventoryType.CHEST_5_ROW, factory.name());
|
||||
ConfigManager config = factory.configuration();
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(Material.RED_WOOL).displayName(Component.text("Abbrechen", NamedTextColor.RED)).build(),
|
||||
0,
|
||||
itemClick -> itemClick.getPlayer().closeInventory(),
|
||||
true
|
||||
);
|
||||
|
||||
setDummyItem(Material.BLACK_STAINED_GLASS_PANE,1);
|
||||
|
||||
setDummyItem(
|
||||
ItemStack.builder(Material.NAME_TAG).displayName(factory.name()).build(),
|
||||
4
|
||||
);
|
||||
|
||||
setDummyItem(Material.BLACK_STAINED_GLASS_PANE,7);
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(Material.GREEN_WOOL).displayName(Component.text("Start", NamedTextColor.GREEN)).build(),
|
||||
8,
|
||||
itemClick -> {
|
||||
try {
|
||||
Game game = factory.manufacture(config != null ? config.getAll() : null);
|
||||
Room.getRoom(itemClick.getPlayer()).moveMembersToGame(game);
|
||||
game.load();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
for(int i = 9; i <= 17; i++) {
|
||||
setDummyItem(Material.BLACK_STAINED_GLASS_PANE, i);
|
||||
}
|
||||
|
||||
if(config == null) {
|
||||
setDummyItem(
|
||||
ItemStack.builder(Material.BARRIER).displayName(Component.text("Keine Optionen")).lore(TextUtil.autoWrap("Für dieses Spiel sind keine Einstellungen verfügbar!")).build(),
|
||||
31
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = 18;
|
||||
for(Option<?> item : config.getAll()) {
|
||||
map.put(pos, item);
|
||||
|
||||
setDummyItem(
|
||||
item.getCurrent(),
|
||||
pos++
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick(Player player, int slot, ClickType clickType, InventoryConditionResult inventoryConditionResult) {
|
||||
inventoryConditionResult.setCancel(true);
|
||||
|
||||
if(!map.containsKey(slot)) return;
|
||||
|
||||
Option item = map.get(slot);
|
||||
setDummyItem(
|
||||
item.getNext(),
|
||||
slot
|
||||
);
|
||||
|
||||
update();
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.config;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public interface GameFactory {
|
||||
Component name();
|
||||
ConfigManager configuration();
|
||||
|
||||
default Material symbol() {
|
||||
return Material.GRASS_BLOCK;
|
||||
};
|
||||
default Component description() {
|
||||
return Component.text("- Keine Beschreibung -");
|
||||
};
|
||||
|
||||
Minigame manufacture(Map<String, Option<?>> configuration);
|
||||
default Minigame manufacture(List<Option<?>> configuration) {
|
||||
if(configuration == null) return manufacture();
|
||||
Map<String, Option<?>> cnf = new HashMap<>();
|
||||
configuration.forEach(option -> cnf.put(option.getId(), option));
|
||||
return manufacture(cnf);
|
||||
}
|
||||
default Minigame manufacture() {
|
||||
if(this.configuration() == null) return manufacture(List.of());
|
||||
return manufacture(this.configuration().getAll());
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.config;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Option<T> {
|
||||
private final Material item;
|
||||
private final String name;
|
||||
private final String id;
|
||||
|
||||
protected T currentValue;
|
||||
private final List<T> options;
|
||||
private int pointer = 0;
|
||||
|
||||
public Option(String id, Material item, String name, List<T> options) {
|
||||
this.id = id;
|
||||
this.item = item;
|
||||
this.name = name;
|
||||
this.options = options;
|
||||
|
||||
currentValue = options.get(0);
|
||||
}
|
||||
|
||||
public ItemStack getNext() {
|
||||
if(++pointer >= options.size()) pointer = 0;
|
||||
currentValue = options.get(pointer);
|
||||
return getCurrent();
|
||||
}
|
||||
|
||||
public ItemStack getCurrent() {
|
||||
int amount = Integer.parseInt(options.get(pointer).toString());
|
||||
return ItemStack.builder(item)
|
||||
.displayName(Component.text(name).append(Component.text(" - ")).append(Component.text(amount)))
|
||||
.build();
|
||||
}
|
||||
|
||||
public int getAsInt() {
|
||||
return Integer.parseInt(getAsString());
|
||||
}
|
||||
|
||||
public String getAsString() {
|
||||
return currentValue.toString();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.config.options;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.Option;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BoolOption extends Option<Boolean> {
|
||||
public BoolOption(String id, Material item, String name) {
|
||||
super(id, item, name, List.of(true, false));
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.config.options;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.Option;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class NumericOption extends Option<Integer> {
|
||||
public NumericOption(String id, Material item, String name, Integer... options) {
|
||||
super(id, item, name, List.of(options));
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.deathcube;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.util.BatchUtil;
|
||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||
import eu.mhsl.minenet.minigames.world.generator.BlockPallet;
|
||||
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularTerrainGenerator;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
class Deathcube extends Minigame {
|
||||
|
||||
int radius, height, percentage;
|
||||
|
||||
public Deathcube(int radius, int height, int percentage) {
|
||||
super(Dimension.THE_END.DIMENSION, "Deathcube");
|
||||
this.radius = radius;
|
||||
this.height = height;
|
||||
this.percentage = percentage;
|
||||
this.setGenerator(new CircularTerrainGenerator(40, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad(CompletableFuture<Void> callback) {
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
|
||||
for(int x = -radius; x <= radius; x++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue;
|
||||
|
||||
for (int y = 49; y < height; y++) {
|
||||
if(super.rnd.nextInt(1, 100) <= percentage) {
|
||||
batch.setBlock(x, y, z, BlockPallet.WOOD.rnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
|
||||
super.onPlayerMove(playerMoveEvent);
|
||||
if(isBeforeBeginning) if(playerMoveEvent.getNewPosition().y() > 51.5) playerMoveEvent.setCancelled(true);
|
||||
if(playerMoveEvent.getNewPosition().y() > 100) getScore().addResult(playerMoveEvent.getPlayer());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pos getSpawn() {
|
||||
return new Pos(0, 50, 30);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.deathcube;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.Option;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.ConfigManager;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.options.NumericOption;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class DeathcubeFactory implements GameFactory {
|
||||
@Override
|
||||
public Component name() {
|
||||
return Component.text("Deathcube");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigManager configuration() {
|
||||
return new ConfigManager()
|
||||
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, "Radius", 10, 30, 50, 100))
|
||||
.addOption(new NumericOption("height", Material.SCAFFOLDING, "Height", 50, 100, 150, 200))
|
||||
.addOption(new NumericOption("percentage", Material.COBWEB, "Percent of blocks", 5, 7, 9, 11, 13));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Minigame manufacture(Map<String, Option<?>> configuration) {
|
||||
return new Deathcube(configuration.get("radius").getAsInt(), configuration.get("height").getAsInt(), configuration.get("percentage").getAsInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material symbol() {
|
||||
return Material.OAK_FENCE;
|
||||
}
|
||||
}
|
@ -0,0 +1,130 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.minerun;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.message.type.ActionBarMessage;
|
||||
import eu.mhsl.minenet.minigames.util.BatchUtil;
|
||||
import eu.mhsl.minenet.minigames.util.Intersect;
|
||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||
import eu.mhsl.minenet.minigames.world.generator.BlockPallet;
|
||||
import eu.mhsl.minenet.minigames.world.generator.terrain.SquareTerrainGenerator;
|
||||
import net.kyori.adventure.sound.Sound;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.sound.SoundEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
class Minerun extends Minigame {
|
||||
|
||||
private int minePercentage = 50;
|
||||
private int width = 100;
|
||||
private int length = 50;
|
||||
|
||||
private final int backRun = -5;
|
||||
private final int preRun = 5;
|
||||
private final int afterMines = 2;
|
||||
private final int afterFinishLine = 10;
|
||||
|
||||
public Minerun(int width, int length, int minePercentage) {
|
||||
super(Dimension.THE_END.DIMENSION, "Minerun");
|
||||
setGenerator(new SquareTerrainGenerator(width, length + preRun + afterFinishLine, true));
|
||||
|
||||
this.width = width;
|
||||
this.length = length;
|
||||
this.minePercentage = minePercentage;
|
||||
|
||||
System.out.println(width + " " + length + " " + minePercentage);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad(CompletableFuture<Void> callback) {
|
||||
int spawnToFinishLine = preRun + length + afterMines;
|
||||
int spawnToEnd = spawnToFinishLine + afterFinishLine;
|
||||
|
||||
Random random = new Random();
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
|
||||
for(int x = 0; x <= width; x++) {
|
||||
for(int z = preRun; z <= length + preRun; z++) {
|
||||
|
||||
if (random.nextInt(0, 100) < minePercentage) {
|
||||
batch.setBlock(x, 50, z, BlockPallet.PRESSURE_PLATES.rnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, String> properties = new HashMap<>() {
|
||||
{
|
||||
put("west", "true");
|
||||
put("east", "true");
|
||||
}
|
||||
};
|
||||
|
||||
for(int x = 0; x <= width; x++) {
|
||||
batch.setBlock(x, 49, spawnToFinishLine, Block.GOLD_BLOCK);
|
||||
batch.setBlock(x, 49, preRun, Block.GOLD_BLOCK);
|
||||
batch.setBlock(x, 50, preRun, Block.OAK_FENCE.withProperties(properties));
|
||||
}
|
||||
BatchUtil.loadAndApplyBatch(batch, this, () -> {
|
||||
callback.complete(null);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
for(int x = 0; x <= width; x++) {
|
||||
batch.setBlock(x, 50, preRun, Block.AIR);
|
||||
}
|
||||
|
||||
BatchUtil.loadAndApplyBatch(batch, this, () -> {
|
||||
playSound(Sound.sound(SoundEvent.BLOCK_WOOD_BREAK, Sound.Source.BLOCK, 1f, 1f));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
|
||||
|
||||
Player p = playerMoveEvent.getPlayer();
|
||||
Pos middle = playerMoveEvent.getNewPosition();
|
||||
|
||||
if(middle.x() < 0 || middle.x() > width) { //player cannot go sidewards
|
||||
playerMoveEvent.setCancelled(true);
|
||||
new ActionBarMessage().appendStatic(Component.text("Please stay in line!", NamedTextColor.RED)).send(p);
|
||||
}
|
||||
|
||||
if(!isRunning && middle.z() > preRun+0.5) { //player cannot go forward before game start
|
||||
playerMoveEvent.setCancelled(true);
|
||||
}
|
||||
|
||||
if(getScore().hasResult(p) && middle.z() < preRun + length + afterMines) { // player cannot go back
|
||||
playerMoveEvent.setCancelled(true);
|
||||
new ActionBarMessage().appendStatic(Component.text("You cannot go back on the Field!", NamedTextColor.RED)).send(p);
|
||||
return;
|
||||
}
|
||||
|
||||
if(Intersect.withPressurePlate(this, BlockPallet.PRESSURE_PLATES, middle)) { //Player died
|
||||
p.setPose(Entity.Pose.DYING);
|
||||
p.teleport(new Pos(p.getPosition().x(), getSpawn().y(), getSpawn().z()));
|
||||
p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.PLAYER, 1f, 1f));
|
||||
}
|
||||
|
||||
if(middle.z() > preRun + length + afterMines) { // Player finished
|
||||
getScore().addResult(p);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pos getSpawn() {
|
||||
return new Pos(width/2, 50, 3);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.minerun;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.ConfigManager;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.Option;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.options.NumericOption;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class MinerunFactory implements GameFactory {
|
||||
@Override
|
||||
public Component name() {
|
||||
return Component.text("Deathcube");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigManager configuration() {
|
||||
return new ConfigManager()
|
||||
.addOption(new NumericOption("width", Material.OAK_FENCE, "Width", 10, 30, 50, 100))
|
||||
.addOption(new NumericOption("length", Material.ZOMBIE_HEAD, "Length", 50, 100, 150, 200))
|
||||
.addOption(new NumericOption("percentage", Material.LIGHT_WEIGHTED_PRESSURE_PLATE, "Percent of mines", 30, 40, 50, 60, 70));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Minigame manufacture(Map<String, Option<?>> configuration) {
|
||||
System.out.println("Manufacture" + configuration.get("width").getAsInt());
|
||||
return new Minerun(configuration.get("width").getAsInt(), configuration.get("length").getAsInt(), configuration.get("percentage").getAsInt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material symbol() {
|
||||
return Material.LIGHT_WEIGHTED_PRESSURE_PLATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component description() {
|
||||
return Component.text("Weiche druckplatten aus");
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.stickfight;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.ConfigManager;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.Option;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class StickFightFactory implements GameFactory {
|
||||
@Override
|
||||
public Component name() {
|
||||
return Component.text("Stickfight");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigManager configuration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Minigame manufacture(Map<String, Option<?>> configuration) {
|
||||
return new Stickfight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material symbol() {
|
||||
return Material.STICK;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.stickfight;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.util.BatchUtil;
|
||||
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularTerrainGenerator;
|
||||
import eu.mhsl.minenet.minigames.world.generator.terrain.SquareTerrainGenerator;
|
||||
import io.github.bloepiloepi.pvp.PvpExtension;
|
||||
import io.github.bloepiloepi.pvp.config.*;
|
||||
import io.github.bloepiloepi.pvp.events.FinalAttackEvent;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.EventNode;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.event.trait.InstanceEvent;
|
||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class Stickfight extends Minigame {
|
||||
public Stickfight() {
|
||||
super(Dimension.OVERWORLD.DIMENSION, "Stickfight");
|
||||
|
||||
eventNode().addChild(
|
||||
PvPConfig.emptyBuilder()
|
||||
.damage(DamageConfig.legacyBuilder().fallDamage(false))
|
||||
.attack(AttackConfig.legacyBuilder().attackCooldown(true))
|
||||
.build().createNode()
|
||||
);
|
||||
|
||||
eventNode().addListener(FinalAttackEvent.class, finalAttackEvent -> {
|
||||
finalAttackEvent.setBaseDamage(0);
|
||||
((Player) finalAttackEvent.getTarget()).setHealth(20);
|
||||
});
|
||||
|
||||
setGenerator(new CircularTerrainGenerator(20, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad(CompletableFuture<Void> callback) {
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
for (int z = -10; z <= 10; z++) {
|
||||
batch.setBlock(0, 50, z, Block.SANDSTONE);
|
||||
}
|
||||
batch.setBlock(0, 50, 0, Block.GOLD_BLOCK);
|
||||
|
||||
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
|
||||
if(isBeforeBeginning) playerMoveEvent.setCancelled(true);
|
||||
|
||||
if(playerMoveEvent.getNewPosition().y() < 40) {
|
||||
playerMoveEvent.getPlayer().teleport(new Pos(0, 51, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onJoin(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pos getSpawn() {
|
||||
return new Pos(0.5, 51, 0.5);
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.trafficlightrace;
|
||||
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
enum LightPhase {
|
||||
RED(Material.RED_WOOL, 1000, 5000),
|
||||
YELLOW(Material.YELLOW_WOOL, 1000, 2000),
|
||||
GREEN(Material.GREEN_WOOL, 1000, 5000);
|
||||
|
||||
public final ItemStack item;
|
||||
private final int minDuration;
|
||||
private final int maxDuration;
|
||||
private static final Random rnd = new Random();
|
||||
|
||||
LightPhase(Material material, int minDuration, int maxDuration) {
|
||||
this.item = ItemStack.of(material);
|
||||
this.minDuration = minDuration;
|
||||
this.maxDuration = maxDuration;
|
||||
}
|
||||
|
||||
public TaskSchedule taskScheduleRandomDuration() {
|
||||
return TaskSchedule.millis(rnd.nextLong(minDuration, maxDuration));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.trafficlightrace;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.util.BatchUtil;
|
||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||
import net.minestom.server.coordinate.Vec;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
class TrafficLightRace extends Minigame {
|
||||
private LightPhase phase = LightPhase.RED;
|
||||
private int phaseCounter = 1;
|
||||
|
||||
public TrafficLightRace() {
|
||||
super(Dimension.THE_END.DIMENSION, "Ampelrennen");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLoad(CompletableFuture<Void> callback) {
|
||||
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
|
||||
for (int x = -10; x <= 10; x++) {
|
||||
for (int z = 5; z <= 100; z++) {
|
||||
batch.setBlock(x, 5, z, super.rnd.nextInt(0, 100) > 90 ? Block.SOUL_SAND : Block.BLACK_CONCRETE_POWDER);
|
||||
}
|
||||
}
|
||||
|
||||
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
scheduler().submitTask(() -> {
|
||||
if(!super.isRunning) return TaskSchedule.stop();
|
||||
|
||||
phaseCounter++;
|
||||
if(phaseCounter >= 4) phaseCounter = 0;
|
||||
|
||||
if(phaseCounter == 0) phase = LightPhase.RED;
|
||||
if(phaseCounter == 1 || phaseCounter == 3) phase = LightPhase.YELLOW;
|
||||
if(phaseCounter == 2) phase = LightPhase.GREEN;
|
||||
|
||||
getPlayers().forEach(player -> {
|
||||
for(int i = 0; i < 9; i++) {
|
||||
player.getInventory().setItemStack(i, phase.item);
|
||||
}
|
||||
});
|
||||
|
||||
return phase.taskScheduleRandomDuration();
|
||||
}, ExecutionType.SYNC);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
|
||||
super.onPlayerMove(playerMoveEvent);
|
||||
|
||||
if(playerMoveEvent.getNewPosition().z() > 110) stop();
|
||||
|
||||
if(phase.equals(LightPhase.RED) && playerMoveEvent.getNewPosition().z() > playerMoveEvent.getPlayer().getPosition().z()) {
|
||||
playerMoveEvent.getPlayer().setVelocity(new Vec(0, 5, -10));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package eu.mhsl.minenet.minigames.instance.game.minigame.types.trafficlightrace;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.Minigame;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.ConfigManager;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.Option;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class TrafficLightRaceFactory implements GameFactory {
|
||||
@Override
|
||||
public Component name() {
|
||||
return Component.text("TrafficLightRace");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigManager configuration() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Minigame manufacture(Map<String, Option<?>> configuration) {
|
||||
return new TrafficLightRace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Material symbol() {
|
||||
return Material.YELLOW_WOOL;
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package eu.mhsl.minenet.minigames.instance.hub;
|
||||
|
||||
import eu.mhsl.minenet.minigames.Resource;
|
||||
import eu.mhsl.minenet.minigames.instance.hub.entity.RoomSelector;
|
||||
import eu.mhsl.minenet.minigames.util.CommonEventHandles;
|
||||
import eu.mhsl.minenet.minigames.instance.Spawnable;
|
||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.event.player.*;
|
||||
import net.minestom.server.instance.AnvilLoader;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
public class HubInstance extends InstanceContainer implements Spawnable {
|
||||
public static final HubInstance INSTANCE = new HubInstance();
|
||||
|
||||
static {
|
||||
MinecraftServer.getInstanceManager().registerInstance(INSTANCE);
|
||||
|
||||
INSTANCE.setChunkLoader(new AnvilLoader(Resource.HUB_MAP.getPath()));
|
||||
|
||||
INSTANCE.eventNode()
|
||||
.addListener(PlayerBlockBreakEvent.class, CommonEventHandles::cancel)
|
||||
.addListener(PlayerBlockPlaceEvent.class, CommonEventHandles::cancel)
|
||||
.addListener(PlayerBlockInteractEvent.class, CommonEventHandles::cancel);
|
||||
|
||||
new RoomSelector().setInstance(INSTANCE, new Pos(0.5, 11, 4.5));
|
||||
}
|
||||
|
||||
private HubInstance() {
|
||||
super(UUID.randomUUID(), Dimension.THE_END.DIMENSION);
|
||||
setChunkLoader(new AnvilLoader(Path.of("maps/hub")));
|
||||
|
||||
setTime(18000);
|
||||
setTimeRate(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pos getSpawn() {
|
||||
return new Pos(0.5, 11, 0.5);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package eu.mhsl.minenet.minigames.instance.hub.entity;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.hub.inventory.HubInventory;
|
||||
import eu.mhsl.minenet.minigames.shared.entity.InteractableEntity;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.metadata.villager.AbstractVillagerMeta;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.event.player.PlayerEntityInteractEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class RoomSelector extends InteractableEntity {
|
||||
final AbstractVillagerMeta abstractVillagerMeta;
|
||||
public RoomSelector() {
|
||||
super(EntityType.VILLAGER);
|
||||
|
||||
abstractVillagerMeta = (AbstractVillagerMeta) this.getEntityMeta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpawn(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttack(@NotNull EntityAttackEvent entityAttackEvent) {
|
||||
super.onAttack(entityAttackEvent);
|
||||
abstractVillagerMeta.setHeadShakeTimer(20);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(@NotNull PlayerEntityInteractEvent playerEntityInteractEvent) {
|
||||
playerEntityInteractEvent.getPlayer().openInventory(new HubInventory());
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package eu.mhsl.minenet.minigames.instance.hub.inventory;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.item.ItemHideFlag;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
public class HubInventory extends InteractableInventory {
|
||||
public HubInventory() {
|
||||
super(InventoryType.CHEST_3_ROW, Component.text("MineNet Servernetzwerk"));
|
||||
|
||||
setClickableItem(
|
||||
ItemStack
|
||||
.builder(Material.WRITABLE_BOOK)
|
||||
.displayName(Component.text("Create own room"))
|
||||
.lore(Component.text("Create new empty room"))
|
||||
.meta(metaBuilder -> metaBuilder.hideFlag(ItemHideFlag.HIDE_ATTRIBUTES))
|
||||
.build(),
|
||||
12,
|
||||
itemClick -> Room.createRoom(itemClick.getPlayer()),
|
||||
true
|
||||
);
|
||||
|
||||
setClickableItem(
|
||||
ItemStack
|
||||
.builder(Material.KNOWLEDGE_BOOK)
|
||||
.displayName(Component.text("Browse room"))
|
||||
.lore(Component.text("Browse existing rooms"))
|
||||
.build(),
|
||||
14,
|
||||
itemClick -> itemClick.getPlayer().openInventory(new JoinInventory())
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package eu.mhsl.minenet.minigames.instance.hub.inventory;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import eu.mhsl.minenet.minigames.instance.hub.HubInstance;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.player.PlayerPacketEvent;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.inventory.condition.InventoryConditionResult;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.item.metadata.PlayerHeadMeta;
|
||||
import net.minestom.server.network.packet.client.play.ClientNameItemPacket;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class JoinInventory extends InteractableInventory {
|
||||
private String typedText = "";
|
||||
private final String prefix = "name:";
|
||||
|
||||
public JoinInventory() {
|
||||
super(InventoryType.ANVIL, Component.text("Enter username"));
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(Material.PLAYER_HEAD)
|
||||
.displayName(Component.text(prefix))
|
||||
.meta(PlayerHeadMeta.class, builder -> {
|
||||
|
||||
})
|
||||
.build(),
|
||||
0,
|
||||
itemClick -> {}
|
||||
);
|
||||
|
||||
HubInstance.INSTANCE.eventNode().addListener(PlayerPacketEvent.class, event -> {
|
||||
if (event.getPacket() instanceof ClientNameItemPacket packet) {
|
||||
typedText = packet.itemName();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick(Player player, int slot, ClickType clickType, InventoryConditionResult inventoryConditionResult) {
|
||||
if(slot != 2) return;
|
||||
inventoryConditionResult.setCancel(true);
|
||||
player.closeInventory();
|
||||
|
||||
typedText = formatInput(typedText);
|
||||
|
||||
Room target = Room.getRoom(MinecraftServer.getConnectionManager().findPlayer(typedText));
|
||||
if(target != null)
|
||||
Room.setRoom(player, target);
|
||||
else
|
||||
new ChatMessage(Icon.ERROR).appendStatic("The room").quote(typedText).appendStatic("could not be found!").send(player);
|
||||
}
|
||||
|
||||
private String formatInput(String raw) {
|
||||
if(raw.startsWith(prefix)) {
|
||||
raw = raw.split(prefix)[1];
|
||||
}
|
||||
|
||||
return raw.toLowerCase(Locale.ROOT).trim();
|
||||
}
|
||||
}
|
123
src/main/java/eu/mhsl/minenet/minigames/instance/room/Room.java
Normal file
123
src/main/java/eu/mhsl/minenet/minigames/instance/room/Room.java
Normal file
@ -0,0 +1,123 @@
|
||||
package eu.mhsl.minenet.minigames.instance.room;
|
||||
|
||||
import eu.mhsl.minenet.minigames.Resource;
|
||||
import eu.mhsl.minenet.minigames.instance.game.Game;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.util.CommonEventHandles;
|
||||
import eu.mhsl.minenet.minigames.util.MoveInstance;
|
||||
import eu.mhsl.minenet.minigames.instance.Spawnable;
|
||||
import eu.mhsl.minenet.minigames.instance.Dimension;
|
||||
import eu.mhsl.minenet.minigames.instance.hub.HubInstance;
|
||||
import eu.mhsl.minenet.minigames.instance.room.entity.GameSelector;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.player.PlayerBlockBreakEvent;
|
||||
import net.minestom.server.event.player.PlayerDisconnectEvent;
|
||||
import net.minestom.server.instance.AnvilLoader;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Room extends InstanceContainer implements Spawnable {
|
||||
private static final Map<Player, Room> rooms = new WeakHashMap<>();
|
||||
|
||||
public static Room createRoom(Player owner) {
|
||||
System.out.println("Room created by " + owner.getUsername());
|
||||
setRoom(owner, new Room(owner));
|
||||
return getRoom(owner);
|
||||
}
|
||||
|
||||
public static void deleteRoom(Room room) {
|
||||
System.out.println("Room deleted");
|
||||
rooms.values().removeAll(Collections.singleton(room)); // remove(room) would only remove the first one
|
||||
room.getAllMembers().forEach(player -> MoveInstance.move(player, HubInstance.INSTANCE));
|
||||
MoveInstance.forceCloseInstance(room);
|
||||
}
|
||||
|
||||
public static Room getRoom(Player p) {
|
||||
return rooms.get(p);
|
||||
}
|
||||
|
||||
public static void setOwnRoom(Player p) {
|
||||
setRoom(p, getRoom(p));
|
||||
}
|
||||
|
||||
public static void setRoom(Player p, Room room) {
|
||||
p.clearEffects();
|
||||
p.clearTitle();
|
||||
p.getInventory().clear();
|
||||
rooms.put(p, room);
|
||||
MoveInstance.move(p, room);
|
||||
}
|
||||
|
||||
public static void unsetRoom(Player p) {
|
||||
rooms.remove(p);
|
||||
}
|
||||
|
||||
public static Set<Room> getAllRooms() {
|
||||
return new HashSet<>(rooms.values());
|
||||
}
|
||||
|
||||
private Player owner;
|
||||
private Room(Player owner) {
|
||||
super(UUID.randomUUID(), Dimension.THE_END.DIMENSION);
|
||||
MinecraftServer.getInstanceManager().registerInstance(this);
|
||||
setChunkLoader(new AnvilLoader(Resource.LOBBY_MAP.getPath()));
|
||||
|
||||
eventNode().addListener(PlayerBlockBreakEvent.class, CommonEventHandles::cancel);
|
||||
|
||||
setOwner(owner);
|
||||
|
||||
new GameSelector().setInstance(this, new Pos(0.5, 16, 9.5));
|
||||
}
|
||||
|
||||
public Player getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
private void setOwner(Player newOwner) {
|
||||
this.owner = newOwner;
|
||||
|
||||
this.owner.eventNode().addListener(PlayerDisconnectEvent.class, playerDisconnectEvent -> {
|
||||
System.out.println("Room Leader left room");
|
||||
Player p = playerDisconnectEvent.getPlayer();
|
||||
|
||||
if(p != this.owner) return; // return if the current handling player is really the current owner
|
||||
|
||||
getAllMembers().stream()
|
||||
.filter(player -> player != p) // exclude the current leaving owner
|
||||
.findFirst() // find first user meeting the requirement
|
||||
.ifPresentOrElse(
|
||||
this::setOwner, // set the new owner
|
||||
() -> Room.deleteRoom(Room.getRoom(p)) // or else delete the room (no players in the room)
|
||||
);
|
||||
|
||||
Room.unsetRoom(p); // remove the player itself from the room
|
||||
|
||||
new ChatMessage(Icon.ERROR).appendStatic("The room leader left!").send(getAllMembers());
|
||||
new ChatMessage(Icon.SCIENCE).appendStatic(this.owner.getUsername()).appendStatic(" is the new Leader!").send(getAllMembers().stream().filter(player -> player != this.owner).collect(Collectors.toSet()));
|
||||
new ChatMessage(Icon.SUCCESS).appendStatic("You are now the leader.").send(this.owner);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void moveMembersToGame(Game game) {
|
||||
this.getAllMembers().forEach(player -> {
|
||||
MoveInstance.move(player, game);
|
||||
});
|
||||
}
|
||||
|
||||
public Set<Player> getAllMembers() {
|
||||
return rooms.keySet().stream()
|
||||
.filter(player -> getRoom(player) == this)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pos getSpawn() {
|
||||
return new Pos(0.5, 16, 0.5);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package eu.mhsl.minenet.minigames.instance.room.entity;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.room.Room;
|
||||
import eu.mhsl.minenet.minigames.instance.room.inventory.MinigameTypeSelectInventory;
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.shared.entity.InteractableEntity;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.metadata.villager.AbstractVillagerMeta;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.event.player.PlayerEntityInteractEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class GameSelector extends InteractableEntity {
|
||||
final AbstractVillagerMeta abstractVillagerMeta;
|
||||
public GameSelector() {
|
||||
super(EntityType.VILLAGER);
|
||||
|
||||
abstractVillagerMeta = (AbstractVillagerMeta) this.getEntityMeta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpawn(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttack(@NotNull EntityAttackEvent entityAttackEvent) {
|
||||
super.onAttack(entityAttackEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInteract(@NotNull PlayerEntityInteractEvent playerEntityInteractEvent) {
|
||||
Room room = (Room) instance;
|
||||
|
||||
if(playerEntityInteractEvent.getPlayer() != room.getOwner()) {
|
||||
abstractVillagerMeta.setHeadShakeTimer(20);
|
||||
|
||||
new ChatMessage(Icon.ERROR).appendStatic("Only the room leader can start games!").indent(1).newLine()
|
||||
.appendStatic("current leader: ").appendStatic(room.getOwner().getUsername())
|
||||
.send(playerEntityInteractEvent.getPlayer());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
playerEntityInteractEvent.getPlayer().openInventory(new MinigameTypeSelectInventory());
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package eu.mhsl.minenet.minigames.instance.room.inventory;
|
||||
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
|
||||
public class BoardInventory extends InteractableInventory {
|
||||
public BoardInventory() {
|
||||
super(InventoryType.CHEST_3_ROW, Component.text("Brettspiele"));
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package eu.mhsl.minenet.minigames.instance.room.inventory;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.MinigameType;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameConfigurationInventory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameFactory;
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.item.ItemHideFlag;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
public class MinigameTypeSelectInventory extends InteractableInventory {
|
||||
public MinigameTypeSelectInventory() {
|
||||
super(InventoryType.CHEST_3_ROW, Component.text("MineNet Servernetzwerk"));
|
||||
|
||||
int i = 0;
|
||||
for (MinigameType minigameType : MinigameType.values()) {
|
||||
GameFactory gameFactory = minigameType.getFactory();
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(gameFactory.symbol())
|
||||
.displayName(gameFactory.name())
|
||||
.lore(gameFactory.description())
|
||||
.meta(metaBuilder -> metaBuilder.hideFlag(ItemHideFlag.HIDE_ATTRIBUTES))
|
||||
.build(),
|
||||
i,
|
||||
itemClick -> itemClick.getPlayer().openInventory(new GameConfigurationInventory(gameFactory))
|
||||
);
|
||||
i++;
|
||||
}
|
||||
|
||||
// setClickableItem(
|
||||
// ItemStack
|
||||
// .builder(Material.IRON_SWORD)
|
||||
// .displayName(Component.text("PVP Spiele"))
|
||||
// .lore(Component.text("Player versus Player"))
|
||||
// .meta(metaBuilder -> metaBuilder.hideFlag(ItemHideFlag.HIDE_ATTRIBUTES))
|
||||
// .build(),
|
||||
// 11,
|
||||
// itemClick -> itemClick.getPlayer().openInventory(new PvpInventory())
|
||||
// );
|
||||
//
|
||||
// setClickableItem(
|
||||
// ItemStack
|
||||
// .builder(Material.ZOMBIE_HEAD)
|
||||
// .displayName(Component.text("PVE Arenen"))
|
||||
// .lore(Component.text("Player versus Entity"))
|
||||
// .build(),
|
||||
// 13,
|
||||
// itemClick -> itemClick.getPlayer().openInventory(new PveInventory())
|
||||
// );
|
||||
//
|
||||
// setClickableItem(
|
||||
// ItemStack
|
||||
// .builder(Material.BRICK_SLAB)
|
||||
// .displayName(Component.text("Brettspiele"))
|
||||
// .lore(Component.text("Bekannte Brettspieler aller Art"))
|
||||
// .build(),
|
||||
// 15,
|
||||
// itemClick -> itemClick.getPlayer().openInventory(new BoardInventory())
|
||||
// );
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
package eu.mhsl.minenet.minigames.instance.room.inventory;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameConfigurationInventory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.minerun.MinerunFactory;
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.deathcube.DeathcubeFactory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.trafficlightrace.TrafficLightRaceFactory;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
public class PveInventory extends InteractableInventory {
|
||||
public PveInventory() {
|
||||
super(InventoryType.CHEST_3_ROW, Component.text("PVE"));
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(Material.LIGHT_WEIGHTED_PRESSURE_PLATE).displayName(Component.text("Minerun")).lore(Component.text("Jump between ground mines to the finish")).build(),
|
||||
0,
|
||||
itemClick -> {
|
||||
itemClick.getPlayer().openInventory(new GameConfigurationInventory(new MinerunFactory()));
|
||||
}
|
||||
);
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(Material.YELLOW_WOOL).displayName(Component.text("Ampelrennen")).build(),
|
||||
1,
|
||||
itemClick -> {
|
||||
itemClick.getPlayer().openInventory(new GameConfigurationInventory(new TrafficLightRaceFactory()));
|
||||
}
|
||||
);
|
||||
|
||||
setClickableItem(
|
||||
ItemStack.builder(Material.RED_WOOL).displayName(Component.text("Deathcube")).build(),
|
||||
2,
|
||||
itemClick -> {
|
||||
itemClick.getPlayer().openInventory(new GameConfigurationInventory(new DeathcubeFactory()));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package eu.mhsl.minenet.minigames.instance.room.inventory;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.config.GameConfigurationInventory;
|
||||
import eu.mhsl.minenet.minigames.instance.game.minigame.types.stickfight.StickFightFactory;
|
||||
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.inventory.condition.InventoryConditionResult;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
|
||||
public class PvpInventory extends InteractableInventory {
|
||||
public PvpInventory() {
|
||||
super(InventoryType.CHEST_6_ROW, Component.text("PVP"));
|
||||
|
||||
setClickableItem(ItemStack.of(Material.GOLD_INGOT), 4, itemClick -> {
|
||||
itemClick.getPlayer().openInventory(new GameConfigurationInventory(new StickFightFactory()));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClick(Player player, int slot, ClickType clickType, InventoryConditionResult inventoryConditionResult) {
|
||||
super.onClick(player, slot, clickType, inventoryConditionResult);
|
||||
}
|
||||
}
|
12
src/main/java/eu/mhsl/minenet/minigames/lang/DummyLang.java
Normal file
12
src/main/java/eu/mhsl/minenet/minigames/lang/DummyLang.java
Normal file
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.minenet.minigames.lang;
|
||||
|
||||
public class DummyLang extends Lang {
|
||||
public DummyLang() {
|
||||
super("dummy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntry(String key) {
|
||||
return "translation:" + key;
|
||||
}
|
||||
}
|
30
src/main/java/eu/mhsl/minenet/minigames/lang/Lang.java
Normal file
30
src/main/java/eu/mhsl/minenet/minigames/lang/Lang.java
Normal file
@ -0,0 +1,30 @@
|
||||
package eu.mhsl.minenet.minigames.lang;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class Lang {
|
||||
|
||||
private String langId;
|
||||
private Map<String, String> entries = new HashMap<>();
|
||||
|
||||
public Lang(String langId) {
|
||||
this.langId = langId;
|
||||
}
|
||||
|
||||
public void addEntry(String key, String value) {
|
||||
entries.put(key, value);
|
||||
}
|
||||
|
||||
public String getEntry(String key) {
|
||||
return entries.computeIfAbsent(key, s -> {
|
||||
Logger.getLogger("localisation").warning(s + " is not known by translation files!");
|
||||
return new DummyLang().getEntry(s);
|
||||
});
|
||||
}
|
||||
|
||||
public String getLangId() {
|
||||
return langId;
|
||||
}
|
||||
}
|
105
src/main/java/eu/mhsl/minenet/minigames/lang/Languages.java
Normal file
105
src/main/java/eu/mhsl/minenet/minigames/lang/Languages.java
Normal file
@ -0,0 +1,105 @@
|
||||
package eu.mhsl.minenet.minigames.lang;
|
||||
|
||||
import eu.mhsl.minenet.minigames.Resource;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Languages {
|
||||
private static Languages instance;
|
||||
private boolean blockAccess = false;
|
||||
|
||||
private Map<String, Lang> languages = new HashMap<>();
|
||||
|
||||
public static Languages getInstance() {
|
||||
if(instance == null) instance = new Languages();
|
||||
return instance;
|
||||
}
|
||||
|
||||
private Languages() {
|
||||
readAll();
|
||||
}
|
||||
|
||||
public Lang getLanguage(Player p) {
|
||||
return getLanguage(p.getSettings().getLocale());
|
||||
}
|
||||
public Lang getLanguage(String mapId) {
|
||||
return languages.computeIfAbsent(mapId, unused -> languages.computeIfAbsent("en_us", (key) -> new DummyLang()));
|
||||
}
|
||||
|
||||
private void readAll() {
|
||||
File locales = new File(Resource.LOCALES.getPath().toString());
|
||||
File[] files = locales.listFiles(File::canRead);
|
||||
|
||||
if(files.length == 0) {
|
||||
System.err.println("Failed to find any Language-files!");
|
||||
return;
|
||||
}
|
||||
|
||||
for(File locale : files) {
|
||||
try {
|
||||
System.out.print("reading translation " + locale.getName() + " ... ");
|
||||
|
||||
Map<Integer, Lang> langColumn = new HashMap<>();
|
||||
String namespace = "";
|
||||
boolean computedFileHeader = false;
|
||||
|
||||
for(String line : Files.readAllLines(locale.toPath())) {
|
||||
line = line.replaceAll("[^\\p{L}\\s,#_+.:;]+", "");
|
||||
String[] columns = line.split(";");
|
||||
|
||||
if(columns.length < 1) continue;
|
||||
|
||||
if(columns[0].equalsIgnoreCase("map")) {
|
||||
|
||||
// file header
|
||||
computedFileHeader = true;
|
||||
int index = -1;
|
||||
for(String langId : columns) {
|
||||
index++;
|
||||
if(langId.endsWith("map")) continue;
|
||||
|
||||
languages.computeIfAbsent(langId, Lang::new);
|
||||
Lang lang = languages.get(langId);
|
||||
langColumn.put(index, lang);
|
||||
languages.put(langId, lang);
|
||||
}
|
||||
|
||||
} else if(columns[0].startsWith("ns:")) {
|
||||
if(!computedFileHeader) throw new IllegalStateException("Cannot compute namespace data before file-header was red!");
|
||||
namespace = columns[0].split(":")[1];
|
||||
|
||||
} else {
|
||||
|
||||
// file contents
|
||||
if(!computedFileHeader) throw new IllegalStateException("Cannot compute translation data before file-header was red!");
|
||||
int index = 0;
|
||||
String mapId = "";
|
||||
for(String translation : columns) {
|
||||
if(index == 0) {
|
||||
// store map name
|
||||
mapId = translation;
|
||||
} else {
|
||||
// add map name and value
|
||||
langColumn.get(index).addEntry(namespace + mapId, translation);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("ok");
|
||||
} catch (Exception e) {
|
||||
System.out.println("fail: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
package eu.mhsl.minenet.minigames.message;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Countdown {
|
||||
public Countdown(Class<? extends TranslatableMessage> messageType) {
|
||||
}
|
||||
public CompletableFuture<Void> countdown(Audience targets, int from, Consumer<CountdownModifier> modifier) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
AtomicInteger count = new AtomicInteger(from);
|
||||
MinecraftServer.getSchedulerManager().submitTask(() -> {
|
||||
if(count.get() <= 0) {
|
||||
future.complete(null);
|
||||
return TaskSchedule.stop();
|
||||
}
|
||||
try {
|
||||
CountdownModifier countdownModifier = new CountdownModifier(count.getAndDecrement());
|
||||
modifier.accept(countdownModifier);
|
||||
countdownModifier.message.send(targets);
|
||||
System.out.println("SEND TITLE" + System.currentTimeMillis());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return TaskSchedule.seconds(1);
|
||||
});
|
||||
return future;
|
||||
}
|
||||
|
||||
|
||||
public static class CountdownModifier {
|
||||
public TranslatableMessage message;
|
||||
public final int timeLeft;
|
||||
public CountdownModifier(int timeLeft) {
|
||||
this.timeLeft = timeLeft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
31
src/main/java/eu/mhsl/minenet/minigames/message/Icon.java
Normal file
31
src/main/java/eu/mhsl/minenet/minigames/message/Icon.java
Normal file
@ -0,0 +1,31 @@
|
||||
package eu.mhsl.minenet.minigames.message;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public enum Icon {
|
||||
SCIENCE("\uD83E\uDDEA", NamedTextColor.LIGHT_PURPLE),
|
||||
STAR("\u2606", NamedTextColor.GOLD),
|
||||
CHAT("\u276F\u276F", NamedTextColor.WHITE),
|
||||
SUCCESS("\u2714", NamedTextColor.GREEN),
|
||||
ERROR("\u274C", NamedTextColor.RED);
|
||||
|
||||
private final String symbol;
|
||||
private final NamedTextColor color;
|
||||
Icon(String symbol, NamedTextColor color) {
|
||||
this.symbol = symbol;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public String getSymbol() {
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public NamedTextColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Component getComponent() {
|
||||
return Component.text(getSymbol(), getColor());
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
package eu.mhsl.minenet.minigames.message;
|
||||
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
//TODO maybe async large batches
|
||||
public interface Sendable {
|
||||
void send(Player p);
|
||||
|
||||
default void send(Audience players) {
|
||||
players.forEachAudience(audience -> {
|
||||
this.send((Player) audience);
|
||||
});
|
||||
}
|
||||
|
||||
default void send(List<Player> players) {
|
||||
players.forEach(this::send);
|
||||
}
|
||||
|
||||
default void send(Set<Player> players) {
|
||||
players.forEach(this::send);
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package eu.mhsl.minenet.minigames.message;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.component.Translatable;
|
||||
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentBuilder;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class TranslatableMessage implements Sendable {
|
||||
int indention = 0;
|
||||
List<ComponentLike> chain = new ArrayList<>();
|
||||
|
||||
public TranslatableMessage() {
|
||||
|
||||
}
|
||||
|
||||
public TranslatableMessage appendStatic(Component component) {
|
||||
chain.add(component);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage appendStatic(String text) {
|
||||
chain.add(Component.text(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage appendTranslated(String mapId) {
|
||||
chain.add(new TranslatedComponent(mapId));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage list(List<String> list) {
|
||||
list.forEach(s -> {
|
||||
chain.add(Component.text(s));
|
||||
newLine();
|
||||
});
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage pipe() {
|
||||
chain.add(Component.text(" | ", NamedTextColor.DARK_GRAY));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage quote(String text) {
|
||||
chain.add(Component.text("'" + text + "'"));
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage indent(int amount) {
|
||||
this.indention += amount;
|
||||
this.newLine();
|
||||
return this;
|
||||
}
|
||||
|
||||
public TranslatableMessage newLine() {
|
||||
chain.add(Component.text(" ".repeat(indention) + "\n"));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Component build(Player p) {
|
||||
ComponentBuilder out = Component.text();
|
||||
chain.forEach(componentLike -> {
|
||||
if(componentLike instanceof Translatable t) t.compute(p);
|
||||
|
||||
out.append(componentLike);
|
||||
});
|
||||
return out.build();
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package eu.mhsl.minenet.minigames.message.component;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public interface Translatable {
|
||||
void compute(Player p);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package eu.mhsl.minenet.minigames.message.component;
|
||||
|
||||
import eu.mhsl.minenet.minigames.lang.Languages;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.ComponentLike;
|
||||
import net.minestom.server.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TranslatedComponent implements ComponentLike, Translatable {
|
||||
private String mapId;
|
||||
private String result;
|
||||
|
||||
public TranslatedComponent(String mapId) {
|
||||
this.mapId = mapId;
|
||||
}
|
||||
|
||||
public void compute(Player p) {
|
||||
result = Languages.getInstance().getLanguage(p).getEntry(mapId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component asComponent() {
|
||||
return Component.text(result);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package eu.mhsl.minenet.minigames.message.type;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class ActionBarMessage extends TranslatableMessage {
|
||||
@Override
|
||||
public void send(Player p) {
|
||||
p.sendActionBar(build(p));
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package eu.mhsl.minenet.minigames.message.type;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
public class ChatMessage extends TranslatableMessage {
|
||||
public ChatMessage(Icon icon) {
|
||||
appendStatic(icon.getComponent());
|
||||
pipe();
|
||||
}
|
||||
|
||||
public void send(Player p) {
|
||||
p.sendMessage(build(p));
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package eu.mhsl.minenet.minigames.message.type;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import javax.management.RuntimeErrorException;
|
||||
|
||||
public class SubtitleMessage extends TranslatableMessage {
|
||||
@Override
|
||||
public void send(Player p) {
|
||||
throw new RuntimeErrorException(new Error("Cannot send subtitle-only to player"));
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
package eu.mhsl.minenet.minigames.message.type;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
|
||||
import net.kyori.adventure.audience.Audience;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.title.Title;
|
||||
import net.kyori.adventure.title.TitlePart;
|
||||
import net.minestom.server.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.UnknownNullability;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TitleMessage extends TranslatableMessage {
|
||||
private Title.Times times;
|
||||
private SubtitleMessage subtitle = new SubtitleMessage();
|
||||
|
||||
public TitleMessage() {
|
||||
times = Title.Times.times(Duration.ZERO, Duration.ofSeconds(1), Duration.ZERO);
|
||||
}
|
||||
public TitleMessage(Duration stay) {
|
||||
times = Title.Times.times(Duration.ZERO, stay, Duration.ZERO);
|
||||
}
|
||||
public TitleMessage(Duration stay, Duration fade) {
|
||||
times = Title.Times.times(fade, stay, fade);
|
||||
}
|
||||
|
||||
public void setTimes(Title.Times times) {
|
||||
this.times = times;
|
||||
}
|
||||
|
||||
public TranslatableMessage subtitle(Consumer<SubtitleMessage> callback) {
|
||||
this.subtitle = new SubtitleMessage();
|
||||
callback.accept(subtitle);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(Player p) {
|
||||
Audience.audience(p).showTitle(new Title() {
|
||||
@Override
|
||||
public @NotNull Component title() {
|
||||
return build(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component subtitle() {
|
||||
return subtitle.build(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable Times times() {
|
||||
return times;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> @UnknownNullability T part(@NotNull TitlePart<T> part) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
90
src/main/java/eu/mhsl/minenet/minigames/score/Score.java
Normal file
90
src/main/java/eu/mhsl/minenet/minigames/score/Score.java
Normal file
@ -0,0 +1,90 @@
|
||||
package eu.mhsl.minenet.minigames.score;
|
||||
|
||||
import eu.mhsl.minenet.minigames.message.Icon;
|
||||
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
|
||||
import eu.mhsl.minenet.minigames.message.type.TitleMessage;
|
||||
import eu.mhsl.minenet.minigames.instance.game.Game;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.event.Event;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
|
||||
import net.minestom.server.event.player.PlayerDisconnectEvent;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
|
||||
public class Score {
|
||||
|
||||
private boolean closed = false;
|
||||
private final HashMap<Player, Integer> results = new HashMap<>();
|
||||
protected final Game instance;
|
||||
private Runnable callback;
|
||||
|
||||
public Score(Game instance) {
|
||||
this.instance = instance;
|
||||
|
||||
this.callback = instance::stop;
|
||||
|
||||
instance.eventNode()
|
||||
.addListener(AddEntityToInstanceEvent.class, this::checkGameEnd)
|
||||
.addListener(RemoveEntityFromInstanceEvent.class, this::checkGameEnd)
|
||||
.addListener(PlayerDisconnectEvent.class, this::checkGameEnd);
|
||||
}
|
||||
|
||||
public void onClose(Runnable callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
private void checkGameEnd(Event e) {
|
||||
if(closed) return;
|
||||
if(instance.getPlayers().size() < 1) return;
|
||||
if(countResults() >= instance.getPlayers().size()) {
|
||||
callback.run();
|
||||
|
||||
new ChatMessage(Icon.STAR)
|
||||
.appendStatic("Ergebnisse:").indent(1)
|
||||
.list(getMapFormatted())
|
||||
.indent(-1).newLine()
|
||||
.appendStatic("Vielen Dank für's Spielen!")
|
||||
.send(instance.getPlayers());
|
||||
|
||||
closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void addResult(Player p) {
|
||||
if(closed) return;
|
||||
if(results.containsKey(p)) return;
|
||||
results.put(p, countResults()+1);
|
||||
|
||||
new TitleMessage(Duration.ofMillis(500), Duration.ofSeconds(1)).appendStatic(Component.text("Fertig", NamedTextColor.GREEN)).send(p);
|
||||
|
||||
checkGameEnd(null);
|
||||
}
|
||||
|
||||
public boolean hasResult(Player p) {
|
||||
return results.containsKey(p);
|
||||
}
|
||||
|
||||
public HashMap<Player, Integer> getMap() {
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<String> getMapFormatted() {
|
||||
List<String> out = new ArrayList<>();
|
||||
|
||||
int counter = 0;
|
||||
for (Map.Entry<Player, Integer> entry : getMap().entrySet()) {
|
||||
out.add(entry.getValue() + ": " + entry.getKey().getUsername());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
public int countResults() {
|
||||
return results.size();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package eu.mhsl.minenet.minigames.server.provider;
|
||||
|
||||
import eu.mhsl.minenet.minigames.util.UuidUtil;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.network.UuidProvider;
|
||||
import net.minestom.server.network.player.PlayerConnection;
|
||||
import net.minestom.server.utils.mojang.MojangUtils;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ByPlayerNameUuidProvider implements UuidProvider {
|
||||
@Override
|
||||
public UUID provide(PlayerConnection playerConnection, String username) {
|
||||
try {
|
||||
|
||||
if(MinecraftServer.getConnectionManager().getPlayer(username) != null) throw new IllegalStateException();
|
||||
String client = MojangUtils.fromUsername(username).get("id").getAsString();
|
||||
return UuidUtil.unTrimm(client);
|
||||
|
||||
} catch (NullPointerException e) {
|
||||
|
||||
Logger.getGlobal().info("Player " + username + " is an known by Mojang! (Using random UUID)");
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
|
||||
Logger.getGlobal().info("Player with the username " + username + " is already online. (Using random UUID)");
|
||||
playerConnection.disconnect();
|
||||
}
|
||||
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package eu.mhsl.minenet.minigames.server.tasks;
|
||||
|
||||
import eu.mhsl.minenet.minigames.util.Monitoring;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.adventure.audience.Audiences;
|
||||
import net.minestom.server.entity.Player;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class TablistUpdateTask implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
Collection<Player> players = MinecraftServer.getConnectionManager().getOnlinePlayers();
|
||||
if (players.isEmpty()) return;
|
||||
|
||||
final Component header =
|
||||
Component.newline()
|
||||
.append(Component.text("MineNet Network", NamedTextColor.GOLD))
|
||||
.append(Component.newline()).append(Component.text("Players: " + players.size()))
|
||||
.append(Component.newline())
|
||||
.append(Component.newline()).append(Component.text("RAM: " + Monitoring.getRamUsage() + " MB", NamedTextColor.GRAY))
|
||||
.append(Component.newline()).append(Component.text("TICK: " + Monitoring.getTickMonitor().getTickTime() + "ms", NamedTextColor.GRAY))
|
||||
.append(Component.newline());
|
||||
|
||||
final Component footer =
|
||||
Component.newline()
|
||||
.append(Component.text("mhsl.eu"))
|
||||
.append(Component.newline());
|
||||
|
||||
Audiences.players().sendPlayerListHeaderAndFooter(header, footer);
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package eu.mhsl.minenet.minigames.shared.entity;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.Spawnable;
|
||||
import net.minestom.server.entity.EntityCreature;
|
||||
import net.minestom.server.entity.EntityType;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.ai.target.ClosestEntityTarget;
|
||||
import net.minestom.server.event.entity.EntityAttackEvent;
|
||||
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
|
||||
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
|
||||
import net.minestom.server.event.player.PlayerEntityInteractEvent;
|
||||
import net.minestom.server.event.player.PlayerMoveEvent;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class InteractableEntity extends EntityCreature {
|
||||
|
||||
/**
|
||||
* Declares an Entity with direct callbacks on interaction
|
||||
* @param entityType type of entity
|
||||
*/
|
||||
public InteractableEntity(@NotNull EntityType entityType) {
|
||||
super(entityType);
|
||||
|
||||
eventNode()
|
||||
.addListener(AddEntityToInstanceEvent.class, this::setInstanceEvent)
|
||||
|
||||
.addListener(AddEntityToInstanceEvent.class, this::onSpawn)
|
||||
.addListener(RemoveEntityFromInstanceEvent.class, this::onDespawn)
|
||||
.addListener(PlayerEntityInteractEvent.class, this::onInteract)
|
||||
.addListener(EntityAttackEvent.class, this::onAttack);
|
||||
}
|
||||
|
||||
private void setInstanceEvent(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {
|
||||
if(addEntityToInstanceEvent.getInstance() instanceof Spawnable instance) {
|
||||
scheduleNextTick((unused) -> {
|
||||
this.lookAt(instance.getSpawn()); //TODO only works someitmes?
|
||||
});
|
||||
}
|
||||
|
||||
addEntityToInstanceEvent.getInstance().eventNode()
|
||||
.addListener(PlayerEntityInteractEvent.class, playerEntityInteractEvent -> {
|
||||
if(playerEntityInteractEvent.getTarget() == this) onInteract(playerEntityInteractEvent);
|
||||
})
|
||||
.addListener(EntityAttackEvent.class, entityAttackEvent -> {
|
||||
if(entityAttackEvent.getTarget() == this) onAttack(entityAttackEvent);
|
||||
})
|
||||
.addListener(PlayerMoveEvent.class, playerMoveEvent -> {
|
||||
//TODO this is heavy in production
|
||||
//maybe store the player and update to the closest Entity only periodic
|
||||
scheduler().submitTask(() -> {
|
||||
setTarget(new ClosestEntityTarget(this, 5, entity -> entity instanceof Player).findTarget());
|
||||
if(getTarget() != null) lookAt(getTarget());
|
||||
|
||||
return TaskSchedule.stop();
|
||||
}, ExecutionType.ASYNC);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when instance of entity is set
|
||||
* @param addEntityToInstanceEvent
|
||||
*/
|
||||
protected void onSpawn(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when instance of entity is unset
|
||||
* @param removeEntityFromInstanceEvent
|
||||
*/
|
||||
protected void onDespawn(@NotNull RemoveEntityFromInstanceEvent removeEntityFromInstanceEvent) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a Player interacts with the entity
|
||||
* @param playerEntityInteractEvent
|
||||
*/
|
||||
protected void onInteract(@NotNull PlayerEntityInteractEvent playerEntityInteractEvent) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a Player attacks the entity
|
||||
* @param entityAttackEvent
|
||||
*/
|
||||
protected void onAttack(@NotNull EntityAttackEvent entityAttackEvent) {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
package eu.mhsl.minenet.minigames.shared.inventory;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.InventoryType;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.inventory.condition.InventoryConditionResult;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class InteractableInventory extends Inventory {
|
||||
/**
|
||||
* Defines an Inventory with direct callbacks for ItemSlots
|
||||
* @param inventoryType
|
||||
* @param title
|
||||
*/
|
||||
protected InteractableInventory(@NotNull InventoryType inventoryType, @NotNull Component title) {
|
||||
super(inventoryType, title);
|
||||
|
||||
addInventoryCondition(this::onClick);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Item with Callback
|
||||
* @param item
|
||||
* @param slot
|
||||
* @param callback
|
||||
*/
|
||||
protected void setClickableItem(ItemStack item, int slot, Consumer<ItemClick> callback, boolean closeAfter) {
|
||||
setItemStack(slot, item);
|
||||
addInventoryCondition((player, clickedSlot, clickType, inventoryConditionResult) -> {
|
||||
if(clickedSlot == slot) {
|
||||
if(closeAfter) player.closeInventory();
|
||||
callback.accept(new ItemClick(player, this, clickedSlot, item, clickType));
|
||||
}
|
||||
inventoryConditionResult.setCancel(true);
|
||||
});
|
||||
}
|
||||
|
||||
protected void setClickableItem(ItemStack item, int slot, Consumer<ItemClick> callback) {
|
||||
this.setClickableItem(item, slot, callback, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Item without handler
|
||||
* @param item
|
||||
* @param slot
|
||||
*/
|
||||
protected void setDummyItem(ItemStack item, int slot) {
|
||||
this.setClickableItem(
|
||||
item,
|
||||
slot,
|
||||
itemClick -> {}
|
||||
);
|
||||
}
|
||||
|
||||
protected void setDummyItem(Material material, int slot) {
|
||||
this.setDummyItem(
|
||||
ItemStack.builder(material).displayName(Component.text("")).build(),
|
||||
slot
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* You may want to Override this method to get more generic click events
|
||||
* @param player
|
||||
* @param slot
|
||||
* @param clickType
|
||||
* @param inventoryConditionResult
|
||||
*/
|
||||
protected void onClick(Player player, int slot, ClickType clickType, InventoryConditionResult inventoryConditionResult) {
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
package eu.mhsl.minenet.minigames.shared.inventory;
|
||||
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.inventory.Inventory;
|
||||
import net.minestom.server.inventory.click.ClickType;
|
||||
import net.minestom.server.item.ItemStack;
|
||||
|
||||
public class ItemClick {
|
||||
private final Player player;
|
||||
private final InteractableInventory inventory;
|
||||
private final int clickedSlot;
|
||||
private final ItemStack item;
|
||||
private final ClickType clickType;
|
||||
|
||||
/**
|
||||
* Describes a click on an Item from an IntractableInventory
|
||||
* @param player
|
||||
* @param inventory
|
||||
* @param clickedSlot
|
||||
* @param item
|
||||
* @param clickType
|
||||
*/
|
||||
public ItemClick(Player player, InteractableInventory inventory, int clickedSlot, ItemStack item, ClickType clickType) {
|
||||
this.player = player;
|
||||
this.inventory = inventory;
|
||||
this.clickedSlot = clickedSlot;
|
||||
this.item = item;
|
||||
this.clickType = clickType;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
public int getClickedSlot() {
|
||||
return clickedSlot;
|
||||
}
|
||||
|
||||
public ItemStack getItem() {
|
||||
return item;
|
||||
}
|
||||
|
||||
public ClickType getClickType() {
|
||||
return clickType;
|
||||
}
|
||||
}
|
33
src/main/java/eu/mhsl/minenet/minigames/skin/SkinCache.java
Normal file
33
src/main/java/eu/mhsl/minenet/minigames/skin/SkinCache.java
Normal file
@ -0,0 +1,33 @@
|
||||
package eu.mhsl.minenet.minigames.skin;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.entity.PlayerSkin;
|
||||
import net.minestom.server.thread.Acquirable;
|
||||
import net.minestom.server.thread.Acquired;
|
||||
import net.minestom.server.timer.ExecutionType;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class SkinCache {
|
||||
private static final Map<String, PlayerSkin> skins = new HashMap<>();
|
||||
|
||||
public static PlayerSkin getSkin(Player p) {
|
||||
return SkinCache.getSkin(p.getUsername());
|
||||
}
|
||||
|
||||
public static PlayerSkin getSkin(String p) {
|
||||
if(!skins.containsKey(p)) skins.put(p, PlayerSkin.fromUsername(p));
|
||||
return skins.get(p);
|
||||
}
|
||||
|
||||
public static void applySkin(Player p) {
|
||||
MinecraftServer.getSchedulerManager().submitTask(() -> {
|
||||
p.setSkin(SkinCache.getSkin(p.getUsername()));
|
||||
return TaskSchedule.stop();
|
||||
}, ExecutionType.ASYNC);
|
||||
}
|
||||
}
|
32
src/main/java/eu/mhsl/minenet/minigames/util/BatchUtil.java
Normal file
32
src/main/java/eu/mhsl/minenet/minigames/util/BatchUtil.java
Normal file
@ -0,0 +1,32 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
|
||||
import net.minestom.server.instance.batch.ChunkBatch;
|
||||
import net.minestom.server.utils.chunk.ChunkUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
public class BatchUtil {
|
||||
public static long[] getAffectedChunks(AbsoluteBlockBatch batch) {
|
||||
try {
|
||||
Field field = batch.getClass().getDeclaredField("chunkBatchesMap");
|
||||
field.setAccessible(true);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
Long2ObjectMap<ChunkBatch> chunkBatchesMap = (Long2ObjectMap<ChunkBatch>) field.get(batch);
|
||||
|
||||
return chunkBatchesMap.keySet().toLongArray();
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void loadAndApplyBatch(AbsoluteBlockBatch batch, InstanceContainer instance, Runnable onFinish) {
|
||||
batch.awaitReady();
|
||||
long[] affectedChunks = BatchUtil.getAffectedChunks(batch);
|
||||
ChunkUtils.optionalLoadAll(instance, affectedChunks, null).thenRun(() -> batch.apply(instance, onFinish));
|
||||
}
|
||||
|
||||
}
|
15
src/main/java/eu/mhsl/minenet/minigames/util/ColorUtil.java
Normal file
15
src/main/java/eu/mhsl/minenet/minigames/util/ColorUtil.java
Normal file
@ -0,0 +1,15 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
public class ColorUtil {
|
||||
public static NamedTextColor scoreColor(int score) {
|
||||
switch (score) {
|
||||
case 1: return NamedTextColor.GOLD;
|
||||
case 2: return NamedTextColor.GREEN;
|
||||
case 3: return NamedTextColor.DARK_GREEN;
|
||||
}
|
||||
|
||||
return NamedTextColor.GRAY;
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import net.minestom.server.event.trait.CancellableEvent;
|
||||
|
||||
public class CommonEventHandles {
|
||||
/**
|
||||
* Cancels the given Event
|
||||
* @param event
|
||||
*/
|
||||
public static void cancel(CancellableEvent event) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
public static void cancel(CancellableEvent event, boolean condition) {
|
||||
event.setCancelled(condition);
|
||||
}
|
||||
}
|
27
src/main/java/eu/mhsl/minenet/minigames/util/Intersect.java
Normal file
27
src/main/java/eu/mhsl/minenet/minigames/util/Intersect.java
Normal file
@ -0,0 +1,27 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import eu.mhsl.minenet.minigames.world.generator.BlockPallet;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
public class Intersect {
|
||||
public static boolean withPressurePlate(Instance instance, BlockPallet target, Pos playerPosition) {
|
||||
Pos[] corners = {
|
||||
playerPosition.add(0.3-Position.PIXEL, 0, 0.3-Position.PIXEL),
|
||||
playerPosition.add(0.3-Position.PIXEL, 0, -0.3+Position.PIXEL),
|
||||
playerPosition.add(-0.3+Position.PIXEL, 0, 0.3-Position.PIXEL),
|
||||
playerPosition.add(-0.3+Position.PIXEL, 0, -0.3+Position.PIXEL)
|
||||
};
|
||||
|
||||
for(Pos coroner : corners) {
|
||||
Block pressed = instance.getBlock(coroner);
|
||||
if(target.contains(pressed) && playerPosition.y() < playerPosition.blockY() + Position.PIXEL)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
26
src/main/java/eu/mhsl/minenet/minigames/util/Monitoring.java
Normal file
26
src/main/java/eu/mhsl/minenet/minigames/util/Monitoring.java
Normal file
@ -0,0 +1,26 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.event.server.ServerTickMonitorEvent;
|
||||
import net.minestom.server.monitoring.TickMonitor;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class Monitoring {
|
||||
private static final Runtime runtime = Runtime.getRuntime();
|
||||
private static final AtomicReference<TickMonitor> lastTick = new AtomicReference<>();
|
||||
|
||||
static {
|
||||
MinecraftServer.getGlobalEventHandler().addListener(ServerTickMonitorEvent .class, event -> lastTick.set(event.getTickMonitor()));
|
||||
}
|
||||
|
||||
public static long getRamUsage() {
|
||||
return (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
|
||||
}
|
||||
|
||||
public static TickMonitor getTickMonitor() {
|
||||
return lastTick.get() != null ? lastTick.get() : new TickMonitor(0, 0);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import eu.mhsl.minenet.minigames.instance.Spawnable;
|
||||
import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.entity.Entity;
|
||||
import net.minestom.server.entity.Player;
|
||||
import net.minestom.server.instance.Instance;
|
||||
import net.minestom.server.instance.InstanceContainer;
|
||||
import net.minestom.server.timer.TaskSchedule;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class MoveInstance {
|
||||
public static void move(Set<Player> playerList, Spawnable destination) {
|
||||
playerList.forEach(player -> move(player, destination));
|
||||
}
|
||||
public static void move(Entity p, Spawnable destination) {
|
||||
p.setInstance((Instance) destination, destination.getSpawn());
|
||||
}
|
||||
|
||||
public static void forceCloseInstance(InstanceContainer instance) {
|
||||
instance.scheduler().scheduleTask(() -> {
|
||||
instance.getPlayers().forEach(player -> player.kick("you exceeded the switch timeout while an instance got closed"));
|
||||
MinecraftServer.getInstanceManager().unregisterInstance(instance);
|
||||
}, TaskSchedule.seconds(10), TaskSchedule.stop());
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
public class Position {
|
||||
public static final double PIXEL = 0.0625;
|
||||
}
|
11
src/main/java/eu/mhsl/minenet/minigames/util/RangeMap.java
Normal file
11
src/main/java/eu/mhsl/minenet/minigames/util/RangeMap.java
Normal file
@ -0,0 +1,11 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
public class RangeMap {
|
||||
public static double map(double oldValue, double oldMin, double oldMax, double newMin, double newMax) {
|
||||
double out = (((oldValue - oldMin) * (newMax - newMin)) / (oldMax - oldMin)) + newMin;
|
||||
if(out > newMax) out = newMax;
|
||||
if(out < newMin) out = newMin;
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Class from the Minestom Arena example
|
||||
*/
|
||||
public final class ResourceUtils {
|
||||
public static void extractResource(String source) throws URISyntaxException, IOException {
|
||||
final URI uri = Objects.requireNonNull(ResourceUtils.class.getResource("/" + source)).toURI();
|
||||
FileSystem fileSystem = null;
|
||||
|
||||
// Only create a new filesystem if it's a jar file
|
||||
// (People can run this from their IDE too)
|
||||
if (uri.toString().startsWith("jar:"))
|
||||
fileSystem = FileSystems.newFileSystem(uri, Map.of("create", "true"));
|
||||
|
||||
try {
|
||||
final Path jarPath = Paths.get(uri);
|
||||
final Path target = Path.of("resources/" + source);
|
||||
if (Files.exists(target)) {
|
||||
try (Stream<Path> pathStream = Files.walk(target)) {
|
||||
pathStream.sorted(Comparator.reverseOrder())
|
||||
.forEach(path -> {
|
||||
try {
|
||||
Files.delete(path);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Files.walkFileTree(jarPath, new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(final Path dir, final BasicFileAttributes attrs) throws IOException {
|
||||
Path currentTarget = target.resolve(jarPath.relativize(dir).toString());
|
||||
Files.createDirectories(currentTarget);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs) throws IOException {
|
||||
final Path to = target.resolve(jarPath.relativize(file).toString());
|
||||
Files.copy(file, to, StandardCopyOption.REPLACE_EXISTING);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
} finally {
|
||||
if (fileSystem != null)
|
||||
fileSystem.close();
|
||||
}
|
||||
}
|
||||
}
|
5
src/main/java/eu/mhsl/minenet/minigames/util/Static.java
Normal file
5
src/main/java/eu/mhsl/minenet/minigames/util/Static.java
Normal file
@ -0,0 +1,5 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
public abstract class Static {
|
||||
public abstract void load(); //TODO REMOVE
|
||||
}
|
134
src/main/java/eu/mhsl/minenet/minigames/util/TextUtil.java
Normal file
134
src/main/java/eu/mhsl/minenet/minigames/util/TextUtil.java
Normal file
@ -0,0 +1,134 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TextUtil {
|
||||
public static Component autoWrap(String input, NamedTextColor color) {
|
||||
System.out.println(wrap(input, 30, "\n", true, "-", " ")); //TODO not working
|
||||
|
||||
return Component.text(wrap(input, 30, "\n", true, "-", " "), color);
|
||||
}
|
||||
|
||||
public static Component autoWrap(String input) {
|
||||
return autoWrap(input, NamedTextColor.WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a source String into a series of lines having a maximum specified length. The source is
|
||||
* wrapped at: spaces, horizontal tabs, system newLine characters, or a specified newLine character
|
||||
* sequence. Existing newLine character sequences in the source string, whether they be the system
|
||||
* newLine or the specified newLine, are honored. Existing whitespace (spaces and horizontal tabs)
|
||||
* is preserved.
|
||||
* <p>
|
||||
* When <tt>wrapLongWords</tt> is true, words having a length greater than the specified
|
||||
* <tt>lineLength</tt> will be broken, the specified <tt>longWordBreak</tt> terminator appended,
|
||||
* and a new line initiated with the text of the specified <tt>longWordLinePrefix</tt> string. The
|
||||
* position of the break will be unceremoniously chosen such that <tt>ineLength</tt> is honored.
|
||||
* One use of <tt>longWordLinePrefix</tt> is to effect "hanging indents" by specifying a series of
|
||||
* spaces for this parameter. This parameter can contain the lineFeed character(s). Although
|
||||
* <tt>longWordLinePrefix</tt> can contain the horizontal tab character, the results are not
|
||||
* guaranteed because no attempt is made to determine the quantity of character positions occupied by a
|
||||
* horizontal tab.</p>
|
||||
* <p>
|
||||
* Example usage:
|
||||
* <pre>
|
||||
* wrap( " A very long word is Abracadabra in my book", 11, "\n", true, "-", " ");</pre>
|
||||
* returns (note the effect of the single-character lineFeed):
|
||||
* <pre>
|
||||
* A very
|
||||
* long word
|
||||
* is Abraca-
|
||||
* dabra in
|
||||
* my book</pre>
|
||||
* Whereas, the following:
|
||||
* <pre>
|
||||
* wrap( " A very long word is Abracadabra in my book", 11, null, true, null, " ");</pre>
|
||||
* returns (due to the 2-character system linefeed):
|
||||
* <pre>
|
||||
* A very
|
||||
* long
|
||||
* word is A
|
||||
* bracada
|
||||
* bra in
|
||||
* my book</pre></p>
|
||||
*
|
||||
* @param src the String to be word wrapped, may be null
|
||||
* @param lineLength the maximum line length, including the length of <tt>newLineStr</tt> and, when
|
||||
* applicable, <tt>longWordLinePrefix</tt>. If the value is insufficient to accommodate
|
||||
* these two parameters + 1 character, it will be increased accordingly.
|
||||
* @param newLineStr the string to insert for a new line, or <code>null</code> to use the value
|
||||
* reported as the system line separator by the JVM
|
||||
* @param wrapLongWords when <tt>false</tt>, words longer than <tt>wrapLength</t> will not be broken
|
||||
* @param longWordBreak string with which to precede <tt>newLineStr</tt> on each line of a broken word,
|
||||
* excepting the last line, or <tt>null</tt> if this feature is not to be used
|
||||
* @param longWordLinePrefix string with which to prefix each line of a broken word, subsequent
|
||||
* to the first line, or <tt>null</tt> if no prefix is to be used
|
||||
* @return a line with newlines inserted, or <code>null</code> if <tt>src</tt> is null
|
||||
*/
|
||||
private static String wrap(String src, int lineLength, String newLineStr, boolean wrapLongWords, String longWordBreak, String longWordLinePrefix) {
|
||||
// Trivial case
|
||||
if ( src == null ) return null;
|
||||
|
||||
if ( newLineStr == null )
|
||||
newLineStr = System.getProperty( "line.separator" );
|
||||
|
||||
if ( longWordBreak == null )
|
||||
longWordBreak = "";
|
||||
|
||||
if ( longWordLinePrefix == null )
|
||||
longWordLinePrefix = "";
|
||||
|
||||
// Adjust maximum line length to accommodate the newLine string
|
||||
lineLength -= newLineStr.length();
|
||||
if ( lineLength < 1 )
|
||||
lineLength = 1;
|
||||
|
||||
// Guard for long word break or prefix that would create an infinite loop
|
||||
if ( wrapLongWords && lineLength - longWordBreak.length() - longWordLinePrefix.length() < 1 )
|
||||
lineLength += longWordBreak.length() + longWordLinePrefix.length();
|
||||
|
||||
int
|
||||
remaining = lineLength,
|
||||
breakLength = longWordBreak.length();
|
||||
|
||||
Matcher m = Pattern.compile( ".+?[ \\t]|.+?mis" + newLineStr + "singValue|.+?$" ).matcher( src );
|
||||
|
||||
StringBuilder cache = new StringBuilder();
|
||||
|
||||
while ( m.find() ) {
|
||||
String word = m.group();
|
||||
|
||||
// Breakup long word
|
||||
while ( wrapLongWords && word.length() > lineLength ) {
|
||||
cache
|
||||
.append(word, 0, remaining - breakLength)
|
||||
.append( longWordBreak )
|
||||
.append( newLineStr );
|
||||
word = longWordLinePrefix + word.substring( remaining - breakLength );
|
||||
remaining = lineLength;
|
||||
} // if
|
||||
|
||||
// Linefeed if word exceeds remaining space
|
||||
if ( word.length() > remaining ) {
|
||||
cache
|
||||
.append( newLineStr )
|
||||
.append( word );
|
||||
remaining = lineLength;
|
||||
} // if
|
||||
|
||||
// Word fits in remaining space
|
||||
else
|
||||
cache.append( word );
|
||||
|
||||
remaining -= word.length();
|
||||
} // while
|
||||
|
||||
return cache.toString();
|
||||
} // wrap()
|
||||
|
||||
}
|
||||
|
18
src/main/java/eu/mhsl/minenet/minigames/util/UuidUtil.java
Normal file
18
src/main/java/eu/mhsl/minenet/minigames/util/UuidUtil.java
Normal file
@ -0,0 +1,18 @@
|
||||
package eu.mhsl.minenet.minigames.util;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class UuidUtil {
|
||||
public static UUID unTrimm(String trimmedUuid) {
|
||||
StringBuilder builder = new StringBuilder(trimmedUuid.trim());
|
||||
try {
|
||||
builder.insert(20, "-");
|
||||
builder.insert(16, "-");
|
||||
builder.insert(12, "-");
|
||||
builder.insert(8, "-");
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return UUID.fromString(builder.toString());
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
package eu.mhsl.minenet.minigames.world.generator;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public enum BlockPallet {
|
||||
GROUND(new Block[] {Block.GRAVEL, Block.STONE, Block.DIRT, Block.GRASS_BLOCK, Block.COARSE_DIRT, Block.ROOTED_DIRT}),
|
||||
WOOD(new Block[] {Block.ACACIA_WOOD, Block.BIRCH_WOOD, Block.JUNGLE_WOOD, Block.OAK_WOOD, Block.DARK_OAK_WOOD, Block.SPRUCE_WOOD}),
|
||||
STONE(new Block[] {Block.CHISELED_STONE_BRICKS, Block.STONE_BRICKS, Block.POLISHED_ANDESITE, Block.POLISHED_BLACKSTONE, Block.POLISHED_DIORITE}),
|
||||
|
||||
PRESSURE_PLATES(new Block[] {Block.ACACIA_PRESSURE_PLATE, Block.BIRCH_PRESSURE_PLATE, Block.CRIMSON_PRESSURE_PLATE, Block.JUNGLE_PRESSURE_PLATE, Block.OAK_PRESSURE_PLATE, Block.DARK_OAK_PRESSURE_PLATE, Block.HEAVY_WEIGHTED_PRESSURE_PLATE, Block.HEAVY_WEIGHTED_PRESSURE_PLATE, Block.POLISHED_BLACKSTONE_PRESSURE_PLATE, Block.SPRUCE_PRESSURE_PLATE, Block.STONE_PRESSURE_PLATE, Block.WARPED_PRESSURE_PLATE});
|
||||
|
||||
final List<Block> list;
|
||||
final Random rnd = new Random();
|
||||
|
||||
BlockPallet(Block[] blocks) {
|
||||
this.list = new ArrayList<>(List.of(blocks));
|
||||
}
|
||||
|
||||
public Block rnd() {
|
||||
return list.get(rnd.nextInt(list.size()));
|
||||
}
|
||||
|
||||
public boolean contains(Block b) {
|
||||
return list.contains(b);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package eu.mhsl.minenet.minigames.world.generator;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.generator.GenerationUnit;
|
||||
import net.minestom.server.instance.generator.Generator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlaneGenerator implements Generator {
|
||||
@Override
|
||||
public void generate(@NotNull GenerationUnit unit) {
|
||||
unit.modifier()
|
||||
.fillHeight(0, 5, Block.STONE);
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package eu.mhsl.minenet.minigames.world.generator.structures;
|
||||
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Structure {
|
||||
protected final Random rnd = new Random();
|
||||
|
||||
public abstract void generateGame(Block.Setter setter);
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package eu.mhsl.minenet.minigames.world.generator.structures.generatable;
|
||||
|
||||
import eu.mhsl.minenet.minigames.world.generator.BlockPallet;
|
||||
import eu.mhsl.minenet.minigames.world.generator.structures.Structure;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
|
||||
public class PeakRock extends Structure {
|
||||
private final Point position;
|
||||
public PeakRock(Point position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateGame(Block.Setter setter) {
|
||||
for (int stoneX = -4; stoneX < 4; stoneX++) {
|
||||
for (int stoneZ = -4; stoneZ < 4; stoneZ++) {
|
||||
|
||||
double distanceToCenter = position.add(stoneX, 0, stoneZ).distance(position);
|
||||
if(distanceToCenter > 3) continue;
|
||||
|
||||
for (int stoneY = 0; stoneY < 10-(int) distanceToCenter * rnd.nextDouble(2, 5); stoneY++) {
|
||||
Point blockPos = position.add(stoneX, stoneY, stoneZ);
|
||||
setter.setBlock(blockPos, BlockPallet.STONE.rnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
package eu.mhsl.minenet.minigames.world.generator.terrain;
|
||||
|
||||
import de.articdive.jnoise.JNoise;
|
||||
import eu.mhsl.minenet.minigames.util.RangeMap;
|
||||
import eu.mhsl.minenet.minigames.world.generator.BlockPallet;
|
||||
import eu.mhsl.minenet.minigames.world.generator.structures.generatable.PeakRock;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.generator.GenerationUnit;
|
||||
import net.minestom.server.instance.generator.Generator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class CircularTerrainGenerator implements Generator {
|
||||
protected final Random rnd = new Random();
|
||||
private final int size;
|
||||
|
||||
protected final Pos mapCenter = new Pos(0, 50, 0);
|
||||
|
||||
private boolean generatePlate;
|
||||
|
||||
public CircularTerrainGenerator(int size, boolean generatePlate) {
|
||||
this.size = size;
|
||||
this.generatePlate = generatePlate;
|
||||
}
|
||||
private final JNoise base = JNoise.newBuilder()
|
||||
.fastSimplex()
|
||||
.setSeed(rnd.nextLong())
|
||||
.setFrequency(0.01)
|
||||
.build();
|
||||
|
||||
private final JNoise batches = JNoise.newBuilder()
|
||||
.fastSimplex()
|
||||
.setSeed(rnd.nextLong())
|
||||
.setFrequency(0.05)
|
||||
.build();
|
||||
|
||||
private final JNoise peaks = JNoise.newBuilder()
|
||||
.fastSimplex()
|
||||
.setSeed(rnd.nextLong())
|
||||
.setFrequency(0.1)
|
||||
.build();
|
||||
|
||||
|
||||
@Override
|
||||
public void generate(@NotNull GenerationUnit unit) {
|
||||
Point start = unit.absoluteStart().withY(0);
|
||||
|
||||
if(unit.absoluteStart().distance(new Pos(0, 0, 0)) > 500 + this.size) return;
|
||||
|
||||
for (int x = 0; x < unit.size().x(); x++) {
|
||||
for (int z = 0; z < unit.size().z(); z++) {
|
||||
Point bottom = start.add(x, 0, z);
|
||||
|
||||
double distance = bottom.distance(new Pos(0, 0, 0));
|
||||
|
||||
if(distance <= this.size && generatePlate) {
|
||||
unit.modifier().fill(bottom, bottom.add(1, 50, 1), BlockPallet.GROUND.rnd());
|
||||
continue;
|
||||
}
|
||||
|
||||
unit.modifier().setBlock(bottom, Block.GRASS_BLOCK);
|
||||
|
||||
synchronized (base) {
|
||||
double baseNoise = base.getNoise(bottom.x(), bottom.z());
|
||||
double currentHeight = minTwo(RangeMap.map(distance, 0, 400, -(this.size / 5), 200)) + baseNoise * 8;
|
||||
|
||||
synchronized (batches) {
|
||||
double elementNoise = batches.getNoise(bottom.x(), bottom.z());
|
||||
|
||||
unit.modifier().fill(
|
||||
bottom,
|
||||
bottom.add(1, 1, 1)
|
||||
.withY(currentHeight),
|
||||
elementNoise < 0.9 ? elementNoise > 0 ? Block.GRASS_BLOCK : Block.SOUL_SAND : Block.STONE
|
||||
);
|
||||
}
|
||||
|
||||
synchronized (peaks) {
|
||||
double peakNoise = peaks.getNoise(bottom.x(), bottom.z());
|
||||
|
||||
if(peakNoise > 0.97 && bottom.distance(new Pos(0, 0, 0)) > (this.size + 20)) {
|
||||
|
||||
Point center = bottom.add(1, currentHeight-3, 1);
|
||||
unit.fork(setter -> new PeakRock(center).generateGame(setter));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static double minTwo(double input) {
|
||||
if(input < 2) return 2;
|
||||
return input;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package eu.mhsl.minenet.minigames.world.generator.terrain;
|
||||
|
||||
import de.articdive.jnoise.JNoise;
|
||||
import eu.mhsl.minenet.minigames.util.RangeMap;
|
||||
import eu.mhsl.minenet.minigames.world.generator.BlockPallet;
|
||||
import eu.mhsl.minenet.minigames.world.generator.structures.generatable.PeakRock;
|
||||
import net.minestom.server.coordinate.Point;
|
||||
import net.minestom.server.coordinate.Pos;
|
||||
import net.minestom.server.instance.block.Block;
|
||||
import net.minestom.server.instance.generator.GenerationUnit;
|
||||
import net.minestom.server.instance.generator.Generator;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class SquareTerrainGenerator implements Generator {
|
||||
protected final Random rnd = new Random();
|
||||
|
||||
private int width;
|
||||
private int length;
|
||||
|
||||
private boolean generatePlate;
|
||||
|
||||
protected final Pos mapStart = new Pos(0, 50, 0);
|
||||
|
||||
public SquareTerrainGenerator(int width, int length, boolean generatePlate) {
|
||||
this.width = width;
|
||||
this.length = length;
|
||||
this.generatePlate = generatePlate;
|
||||
}
|
||||
private final JNoise base = JNoise.newBuilder()
|
||||
.fastSimplex()
|
||||
.setSeed(rnd.nextLong())
|
||||
.setFrequency(0.01)
|
||||
.build();
|
||||
|
||||
private final JNoise batches = JNoise.newBuilder()
|
||||
.fastSimplex()
|
||||
.setSeed(rnd.nextLong())
|
||||
.setFrequency(0.05)
|
||||
.build();
|
||||
|
||||
private final JNoise peaks = JNoise.newBuilder()
|
||||
.fastSimplex()
|
||||
.setSeed(rnd.nextLong())
|
||||
.setFrequency(0.1)
|
||||
.build();
|
||||
|
||||
|
||||
@Override
|
||||
public void generate(@NotNull GenerationUnit unit) {
|
||||
Point start = unit.absoluteStart().withY(0);
|
||||
|
||||
// don't generate more than 500 blocks outwards
|
||||
Point chunkStart = unit.absoluteStart();
|
||||
if(chunkStart.z() > length + 500 || chunkStart.z() < -500) return;
|
||||
if(chunkStart.x() < -500 || chunkStart.x() > width + 500) return;
|
||||
|
||||
for (int x = 0; x < unit.size().x(); x++) {
|
||||
for (int z = 0; z < unit.size().z(); z++) {
|
||||
Point bottom = start.add(x, 0, z);
|
||||
|
||||
double distance = bottom.distance(new Pos(0, 0, 0));
|
||||
|
||||
if(generatePlate) {
|
||||
if(bottom.x() <= width && bottom.x() >= 0 && bottom.z() <= length && bottom.z() >= 0) {
|
||||
unit.modifier().fill(bottom, bottom.add(1, 50, 1), BlockPallet.GROUND.rnd());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
unit.modifier().setBlock(bottom, Block.GRASS_BLOCK);
|
||||
|
||||
synchronized (base) {
|
||||
double baseNoise = base.getNoise(bottom.x(), bottom.z());
|
||||
double currentHeight = minTwo(RangeMap.map(distance, 0, 400, -(this.width / 5), 200)) + baseNoise * 8;
|
||||
|
||||
synchronized (batches) {
|
||||
double elementNoise = batches.getNoise(bottom.x(), bottom.z());
|
||||
|
||||
unit.modifier().fill(
|
||||
bottom,
|
||||
bottom.add(1, 1, 1)
|
||||
.withY(currentHeight),
|
||||
elementNoise < 0.9 ? elementNoise > 0 ? Block.GRASS_BLOCK : Block.SOUL_SAND : Block.STONE
|
||||
);
|
||||
}
|
||||
|
||||
synchronized (peaks) {
|
||||
double peakNoise = peaks.getNoise(bottom.x(), bottom.z());
|
||||
|
||||
if(peakNoise > 0.97 && bottom.distance(new Pos(0, 0, 0)) > (this.width + 20)) {
|
||||
|
||||
Point center = bottom.add(1, currentHeight-3, 1);
|
||||
unit.fork(setter -> new PeakRock(center).generateGame(setter));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static double minTwo(double input) {
|
||||
if(input < 2) return 2;
|
||||
return input;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user