Initial commit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user