32 Commits

Author SHA1 Message Date
7186b4dbea Merge pull request 'added pillars and block battle' (#10) from develop-pillars into develop
Reviewed-on: #10
Reviewed-by: Lars Neuhaus <larslukasneuhaus@gmx.de>
2026-02-02 19:09:44 +00:00
24d79d7a11 pull requestest changes 2026-02-02 20:04:55 +01:00
70fd5bafdb updated Block Battle description 2026-02-02 18:19:45 +00:00
11ddd01470 pull requestest changes 2026-02-02 19:15:46 +01:00
7d5fb025bd added setting, refactored code 2026-02-01 18:24:36 +01:00
05240660f2 added scores and translations 2026-02-01 17:37:37 +01:00
d0031b4ea5 added BlockBattle 2026-02-01 14:14:34 +01:00
360266339d added pillars game 2026-01-23 20:26:04 +01:00
325fba2a53 Merge pull request 'added second option to game selection menu, finished stickfight(added timer to stick fight)' (#9) from develop-jannis into develop
Reviewed-on: #9
Reviewed-by: Elias Müller <elias@elias-mueller.com>
2026-01-11 19:07:05 +00:00
e760cdb2c6 removed 0 add option seconds 2026-01-10 21:41:45 +01:00
c111c027ff added second option to game selection menu, finished stickfight 2026-01-10 17:41:19 +01:00
73ab137ae4 Merge remote-tracking branch 'origin/develop' into develop 2026-01-10 16:29:26 +01:00
9a9e646288 fixed Tetris camera shake 2026-01-10 16:29:12 +01:00
728dc92fc8 Merge pull request 'elytra race fix boost ring 1' (#8) from develop-jannis into develop
Reviewed-on: #8
2026-01-10 13:48:50 +00:00
2f8ff36e5e Merge branch 'develop' into develop-jannis 2026-01-10 13:48:39 +00:00
5cb71c5c32 changed respawn height on first respawn in elytrarace
added level indicator for stickfight
2026-01-10 14:47:57 +01:00
5ab42fde4b Merge pull request 'added stick to inventory for stick fight' (#7) from develop-stickfight into develop
Reviewed-on: #7
Reviewed-by: Elias Müller <elias@elias-mueller.com>
2026-01-10 13:10:26 +00:00
d5c2f06409 elytra race fix boost ring 1 2026-01-10 14:02:21 +01:00
1ff8cca7e9 added stick to inventory for stick fight 2026-01-10 00:41:24 +01:00
47c40c4941 fixed winning condition in SpaceSnake 2026-01-07 15:06:12 +01:00
d4a7fcada7 improved chat formatting by adding username colors and better separators 2026-01-02 02:26:56 +01:00
a0124f1bcb Merge remote-tracking branch 'origin/develop' into develop 2025-12-28 18:53:52 +01:00
c79fbf3136 fixed tournament random order at the end 2025-12-28 18:53:14 +01:00
660eb645e4 Merge remote-tracking branch 'origin/develop' into develop 2025-12-27 11:37:36 +01:00
3c50aca1e8 updated reward API endpoint in PublishRewardCommand 2025-12-27 11:37:33 +01:00
865cdfa605 added gamemode change to survival on leaving tetris 2025-12-25 00:52:56 +01:00
fe88e3f921 added slowness to tetris 2025-12-24 13:20:05 +01:00
5e94479949 updated locales file with enhanced Stickfight description and added BoatRace entry 2025-12-21 10:42:23 +01:00
b15c9c97b0 finished boat race 2025-12-18 21:36:22 +01:00
334e130cf6 fixed boat stuttering 2025-12-18 20:02:26 +01:00
31385fbd7f cleanup 2025-12-13 15:15:23 +01:00
b1b1e24104 added BoatRace game with factory and updated GameList 2025-12-03 23:08:55 +01:00
41 changed files with 625 additions and 55 deletions

View File

@@ -60,9 +60,9 @@ dependencies {
implementation 'io.github.TogAr2:MinestomPvP:PR62-SNAPSHOT'
// Hephaestus engine
implementation("team.unnamed:hephaestus-api:0.2.1-SNAPSHOT")
implementation("team.unnamed:hephaestus-reader-blockbench:0.2.1-SNAPSHOT")
implementation("team.unnamed:hephaestus-runtime-minestom:0.2.1-SNAPSHOT")
// implementation("team.unnamed:hephaestus-api:0.2.1-SNAPSHOT")
// implementation("team.unnamed:hephaestus-reader-blockbench:0.2.1-SNAPSHOT")
// implementation("team.unnamed:hephaestus-runtime-minestom:0.2.1-SNAPSHOT")
}
tasks {

View File

@@ -25,7 +25,7 @@ public class PublishRewardCommand extends PrivilegedCommand {
String rewardRequestJson = new Gson().toJson(room.getTournament().getRewards());
HttpRequest giveRewardsRequest = HttpRequest.newBuilder()
.uri(new URI("http://10.20.7.1:8080/api/event/reward"))
.uri(new URI("http://10.20.9.3:8080/api/event/reward"))
.POST(HttpRequest.BodyPublishers.ofString(rewardRequestJson))
.build();

View File

@@ -2,6 +2,8 @@ package eu.mhsl.minenet.minigames.handler.global;
import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.PlayerChatEvent;
import org.jetbrains.annotations.NotNull;
@@ -14,7 +16,14 @@ public class ChatFormatHandler implements EventListener<PlayerChatEvent> {
@Override
public @NotNull Result run(@NotNull PlayerChatEvent event) {
event.setFormattedMessage(new ChatMessage(Icon.CHAT).appendStatic(event.getRawMessage()).build(event.getPlayer()));
NamedTextColor color = event.getPlayer().getPermissionLevel() > 0 ? NamedTextColor.AQUA : NamedTextColor.GRAY;
event.setFormattedMessage(
new ChatMessage(Icon.CHAT)
.appendStatic(Component.text(event.getPlayer().getUsername(), color))
.appendStatic(Component.text(" > ", NamedTextColor.DARK_GRAY))
.appendStatic(event.getRawMessage())
.build(event.getPlayer())
);
return Result.SUCCESS;
}
}

View File

@@ -5,7 +5,9 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.acidRain.AcidRain
import eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun.AnvilRunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms.BackroomsFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bedwars.BedwarsFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBattle.BlockBattleFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace.BlockBreakRaceFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.boatRace.BoatRaceFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube.DeathcubeFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory;
@@ -13,6 +15,7 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.fastbridge.Fastbr
import eu.mhsl.minenet.minigames.instance.game.stateless.types.highGround.HighGroundFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.jumpDive.JumpDiveFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.minerun.MinerunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.pillars.PillarsFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.spaceSnake.SpaceSnakeFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.spleef.SpleefFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.stickfight.StickFightFactory;
@@ -44,7 +47,10 @@ public enum GameList {
HIGHGROUND(new HighGroundFactory(), GameType.PVP),
FASTBRIDGE(new FastbridgeFactory(), GameType.OTHER),
BLOCKBREAKRACE(new BlockBreakRaceFactory(), GameType.OTHER),
SPACESNAKE(new SpaceSnakeFactory(), GameType.PVP);
SPACESNAKE(new SpaceSnakeFactory(), GameType.PVP),
BOATRACE(new BoatRaceFactory(), GameType.OTHER),
PILLARS(new PillarsFactory(), GameType.PROTOTYPE),
BLOCKBATTLE(new BlockBattleFactory(), GameType.PROTOTYPE);
private final GameFactory factory;
private final GameType type;

View File

@@ -0,0 +1,207 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBattle;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import io.github.togar2.pvp.events.FinalAttackEvent;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
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.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
public class BlockBattle extends StatelessGame {
private final Team teamBlue = new Team(new Pos(0,101,20).add(0.5).withView(180, 0), Team.Color.BLUE);
private final Team teamRed = new Team(new Pos(0, 101, -20).add(0.5), Team.Color.RED);
private final int itemCount;
private final Map<Player, Team> teams = new WeakHashMap<>();
public BlockBattle(int itemCount) {
super(Dimension.THE_END.key, "Block Battle", new FirstWinsScore());
this.itemCount = itemCount;
this.eventNode().addChild(
CombatFeatures.empty()
.add(CombatFeatures.VANILLA_ATTACK)
.add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build().createNode()
);
this.eventNode().addListener(FinalAttackEvent.class, finalAttackEvent -> {
if(this.isBeforeBeginning) finalAttackEvent.setCancelled(true);
finalAttackEvent.setBaseDamage(0);
((Player) finalAttackEvent.getTarget()).setHealth(20);
});
}
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
this.generatePlatform(new Pos(0, 100, 0), Block.GOLD_BLOCK, Block.YELLOW_CONCRETE_POWDER);
this.generatePlatform(new Pos(0, 101, 0), Block.AIR, Block.SANDSTONE_SLAB);
this.generatePlatform(new Pos(0, 100, 20), Block.BLUE_CONCRETE, Block.BLUE_CONCRETE_POWDER);
this.generatePlatform(new Pos(0, 100, -20), Block.RED_CONCRETE, Block.RED_CONCRETE_POWDER);
this.generatePlatform(new Pos(-5, 101, -14), Block.RED_STAINED_GLASS, Block.AIR);
this.generatePlatform(new Pos(5, 101, 14), Block.BLUE_STAINED_GLASS, Block.AIR);
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
Pos[] positionsRedGlass = {
new Pos(2, 102, -9),
new Pos(-1, 103, -9),
new Pos(-2, 104, -6),
new Pos(-5, 103, -7),
new Pos(-7, 102, -10),
new Pos(3, 102, -12),
new Pos(5, 101, -15)
};
Pos[] positionsBlueGlass = {
new Pos(-5, 101, 15),
new Pos(-3, 102, 12),
new Pos(-2, 102, 9),
new Pos(1, 103, 9),
new Pos(2, 104, 6),
new Pos(5, 103, 7),
new Pos(7, 102, 10)
};
for(Pos pos : positionsRedGlass)
batch.setBlock(pos, Block.RED_STAINED_GLASS);
for(Pos pos : positionsBlueGlass)
batch.setBlock(pos, Block.BLUE_STAINED_GLASS);
BatchUtil.loadAndApplyBatch(batch, this, () -> {});
}
@Override
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) {
Pos posGoldBlock = new Pos(playerBlockPlaceEvent.getBlockPosition()).sub(0, 1, 0);
Block goldBlock = playerBlockPlaceEvent.getInstance().getBlock(posGoldBlock);
playerBlockPlaceEvent.setCancelled(goldBlock != Block.GOLD_BLOCK);
playerBlockPlaceEvent.getInstance().scheduler().scheduleNextTick(() -> {
Pos middle = new Pos(0, 101, 0);
boolean validBlue = true;
boolean validRed = true;
for(int x = middle.blockX()-1; x < middle.blockX()+2; x++) {
for(int z = middle.blockZ()-1; z < middle.blockZ()+2; z++) {
if(playerBlockPlaceEvent.getInstance().getBlock(x, 101, z) != Block.BLUE_WOOL) {
validBlue = false;
break;
}
}
if(!validBlue)
break;
}
for(int x = middle.blockX()-1; x < middle.blockX()+2; x++) {
for(int z = middle.blockZ()-1; z < middle.blockZ()+2; z++) {
if(playerBlockPlaceEvent.getInstance().getBlock(x, 101, z) != Block.RED_WOOL) {
validRed = false;
break;
}
}
if(!validRed)
break;
}
if(!validBlue && !validRed) return;
var winningTeam = validBlue ? Team.Color.BLUE : Team.Color.RED;
var winningPlayers = this.teams.entrySet().stream()
.filter(entry -> entry.getValue().color().equals(winningTeam))
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
this.getScore().insertMultiple(winningPlayers);
super.stop();
});
}
@Override
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent playerBlockBreakEvent) {
boolean isAllowed = Arrays.stream(Team.Color.values())
.map(Team.Color::getMaterial)
.map(Material::block)
.toList()
.contains(playerBlockBreakEvent.getBlock());
if(!isAllowed) playerBlockBreakEvent.setCancelled(true);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(playerMoveEvent.getNewPosition().y() < 95) {
var player = playerMoveEvent.getPlayer();
player.teleport(
this.isBeforeBeginning
? this.getSpawn()
: this.teams.get(player).spawnPosition()
);
this.giveItems(player);
}
}
@Override
protected void onStart() {
this.setTeams();
this.getPlayers().forEach(player -> player.teleport(this.teams.get(player).spawnPosition()).thenRun(() -> {
this.giveItems(player);
player.setGameMode(GameMode.SURVIVAL);
}));
}
private void generatePlatform(Pos center, Block inner, Block outer) {
for(int x = center.blockX()-2; x < center.blockX()+3; x++) {
for(int z = center.blockZ()-2; z < center.blockZ()+3; z++) {
this.setBlock(x, center.blockY(), z, outer);
}
}
for(int x = center.blockX()-1; x < center.blockX()+2; x++) {
for(int z = center.blockZ()-1; z < center.blockZ()+2; z++) {
this.setBlock(x, center.blockY(), z, inner);
}
}
}
private void setTeams() {
List<Player> players = new ArrayList<>(this.getPlayers());
Collections.shuffle(players);
int halfPlayers = players.size()/2;
players.subList(0, halfPlayers).forEach(player -> this.teams.put(player, this.teamBlue));
players.subList(halfPlayers, players.size()).forEach(player -> this.teams.put(player, this.teamRed));
}
@Override
public Pos getSpawn() {
return new Pos(0, 101, 0).add(0.5);
}
private void giveItems(Player player) {
player.getInventory().clear();
ItemStack item = ItemStack.of(
this.teams.get(player).color().getMaterial(),
this.itemCount
);
player.getInventory().addItemStack(item);
}
}

View File

@@ -0,0 +1,40 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBattle;
import eu.mhsl.minenet.minigames.instance.game.Game;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.ConfigManager;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.NumericOption;
import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import net.minestom.server.item.Material;
import java.util.Map;
public class BlockBattleFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_BlockBattle#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_BlockBattle#description");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("itemCount", Material.WHITE_WOOL, TranslatedComponent.byId("game_BlockBattle#itemCount"), 1, 2, 3));
}
@Override
public Material symbol() {
return Material.GREEN_CONCRETE;
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new BlockBattle(configuration.get("itemCount").getAsInt()).setParent(parent);
}
}

View File

@@ -0,0 +1,21 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBattle;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.item.Material;
public record Team(Pos spawnPosition, Color color) {
public enum Color {
RED(Material.RED_WOOL),
BLUE(Material.BLUE_WOOL);
private final Material block;
Color(Material block) {
this.block = block;
}
public Material getMaterial() {
return this.block;
}
}
}

View File

@@ -0,0 +1,75 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.boatRace;
import eu.mhsl.minenet.minigames.Resource;
import eu.mhsl.minenet.minigames.handler.global.PlayerLoginHandler;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import eu.mhsl.minenet.minigames.util.CommonProperties;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.anvil.AnvilLoader;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
public class BoatRace extends StatelessGame {
public BoatRace() {
super(Dimension.OVERWORLD.key, "boatRace", new FirstWinsScore());
this.setChunkLoader(new AnvilLoader(Resource.GAME_MAP.getPath().resolve("boatRace/woodlandMansion")));
}
@Override
protected boolean onPlayerJoin(Player p) {
Entity boat = new Entity(EntityType.OAK_BOAT);
boat.setInstance(this, this.getSpawn());
boat.setSynchronizationTicks(100000);
PlayerLoginHandler.globalTeam.addMember(boat.getUuid().toString());
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> boat.addPassenger(p));
return super.onPlayerJoin(p);
}
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
for(int z = 9; z <= 32; z++) {
this.setBlock(31, 235, z, Block.CHERRY_FENCE.withProperties(CommonProperties.fenceNorthSouth));
}
}
@Override
protected void onStart() {
for(int z = 9; z <= 32; z++) {
this.setBlock(31, 235, z, Block.AIR);
}
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent event) {
if (this.isBeforeBeginning) return;
if(event.getNewPosition().z() > 469) {
Player player = event.getPlayer();
this.getScore().insertResult(player);
Entity vehicle = player.getVehicle();
if(vehicle != null) {
vehicle.removePassenger(player);
player.teleport(player.getPosition().withY(y -> y + 3));
player.setGameMode(GameMode.SPECTATOR);
vehicle.remove();
}
}
}
@Override
public Pos getSpawn() {
return new Pos(20, 236, 20, -90, 0);
}
}

View File

@@ -0,0 +1,27 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.boatRace;
import eu.mhsl.minenet.minigames.instance.game.Game;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option;
import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import net.minestom.server.item.Material;
import java.util.Map;
public class BoatRaceFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_BoatRace#name");
}
@Override
public Material symbol() {
return Material.OAK_BOAT;
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new BoatRace().setParent(parent);
}
}

View File

@@ -133,7 +133,7 @@ public class ElytraRace extends StatelessGame {
return;
}
this.playerCheckpoints.putIfAbsent(player, new CheckPointData(this.ringSpacing, this.ringSpacing * 2));
this.playerCheckpoints.putIfAbsent(player, new CheckPointData(0, this.ringSpacing));
if(newPos.z() > this.generatedUntil - this.ringSpacing) {
this.generateRing(this.generatedUntil + this.ringSpacing);
@@ -224,7 +224,9 @@ public class ElytraRace extends StatelessGame {
}
private void toCheckpoint(Player p) {
CheckPointData data = this.playerCheckpoints.get(p);
Point checkpointPos = this.getRingPositionAtZ(this.playerCheckpoints.get(p).currentCheckpoint);
if(data.currentCheckpoint == 0) checkpointPos = this.getSpawn().add(0, 3, 0);
p.setVelocity(Vec.ZERO);
p.setFlyingWithElytra(false);
p.teleport(Pos.fromPoint(checkpointPos).add(0.5, 0, 0.5));

View File

@@ -0,0 +1,103 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.pillars;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import eu.mhsl.minenet.minigames.util.Position;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
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.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
class Pillars extends StatelessGame {
private int spawnPosx = 0;
private int spawnPosz = 0;
private final int pillarSpacing = 10;
private final int pillarRowCount = 5;
public Pillars() {
super(Dimension.THE_END.key, "Pillars", new LastWinsScore());
this.getScore().setIgnoreLastPlayers(1);
this.eventNode().addChild(
CombatFeatures.empty()
.add(CombatFeatures.VANILLA_ATTACK)
.add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build().createNode()
);
}
@Override
protected boolean onPlayerJoin(Player p) {
Pos pos = new Pos(this.spawnPosx * this.pillarSpacing, 100, this.spawnPosz * this.pillarSpacing);
this.setBlock(pos.sub(0, 1, 0), Block.BEDROCK);
if(this.spawnPosx >= this.pillarRowCount) {
this.spawnPosx = 0;
this.spawnPosz++;
}
this.spawnPosx++;
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> p.teleport(pos.add(0.5, 0, 0.5)));
return super.onPlayerJoin(p);
}
@Override
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) {}
@Override
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent playerBlockBreakEvent) {}
@Override
protected void onItemDrop(@NotNull ItemDropEvent itemDropEvent) {}
@Override
public Pos getSpawn() {
return new Pos(0, 105, 0);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
var player = playerMoveEvent.getPlayer();
if(this.isBeforeBeginning && Position.hasPositionChanged(player.getPosition(), playerMoveEvent.getNewPosition()))
playerMoveEvent.setCancelled(true);
if(playerMoveEvent.getNewPosition().y() < 80) {
this.getScore().insertResult(player);
player.teleport(this.getSpawn());
player.setGameMode(GameMode.SPECTATOR);
}
}
@Override
protected void onStart() {
this.getPlayers().forEach(player -> player.setGameMode(GameMode.SURVIVAL));
MinecraftServer.getSchedulerManager().submitTask(() -> {
List<Material> materials = Material.values().stream()
.filter(material -> !material.equals(Material.AIR))
.toList();
this.getPlayers().forEach(player -> {
ItemStack item = ItemStack.of(materials.get(ThreadLocalRandom.current().nextInt(Material.values().toArray().length)));
player.getInventory().addItemStack(item);
});
return TaskSchedule.seconds(5);
});
}
}

View File

@@ -0,0 +1,32 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.pillars;
import eu.mhsl.minenet.minigames.instance.game.Game;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option;
import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import net.minestom.server.item.Material;
import java.util.Map;
public class PillarsFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_Pillars#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_Pillars#description");
}
@Override
public Material symbol() {
return Material.BEDROCK;
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new Pillars().setParent(parent);
}
}

View File

@@ -110,7 +110,7 @@ public class SpaceSnake extends StatelessGame {
playerMoveEvent.getPlayer().teleport(this.getSpawn());
playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
long livingPlayers = this.getPlayers().stream()
.filter(p -> this.getScore().hasResult(p))
.filter(p -> !this.getScore().hasResult(p))
.count();
if(livingPlayers == 1) this.setTimeLimit(10);
if(livingPlayers == 0) this.stop();

View File

@@ -28,7 +28,8 @@ public class StickFightFactory implements GameFactory {
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("length", Material.SANDSTONE, TranslatedComponent.byId("optionCommon#length"), 7, 10, 13, 16, 19));
.addOption(new NumericOption("length", Material.SANDSTONE, TranslatedComponent.byId("optionCommon#length"), 7, 10, 13, 16, 19))
.addOption(new NumericOption("seconds", Material.CLOCK, TranslatedComponent.byId("optionCommon#seconds"), 30, 60, 90, 120));
}
@Override
@@ -40,7 +41,7 @@ public class StickFightFactory implements GameFactory {
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) {
return new Stickfight(configuration.get("length").getAsInt()).setParent(parent);
return new Stickfight(configuration.get("length").getAsInt(), configuration.get("seconds").getAsInt()).setParent(parent);
}
@Override

View File

@@ -10,6 +10,8 @@ import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -22,10 +24,12 @@ public class Stickfight extends StatelessGame {
private final WeakHashMap<Player, Pos> spawnPoints = new WeakHashMap<>();
private final Map<Player, Integer> scoreMap = new WeakHashMap<>();
private boolean countdownStarted = false;
private final int seconds;
public Stickfight(int length) {
public Stickfight(int length, int seconds) {
super(Dimension.OVERWORLD.key, "Stickfight", new LowestPointsWinScore());
this.radius = length;
this.seconds = seconds;
this.eventNode().addChild(
CombatFeatures.empty()
@@ -79,10 +83,18 @@ public class Stickfight extends StatelessGame {
this.generateBridge(spawnX, spawnY, spawnZ);
}
ItemStack item = ItemStack.of(Material.STICK).withGlowing(true);
players.forEach(player -> player.getInventory().addItemStack(item));
this.setBlock(0, 50, 0, Block.GOLD_BLOCK);
super.start();
}
@Override
protected void onStart() {
this.setTimeLimit(this.seconds);
}
@Override
protected void onStop() {
this.scoreMap.forEach((player, score) -> this.getScore().insertResult(player, score));
@@ -117,6 +129,7 @@ public class Stickfight extends StatelessGame {
player.teleport(this.spawnPoints.get(player));
this.scoreMap.putIfAbsent(player, 0);
this.scoreMap.put(player, this.scoreMap.get(player) + 1);
player.setLevel(this.scoreMap.get(player));
}
}

View File

@@ -6,16 +6,20 @@ import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetri
import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.Tetromino;
import eu.mhsl.minenet.minigames.score.PointsWinScore;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.metadata.display.BlockDisplayMeta;
import net.minestom.server.event.player.PlayerHandAnimationEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerTickEvent;
import net.minestom.server.event.player.PlayerUseItemEvent;
import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
@@ -71,21 +75,29 @@ class Tetris extends StatelessGame {
@Override
protected void onPlayerLeave(Player p) {
this.tetrisGames.get(p).sidebar.removeViewer(p);
p.clearEffects();
this.letPlayerLoose(p);
p.setGameMode(GameMode.SURVIVAL);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent event) {
private void onPlayerInteract(@NotNull PlayerUseItemEvent event) {
event.setItemUseTime(0);
this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseRight);
}
private void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) {
this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseLeft);
}
private void onPlayerTick(PlayerTickEvent event) {
Player player = event.getPlayer();
Pos currentPosition = event.getNewPosition();
TetrisGame tetrisGame = this.tetrisGames.get(player);
if(tetrisGame == null) {
event.setCancelled(true);
if(tetrisGame == null) return;
if(tetrisGame.lost) {
this.letPlayerLoose(player);
return;
}
if(tetrisGame.lost) return;
if(player.getGameMode() == GameMode.SPECTATOR) return;
if(player.inputs().forward()) tetrisGame.pressedButton(TetrisGame.Button.W);
@@ -93,26 +105,6 @@ class Tetris extends StatelessGame {
if(player.inputs().right()) tetrisGame.pressedButton(TetrisGame.Button.D);
if(player.inputs().left()) tetrisGame.pressedButton(TetrisGame.Button.A);
if(player.inputs().jump()) tetrisGame.pressedButton(TetrisGame.Button.space);
event.setNewPosition(tetrisGame.getPlayerSpawnPosition().withView(currentPosition));
player.setSprinting(false);
}
protected void onPlayerInteract(@NotNull PlayerUseItemEvent event) {
this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseRight);
}
protected void onPlayerAttack(@NotNull PlayerHandAnimationEvent event) {
this.tetrisGames.get(event.getPlayer()).pressedButton(TetrisGame.Button.mouseLeft);
}
protected void onPlayerTick(PlayerTickEvent event) {
Player player = event.getPlayer();
TetrisGame tetrisGame = this.tetrisGames.get(player);
if(tetrisGame == null) return;
if(tetrisGame.lost && player.getGameMode() != GameMode.SPECTATOR) {
this.letPlayerLoose(player);
}
}
private void letPlayerLoose(Player player) {
@@ -120,6 +112,7 @@ class Tetris extends StatelessGame {
if(!this.getScore().hasResult(player)) {
player.setGameMode(GameMode.SPECTATOR);
player.setInvisible(true);
if(player.getVehicle() != null) player.getVehicle().removePassenger(player);
this.getScore().insertResult(player, tetrisGame.getScore());
}
@@ -157,6 +150,16 @@ class Tetris extends StatelessGame {
p.teleport(tetrisGame.getPlayerSpawnPosition());
tetrisGame.sidebar.addViewer(p);
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
Entity ghostBlock = new Entity(EntityType.BLOCK_DISPLAY);
((BlockDisplayMeta) ghostBlock.getEntityMeta()).setBlockState(Block.AIR);
ghostBlock.setNoGravity(true);
ghostBlock.setInstance(this, tetrisGame.getPlayerSpawnPosition());
ghostBlock.addPassenger(p);
return TaskSchedule.stop();
}, TaskSchedule.nextTick());
return super.onPlayerJoin(p);
}

View File

@@ -30,6 +30,11 @@ public abstract class Score {
throw new NotImplementedException("This Score type is not able to process points");
}
public void insertMultiple(Set<Player> p) {
p.forEach(player -> this.insertResultProcessor(player, () -> {}));
this.insertResultImplementation(p);
}
public void insertResult(Player p) {
this.insertResultProcessor(p, () -> this.insertResultImplementation(Set.of(p)));
}

View File

@@ -54,18 +54,18 @@ public class Tournament {
}
public List<Set<Player>> getPlaces() {
List<Set<Player>> players = new ArrayList<>(
this.getGameScores().entrySet().stream()
Map<Integer, Set<Player>> players = this.getGameScores().entrySet().stream()
.collect(
Collectors.groupingBy(
Map.Entry::getValue,
Collectors.mapping(Map.Entry::getKey, Collectors.toSet())
)
).values()
);
Collections.reverse(players);
return players;
return players.entrySet().stream()
.sorted(Map.Entry.<Integer, Set<Player>>comparingByKey().reversed())
.map(Map.Entry::getValue)
.toList();
}
private int boost(int selfPlace, int placeCount) {

View File

@@ -10,4 +10,11 @@ public class CommonProperties {
this.put("east", "true");
}
};
public static Map<String, String> fenceNorthSouth = new HashMap<>() {
{
this.put("north", "true");
this.put("south", "true");
}
};
}

View File

@@ -33,9 +33,15 @@ public class Position {
public static List<Block> blocksBelowPlayer(Instance instance, Player p) {
Point playerPos = p.getPosition();
List<Block> blocks = new ArrayList<>();
GeneratorUtils.foreachXZ(playerPos.sub(0.5, 1, 0.5), playerPos.add(0.5, -1, 0.5), point -> {
blocks.add(instance.getBlock(point));
});
GeneratorUtils.foreachXZ(
playerPos.sub(0.5, 1, 0.5),
playerPos.add(0.5, -1, 0.5),
point -> blocks.add(instance.getBlock(point))
);
return blocks.stream().distinct().toList();
}
public static boolean hasPositionChanged(Pos oldPos, Pos newPos) {
return !oldPos.withView(0, 0).equals(newPos.withView(0, 0));
}
}

View File

@@ -105,7 +105,7 @@ optionPvpEnabled;pvp enabled;PvP aktiviert
;;
ns:game_Stickfight#;;
name;Stickfight;Stockschlacht
description;Push your opponents off the Bridge;Stoße deine Gegener von der Brücke
description;Push your opponents off the Bridge;Stoße deine Gegener von der Brücke, der Spieler mit den wenigsten Toden gewinnt!
;;
ns:game_TrafficlightRace#;;
name;Red light green light;Rotes licht, Grünes licht
@@ -170,3 +170,16 @@ ns:game_TurtleGame#;;
name;Turtle Game;Turtle Game
description;Eat snacks and dodge bombs to get the highest score!;Esse Snacks und weiche Bomben aus, um den höchsten Score zu erreichen!
startSpeed;Start Speed;Startgeschwindigkeit
;;
ns:game_BoatRace#;;
name;Boatrace;Bootrennen
description;;
;;
ns:game_Pillars#;;
name;Pillars;Pillars
description;Build yourself up with your random blocks to reach your opponents and push them down!;Baue dich mit deinen zufälligen Blöcken zu deinen Gegnern und schupse sie runter!
;;
ns:game_BlockBattle#;;
name;Block Battle;Block Kampf
description;The team that fills the center with their color first wins!;Das Team, welches als erstes die Mitte mit seiner Farbe gefüllt hat, gewinnt!
itemCount;Block Count;Block Anzahl
1 map en_us de_de
105
106 ns:game_Stickfight#
107 name Stickfight Stockschlacht
108 description Push your opponents off the Bridge Stoße deine Gegener von der Brücke Stoße deine Gegener von der Brücke, der Spieler mit den wenigsten Toden gewinnt!
109
110 ns:game_TrafficlightRace#
111 name Red light green light Rotes licht, Grünes licht
170 name Turtle Game Turtle Game
171 description Eat snacks and dodge bombs to get the highest score! Esse Snacks und weiche Bomben aus, um den höchsten Score zu erreichen!
172 startSpeed Start Speed Startgeschwindigkeit
173
174 ns:game_BoatRace#
175 name Boatrace Bootrennen
176 description
177
178 ns:game_Pillars#
179 name Pillars Pillars
180 description Build yourself up with your random blocks to reach your opponents and push them down! Baue dich mit deinen zufälligen Blöcken zu deinen Gegnern und schupse sie runter!
181
182 ns:game_BlockBattle#
183 name Block Battle Block Kampf
184 description The team that fills the center with their color first wins! Das Team, welches als erstes die Mitte mit seiner Farbe gefüllt hat, gewinnt!
185 itemCount Block Count Block Anzahl