Compare commits

...

71 Commits

Author SHA1 Message Date
edf26785a3 removed accidental code change 2025-04-16 23:45:03 +02:00
4d90f5fc28 added missing 'this' qualifier 2025-04-13 12:59:22 +02:00
343decb05a added this qualifier to tetris classes 2025-04-12 23:53:40 +02:00
36c6c93edb started towerdefense path mechanic 2025-04-11 00:51:43 +02:00
24af27f2e3 fixed different player gamemodes in lobby after games 2025-03-22 11:11:08 +01:00
13132eace6 fixed minestom-pvp version, made stickfight playable 2025-03-03 20:28:10 +01:00
8d479b69e3 updated JumpDive translations 2025-03-03 01:31:57 +01:00
5ca8ad8bd7 added jumpDive game 2025-03-03 01:28:29 +01:00
3f2ba1e428 prevent execution of /hub in api driven rooms 2025-03-02 23:40:39 +01:00
5bab1a1ac7 fixed skin not being applied properly, made /skin privileged 2025-03-02 23:35:30 +01:00
8fdd0487bf updated project to newest minestom commit 2025-03-02 23:26:58 +01:00
e0ee1e66c9 added description message on game start 2025-01-02 01:08:53 +01:00
5acb44b0e1 disabled player collisions 2025-01-01 22:20:57 +01:00
7cd849946b fixed elytra race spectators flying elytra 2024-12-27 12:02:38 +01:00
a71aca5d6c added missing translations 2024-12-27 12:01:44 +01:00
ea08ac7a81 fixed tnt run falling before start 2024-12-27 11:10:18 +01:00
ee192c1035 fixed some bugs 2024-12-27 10:58:07 +01:00
81dbf16d3f fixed tetris player inputs 2024-12-27 10:53:02 +01:00
f03011e4f1 Merge remote-tracking branch 'origin/develop' into develop 2024-12-24 00:26:53 +01:00
9069ead9e9 fixed barrier border for terrain generator 2024-12-24 00:26:41 +01:00
7ced598bfd Merge remote-tracking branch 'origin/develop' into develop 2024-12-23 23:55:35 +01:00
f04f1b33e3 added transfer, updated adress 2024-12-23 23:55:30 +01:00
0715771bfc add adventure mode for tournament display 2024-12-23 23:45:16 +01:00
c18ac59442 changed tetris button press value 2024-12-23 23:28:53 +01:00
0a1ae69f53 Merge branch 'refs/heads/develop-tetris' into develop
# Conflicts:
#	src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java
#	src/main/resources/lang/locales.map.csv
2024-12-16 21:02:50 +01:00
8451463b73 updated minestom version 2024-12-16 21:00:02 +01:00
7e27a05596 updated pvp dependency 2024-12-16 00:52:06 +01:00
ba260519e0 added new tournament display 2024-12-02 15:52:19 +01:00
378d872283 changed computeIfAbsent back to if statement 2024-11-24 00:47:15 +01:00
bc27c35f1a removed debug outputs 2024-11-23 23:58:54 +01:00
18689ac0df fixed score 2024-11-23 23:56:18 +01:00
3fe57d5fe9 continued fixing pr comments 2024-11-23 22:24:08 +01:00
0699206c21 started fixing pr comments 2024-11-23 14:26:19 +01:00
e663f3f105 made tetris spectators invisible, added barrier walls to elytra race 2024-11-04 21:53:54 +01:00
55be88b7da removed countdown when no player left 2024-11-04 15:04:09 +01:00
dc24f28b8f updated pvp, refactored some old code, removed transfer instance 2024-11-03 14:57:53 +01:00
f85ebbbb5d made BoolOption show true or false, shortened tetris Timeout after first death 2024-10-24 23:37:41 +02:00
720d3c8d65 changed Player spawn position 2024-10-24 23:10:09 +02:00
e397d69d7a added score above playfield 2024-10-23 22:43:14 +02:00
bef697e5fc added Tetris options to translation files 2024-10-23 21:15:47 +02:00
6638a48677 added combos 2024-10-23 17:41:05 +02:00
73a374e529 added timeout for tetris and display points at end of PointsWinScore 2024-10-23 17:26:31 +02:00
f838317af0 centered hold and next tetrominoes 2024-10-23 14:53:07 +02:00
3c25f5f079 changed player spawn position 2024-10-23 13:55:39 +02:00
179fa2e4d7 added combat system and options for game list 2024-10-23 01:08:52 +02:00
075db7a91b added border around next and hold tetromino 2024-10-22 21:21:00 +02:00
c9d00f4f77 added tetris to translation file 2024-10-22 17:16:26 +02:00
4de66d65a2 added anvil run to translation file 2024-10-22 17:13:10 +02:00
8594f8029c fixed score at end of tetris not working 2024-10-22 17:05:24 +02:00
e192ae4433 moved tetris from prototype to other 2024-10-22 16:45:32 +02:00
bdb7c85ceb added anvil run to PVE 2024-10-22 16:43:58 +02:00
1b448e749e fixed leaderboard with new PointsWinScore class 2024-10-22 16:34:23 +02:00
2799a40c58 made multiplayer possible 2024-10-22 15:51:00 +02:00
710838645f added ghost tetromino 2024-10-22 00:36:57 +02:00
f56023004a removed unused import 2024-10-21 19:22:51 +02:00
55a98b6464 changed background, added hold, show score 2024-10-21 19:22:31 +02:00
236d372746 fixed collision detection, added rotation 2024-10-21 15:55:54 +02:00
1332a42bf6 added tetromino controlls 2024-10-21 00:27:58 +02:00
5acfe8f6af added basic tetris classes 2024-10-20 18:24:53 +02:00
9d287f7c2f added control input 2024-10-19 22:57:05 +02:00
7ea39f9aad started tetris 2024-10-19 16:38:43 +02:00
21ab8c4bd3 Merge pull request 'develop-anvilRun' (#1) from develop-anvilRun into develop
Reviewed-on: #1
2024-10-19 14:35:16 +00:00
3f247bfc90 privileged commands only for admins 2024-10-19 16:32:51 +02:00
843fa26c08 removed tetris 2024-10-19 16:28:32 +02:00
cfbb2688d2 fixed starting platform for elytra race 2024-10-19 15:54:18 +02:00
350cf108dd added game length for anvil run 2024-10-19 15:43:00 +02:00
c9ef7197cc added scheduled task for anvil run 2024-10-12 17:54:52 +02:00
40f02449d9 finished basic anvil run 2024-10-10 15:46:32 +02:00
e71dccb98d started with tetris 2024-10-09 12:55:50 +02:00
a3f2a06f6a added AnvilRun files 2024-10-08 21:47:28 +02:00
a321d243ba updated minestom version, breaking some behaviour 2024-10-06 17:53:41 +02:00
98 changed files with 1949 additions and 454 deletions

View File

@ -10,8 +10,6 @@ group 'eu.mhsl.minenet'
version '1.0-SNAPSHOT'
repositories {
//maven 'https://repo.unnamed.team/repository/unnamed-public/'
mavenCentral()
google()
@ -28,9 +26,16 @@ repositories {
}
}
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
languageVersion = JavaLanguageVersion.of(21)
}
}
@ -39,13 +44,7 @@ dependencies {
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
//https://jitpack.io/#Minestom/Minestom
// implementation 'com.github.Minestom:Minestom:c496ee357'
// implementation 'com.github.waxeria:Minestom:e0427a36f3'
// implementation 'dev.hollowcube:minestom-ce:5bcc72b911'
implementation 'dev.hollowcube:minestom-ce:8715f4305d'
implementation 'dev.hollowcube:minestom-ce-extensions:1.2.0'
implementation 'net.minestom:minestom-snapshots:fd51c8d17a'
//Tools
implementation 'de.articdive:jnoise:3.0.2'
@ -54,13 +53,11 @@ dependencies {
implementation 'org.spongepowered:configurate-yaml:4.1.2'
implementation 'com.sparkjava:spark-core:2.9.4'
implementation 'com.google.code.gson:gson:2.10.1'
implementation 'com.google.guava:guava:31.0.1-jre'
implementation 'com.google.guava:guava:32.0.1-android'
//PvP
implementation 'com.github.TogAr2:MinestomPvP:35e5661'
//implementation 'com.github.TogAr2:MinestomPvP:135ec9e2b7'
implementation 'io.github.TogAr2:MinestomPvP:PR62-SNAPSHOT'
// Hephaestus engine
implementation("team.unnamed:hephaestus-api:0.2.1-SNAPSHOT")

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

56
gradlew vendored Normal file → Executable file
View File

@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@ -25,7 +27,7 @@
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# eu.mhsl.minenet.minigames.command line, like:
# command line, like:
#
# ksh Gradle
#
@ -35,7 +37,7 @@
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «eu.mhsl.minenet.minigames.command», «set», and «ulimit».
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -80,13 +82,12 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -117,7 +118,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java eu.mhsl.minenet.minigames.command to use to start the JVM.
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
@ -133,29 +134,36 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC2039,SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Collect all arguments for the java eu.mhsl.minenet.minigames.command, stacking in reverse order:
# * args from the eu.mhsl.minenet.minigames.command line
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
@ -193,11 +201,15 @@ if "$cygwin" || "$msys" ; then
done
fi
# Collect all arguments for the java eu.mhsl.minenet.minigames.command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
@ -205,6 +217,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
@ -214,7 +232,7 @@ set -- \
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor eu.mhsl.minenet.minigames.command substitution, so instead we
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap

39
gradlew.bat vendored
View File

@ -13,8 +13,10 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' eu.mhsl.minenet.gameList.command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@ -56,16 +59,16 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
:execute
@rem Setup the eu.mhsl.minenet.gameList.command line
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@ -5,8 +5,6 @@ import eu.mhsl.minenet.minigames.command.Commands;
import eu.mhsl.minenet.minigames.handler.Listeners;
import eu.mhsl.minenet.minigames.lang.Languages;
import eu.mhsl.minenet.minigames.server.tasks.TablistUpdateTask;
import eu.mhsl.minenet.minigames.server.provider.ByPlayerNameUuidProvider;
import io.github.bloepiloepi.pvp.PvpExtension;
import net.minestom.server.MinecraftServer;
import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.extras.lan.OpenToLAN;
@ -42,14 +40,12 @@ public class Main {
logger.info("Initialize Minecraft server...");
MinecraftServer server = MinecraftServer.init();
PvpExtension.init();
// MinestomPvP.init();
MinecraftServer.setBrandName("mhsl.eu - minenet - credits to minestom");
MinecraftServer.setCompressionThreshold(serverConfig.node("compression-threshold").getInt(0));
System.setProperty("minestom.chunk-view-distance", String.valueOf(serverConfig.node("view-distance").getInt()));
MinecraftServer.getConnectionManager().setUuidProvider(new ByPlayerNameUuidProvider());
Commands.values();
Listeners.values();
new HttpServer();

View File

@ -1,6 +1,6 @@
package eu.mhsl.minenet.minigames.command;
import eu.mhsl.minenet.minigames.command.anonymous.SkinCommand;
import eu.mhsl.minenet.minigames.command.privileged.SkinCommand;
import eu.mhsl.minenet.minigames.command.privileged.*;
import eu.mhsl.minenet.minigames.command.anonymous.HubCommand;
import eu.mhsl.minenet.minigames.command.anonymous.LeaveCommand;
@ -41,7 +41,7 @@ public enum Commands {
static {
MinecraftServer.getCommandManager().setUnknownCommandCallback((sender, command) -> {
if(command.isBlank()) return;
new ChatMessage(Icon.ERROR).appendStatic("Unknown command").quote(command).send(sender);
new ChatMessage(Icon.ERROR).appendStatic("Unknown command: ").quote(command).send(sender);
});
}
}

View File

@ -2,6 +2,7 @@ package eu.mhsl.minenet.minigames.command;
import net.minestom.server.command.builder.Command;
import net.minestom.server.command.builder.condition.CommandCondition;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -27,7 +28,7 @@ public class PrivilegedCommand extends Command {
}
protected CommandCondition isPrivileged() {
return (sender, commandString) -> sender.hasPermission("admin");
return (sender, commandString) -> ((Player) sender).getPermissionLevel() == 4;
}
protected void addCondition(CommandCondition condition) {

View File

@ -10,9 +10,13 @@ public class HubCommand extends Command {
public HubCommand() {
super("hub");
setCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Room);
setCondition(
(sender, commandString) ->
((Player) sender).getInstance() instanceof Room room && !room.apiDriven
);
setDefaultExecutor((sender, context) -> {
if(Room.getRoom((Player) sender).orElseThrow().apiDriven) return;
Room.unsetRoom((Player) sender);
MoveInstance.move((Player) sender, Hub.INSTANCE);
});

View File

@ -5,7 +5,6 @@ import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ActionBarMessage;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.message.type.TitleMessage;
import eu.mhsl.minenet.minigames.util.PacketUtil;
import net.minestom.server.entity.Player;
import java.util.ArrayList;
@ -36,8 +35,6 @@ public class DebugCommand extends PrivilegedCommand {
.appendTranslated("score#thanks")
.send(sender);
PacketUtil.resendPlayerList(((Player) sender));
new ChatMessage(Icon.SCIENCE).appendStatic(((Player) sender).getUuid().toString()).send(sender);
});

View File

@ -6,8 +6,6 @@ import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.fakeplayer.FakePlayer;
import net.minestom.server.entity.fakeplayer.FakePlayerOption;
import java.util.UUID;
@ -18,12 +16,12 @@ public class FakeplayerCommand extends PrivilegedCommand {
addSyntax((sender, context) -> {
if(sender instanceof Player p) {
if(p.getInstance() instanceof Room room) {
FakePlayer.initPlayer(
UUID.randomUUID(),
context.getRaw("name"),
new FakePlayerOption().setInTabList(true).setRegistered(true),
fakePlayer -> Room.setRoom(fakePlayer, room)
);
// FakePlayer.initPlayer( // TODO FakePlayer does no longer exists
// UUID.randomUUID(),
// context.getRaw("name"),
// new FakePlayerOption().setInTabList(true).setRegistered(true),
// fakePlayer -> Room.setRoom(fakePlayer, room)
// );
} else {
new ChatMessage(Icon.ERROR).appendStatic("Du musst dich in einer Raumlobby befinden!").send(sender);
}

View File

@ -26,7 +26,7 @@ public class KickCommand extends PrivilegedCommand {
}
private void kick(String playername, String reason) {
Player playerToKick = MinecraftServer.getConnectionManager().findPlayer(playername);
Player playerToKick = MinecraftServer.getConnectionManager().findOnlinePlayer(playername);
Objects.requireNonNull(playerToKick).kick(reason);
}
}

View File

@ -6,16 +6,15 @@ import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.Player;
import net.minestom.server.permission.Permission;
public class OpCommand extends PrivilegedCommand {
public OpCommand() {
super("op");
addSyntax((sender, context) -> {
Player target = MinecraftServer.getConnectionManager().getPlayer(context.getRaw("target"));
Player target = MinecraftServer.getConnectionManager().getOnlinePlayerByUsername(context.getRaw("target"));
if(target != null) {
target.addPermission(new Permission("admin"));
target.setPermissionLevel(4);
target.refreshCommands();
} else new ChatMessage(Icon.ERROR).appendStatic("Spieler nicht gefunden").send(sender);
}, ArgumentType.Entity("target").onlyPlayers(true));

View File

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

View File

@ -27,7 +27,7 @@ public class SetRoomOwnerCommand extends PrivilegedCommand {
addSyntax((sender, context) -> {
System.out.println("Test");
if(sender instanceof Player p) {
Player newOwner = MinecraftServer.getConnectionManager().getPlayer(context.getRaw("player"));
Player newOwner = MinecraftServer.getConnectionManager().getOnlinePlayerByUsername(context.getRaw("player"));
Room.getRoom(p).orElseThrow().setOwner(Objects.requireNonNull(newOwner));
new ChatMessage(Icon.SUCCESS).appendStatic("The new owner has been set!").send(sender);
}

View File

@ -1,11 +1,11 @@
package eu.mhsl.minenet.minigames.command.anonymous;
package eu.mhsl.minenet.minigames.command.privileged;
import net.minestom.server.command.builder.Command;
import eu.mhsl.minenet.minigames.command.PrivilegedCommand;
import net.minestom.server.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin;
public class SkinCommand extends Command {
public class SkinCommand extends PrivilegedCommand {
public SkinCommand() {
super("skin");

View File

@ -6,7 +6,6 @@ import net.minestom.server.event.EventListener;
public enum Listeners {
SPAWN(new AddEntityToInstanceEventListener()),
CHAT(new PlayerChatHandler()),
LOGIN(new PlayerLoginHandler()),
LEAVE(new PlayerLeaveHandler());

View File

@ -1,7 +1,6 @@
package eu.mhsl.minenet.minigames.handler.global;
import eu.mhsl.minenet.minigames.instance.Spawnable;
import eu.mhsl.minenet.minigames.util.PacketUtil;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener;
@ -20,15 +19,13 @@ public class AddEntityToInstanceEventListener implements EventListener<AddEntity
@Override
public @NotNull Result run(@NotNull AddEntityToInstanceEvent event) {
if(event.getEntity() instanceof Player p) {
MinecraftServer.getSchedulerManager().scheduleNextTick(p::refreshCommands, ExecutionType.ASYNC);
MinecraftServer.getSchedulerManager().scheduleNextTick(p::refreshCommands, ExecutionType.TICK_END);
if(event.getInstance() instanceof Spawnable instance) {
p.setRespawnPoint(instance.getSpawn());
}
PacketUtil.resendPlayerList(p);
p.addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, 20)); //TODO Uncomment, currently buggy causes disconnect see https://github.com/Minestom/Minestom/discussions/1302
p.addEffect(new Potion(PotionEffect.BLINDNESS, (byte) 1, 20));
}
return Result.SUCCESS;

View File

@ -1,26 +0,0 @@
package eu.mhsl.minenet.minigames.handler.global;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.PlayerChatEvent;
import org.jetbrains.annotations.NotNull;
public class PlayerChatHandler implements EventListener<PlayerChatEvent> {
@Override
public @NotNull Class<PlayerChatEvent> eventType() {
return PlayerChatEvent.class;
}
@Override
public @NotNull Result run(@NotNull PlayerChatEvent event) {
event.setChatFormat(
(messages) -> new ChatMessage()
.appendStatic(event.getPlayer().getUsername())
.pipe()
.appendStatic(messages.getMessage())
.build(event.getPlayer())
);
return Result.SUCCESS;
}
}

View File

@ -8,10 +8,11 @@ import eu.mhsl.minenet.minigames.skin.SkinCache;
import eu.mhsl.minenet.minigames.util.MoveInstance;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.PlayerLoginEvent;
import eu.mhsl.minenet.minigames.instance.hub.Hub;
import net.minestom.server.permission.Permission;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.network.packet.server.play.TeamsPacket;
import net.minestom.server.scoreboard.Team;
import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.serialize.SerializationException;
@ -20,14 +21,19 @@ import java.util.Objects;
import java.util.UUID;
import java.util.logging.Logger;
public class PlayerLoginHandler implements EventListener<PlayerLoginEvent> {
public class PlayerLoginHandler implements EventListener<AsyncPlayerConfigurationEvent> {
public static final Team globalTeam = MinecraftServer.getTeamManager()
.createBuilder("global")
.collisionRule(TeamsPacket.CollisionRule.NEVER)
.build();
@Override
public @NotNull Class<PlayerLoginEvent> eventType() {
return PlayerLoginEvent.class;
public @NotNull Class<AsyncPlayerConfigurationEvent> eventType() {
return AsyncPlayerConfigurationEvent.class;
}
@Override
public @NotNull Result run(@NotNull PlayerLoginEvent event) {
public @NotNull Result run(@NotNull AsyncPlayerConfigurationEvent event) {
Player p = event.getPlayer();
Transfer transferInstance = new Transfer();
@ -37,22 +43,23 @@ public class PlayerLoginHandler implements EventListener<PlayerLoginEvent> {
UUID pushQueue = QueuedPlayerRooms.pullQueue(event.getPlayer().getUuid());
MinecraftServer.getSchedulerManager().scheduleTask(
() -> {
if(pushQueue != null) {
Room.setRoom(p, Room.getRoom(pushQueue).orElseThrow());
} else {
MoveInstance.move(p, Hub.INSTANCE);
}
},
TaskSchedule.seconds(5),
TaskSchedule.stop()
() -> {
p.setTeam(globalTeam);
if(pushQueue != null) {
Room.setRoom(p, Room.getRoom(pushQueue).orElseThrow());
} else {
MoveInstance.move(p, Hub.INSTANCE);
}
},
TaskSchedule.seconds(1),
TaskSchedule.stop()
);
SkinCache.applySkin(p);
try {
if(Objects.requireNonNull(Main.globalConfig.node("admins").getList(String.class)).stream().anyMatch(s -> s.equalsIgnoreCase(p.getUsername()))) {
p.addPermission(new Permission("admin"));
p.setPermissionLevel(4);
}
} catch (SerializationException | NullPointerException ignored) {}

View File

@ -1,6 +1,7 @@
package eu.mhsl.minenet.minigames.instance;
import net.minestom.server.MinecraftServer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.utils.NamespaceID;
import net.minestom.server.world.DimensionType;
@ -9,33 +10,39 @@ import net.minestom.server.world.DimensionType;
*/
public enum Dimension {
OVERWORLD(
NamespaceID.from("minenet:fullbright_overworld"),
DimensionType
.builder(NamespaceID.from("minenet:fullbright_overworld"))
.builder()
.ambientLight(2.0f)
.build()
),
NETHER(
NamespaceID.from("minenet:fullbright_nether"),
DimensionType
.builder(NamespaceID.from("minenet:fullbright_nether"))
.builder()
.ambientLight(2.0f)
.effects("minecraft:the_nether")
.build()
),
THE_END(
NamespaceID.from("minenet:fullbright_end"),
DimensionType
.builder(NamespaceID.from("minenet:fullbright_end"))
.builder()
.ambientLight(2.0f)
.effects("minecraft:the_end")
.build()
);
public final DimensionType DIMENSION;
Dimension(DimensionType dimType) {
public final NamespaceID namespaceID;
public final DynamicRegistry.Key<DimensionType> key;
Dimension(NamespaceID namespaceID, DimensionType dimType) {
this.DIMENSION = dimType;
this.namespaceID = namespaceID;
MinecraftServer.getDimensionTypeManager().addDimension(this.DIMENSION);
this.key = MinecraftServer.getDimensionTypeRegistry().register(namespaceID, DIMENSION);
}
}

View File

@ -7,13 +7,15 @@ import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.instance.InstanceManager;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType;
import java.util.UUID;
public class MineNetInstance extends InstanceContainer {
public MineNetInstance(DimensionType type) {
public MineNetInstance(DynamicRegistry.Key<DimensionType> type) {
super(UUID.randomUUID(), type);
MinecraftServer.getInstanceManager().registerInstance(this);

View File

@ -16,6 +16,7 @@ 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.registry.DynamicRegistry;
import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType;
@ -36,18 +37,18 @@ public abstract class Game extends MineNetInstance implements Spawnable {
protected final Logger logger;
public Game(DimensionType dimensionType) {
public Game(DynamicRegistry.Key<DimensionType> dimensionType) {
super(dimensionType);
MinecraftServer.getInstanceManager().registerInstance(this);
logger = Logger.getLogger("Game:" + getUniqueId());
logger = Logger.getLogger("Game:" + getUuid());
eventNode()
.addListener(PlayerMoveEvent.class, this::onPlayerMove)
.addListener(PlayerBlockBreakEvent.class, this::onBlockBreak)
.addListener(PlayerBlockPlaceEvent.class, this::onBlockPlace)
.addListener(ItemDropEvent.class, this::onItemDrop);
.addListener(PlayerMoveEvent.class, this::onPlayerMove)
.addListener(PlayerBlockBreakEvent.class, this::onBlockBreak)
.addListener(PlayerBlockPlaceEvent.class, this::onBlockPlace)
.addListener(ItemDropEvent.class, this::onItemDrop);
}
public Game setParent(Room parentRoom) {
@ -62,6 +63,17 @@ public abstract class Game extends MineNetInstance implements Spawnable {
game.load();
Room.getRoom(owner).orElseThrow().moveMembersToInstance(game);
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
game.getPlayers().forEach(player -> new ChatMessage(Icon.SCIENCE)
.appendStatic(factory.name().getAssembled(player).asComponent())
.newLine()
.appendStatic(factory.description().getAssembled(player).asComponent())
.send(player));
return TaskSchedule.stop();
}, TaskSchedule.seconds(3));
} catch (Exception e) {
new ChatMessage(Icon.ERROR).appendStatic("Instance crashed: " + e.getMessage()).send(owner);
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> Room.getRoom(owner).orElseThrow().moveMembersToRoomLobby());
@ -78,7 +90,7 @@ public abstract class Game extends MineNetInstance implements Spawnable {
this.onLoad(callback);
// callback.whenComplete((unused, throwable) -> this.start());
return TaskSchedule.stop();
}, ExecutionType.ASYNC);
}, ExecutionType.TICK_END);
}
@ -101,7 +113,7 @@ public abstract class Game extends MineNetInstance implements Spawnable {
scheduler().scheduleTask(() -> {
logger.info("stopping game instance " + this.uniqueId);
logger.info("stopping game instance " + this.uuid);
getPlayers().forEach(player -> player.kick("timeout"));
MinecraftServer.getInstanceManager().unregisterInstance(this);
@ -117,7 +129,6 @@ public abstract class Game extends MineNetInstance implements Spawnable {
protected void onStop() {}
protected void onUnload() {}
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
}

View File

@ -1,32 +1,38 @@
package eu.mhsl.minenet.minigames.instance.game;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun.AnvilRunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory;
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.acidRain.AcidRainFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube.DeathcubeFactory;
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.spleef.SpleefFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.stickfight.StickFightFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.TetrisFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.tntrun.TntRunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.trafficlightrace.TrafficLightRaceFactory;
public enum GameList {
DEATHCUBE(new DeathcubeFactory(), GameType.JUMPNRUN),
STICKFIGHT(new StickFightFactory(), GameType.PVP),
MINERUN(new MinerunFactory(), GameType.JUMPNRUN),
TRAFFICLIGHTRACE(new TrafficLightRaceFactory(), GameType.OTHER),
STICKFIGHT(new StickFightFactory(), GameType.PROTOTYPE),
TOWERDEFENSE(new TowerdefenseFactory(), GameType.PROTOTYPE),
BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE),
BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE),
BOWSPLEEF(new BowSpleefFactory(), GameType.PROTOTYPE),
TETRIS(new TetrisFactory(), GameType.OTHER),
TNTRUN(new TntRunFactory(), GameType.OTHER),
ANVILRUN(new AnvilRunFactory(), GameType.PVE),
ACIDRAIN(new AcidRainFactory(), GameType.PVE),
ELYTRARACE(new ElytraRaceFactory(), GameType.PVP),
SPLEEF(new SpleefFactory(), GameType.PVP),
BOWSPLEEF(new BowSpleefFactory(), GameType.PVP);
JUMPDIVE(new JumpDiveFactory(), GameType.JUMPNRUN);
private final GameFactory factory;
private final GameType type;

View File

@ -9,7 +9,9 @@ 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.registry.DynamicRegistry;
import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType;
@ -19,10 +21,12 @@ import java.util.concurrent.CompletableFuture;
public class StatelessGame extends Game {
private final String name;
private final Score score;
private Task timeLimitTask;
private int timeLimit = 0;
private int timePlayed = 0;
public StatelessGame(DimensionType dimensionType, String gameName, Score score) {
public StatelessGame(DynamicRegistry.Key<DimensionType> dimensionType, String gameName, Score score) {
super(dimensionType);
this.score = score;
this.name = gameName;
@ -38,8 +42,12 @@ public class StatelessGame extends Game {
public void setTimeLimit(int limit) {
this.timeLimit = limit;
if(timeLimit > 0) {
scheduler().submitTask(() -> {
if(this.timeLimitTask != null) {
this.timeLimitTask.cancel();
this.timePlayed = 0;
}
if(this.timeLimit > 0) {
this.timeLimitTask = scheduler().submitTask(() -> {
if(!isRunning || timeLimit == 0) return TaskSchedule.stop();
if(timeLimit <= timePlayed) {
stop();
@ -48,14 +56,14 @@ public class StatelessGame extends Game {
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());
case 90, 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);
}, ExecutionType.TICK_START);
}
}

View File

@ -47,7 +47,7 @@ public class GameConfigurationInventory extends InteractableInventory {
setClickableItem(
ItemStack.builder(Material.RED_WOOL)
.displayName(
.customName(
TranslatedComponent.byId("common#back")
.setColor(NamedTextColor.RED)
.getAssembled(p)
@ -62,7 +62,7 @@ public class GameConfigurationInventory extends InteractableInventory {
setDummyItem(
ItemStack.builder(Material.NAME_TAG)
.displayName(
.customName(
factory.name().setColor(NamedTextColor.GOLD).getAssembled(p)
)
.build(),
@ -80,7 +80,7 @@ public class GameConfigurationInventory extends InteractableInventory {
if(config == null) {
setDummyItem(
ItemStack.builder(Material.BARRIER)
.displayName(
.customName(
TranslatedComponent.byId("room#noOption").setColor(NamedTextColor.RED).getAssembled(p)
)
.lore(
@ -130,7 +130,7 @@ public class GameConfigurationInventory extends InteractableInventory {
setClickableItem(
ItemStack.builder(restrictionHandler.getWarnings(restrictionData).size() > 0 ? Material.YELLOW_WOOL : Material.GREEN_WOOL)
.displayName(TranslatedComponent.byId("restriction#success").setColor(NamedTextColor.GREEN).getAssembled(p))
.customName(TranslatedComponent.byId("restriction#success").setColor(NamedTextColor.GREEN).getAssembled(p))
.lore(restrictionHandler.getWarnings(restrictionData).stream().map(translatedComponent -> translatedComponent.getAssembled(p)).collect(Collectors.toList()))
.build(),
8,
@ -142,7 +142,7 @@ public class GameConfigurationInventory extends InteractableInventory {
setClickableItem(
ItemStack.builder(Material.RED_WOOL)
.displayName(TranslatedComponent.byId("restriction#fail").setColor(NamedTextColor.RED).getAssembled(p))
.customName(TranslatedComponent.byId("restriction#fail").setColor(NamedTextColor.RED).getAssembled(p))
.lore(
restrictionHandler.getRestrictions()
.stream()

View File

@ -9,6 +9,7 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import java.util.List;
import java.util.Objects;
public abstract class Option<T> {
private RestrictionHandler restrictionHandler;
@ -25,7 +26,7 @@ public abstract class Option<T> {
this.name = name;
this.options = options;
currentValue = options.get(0);
currentValue = options.getFirst();
}
public void setRestrictionHandler(RestrictionHandler restrictionHandler) {
@ -44,11 +45,11 @@ public abstract class Option<T> {
}
public ItemStack getCurrent(Player p) {
int amount = Integer.parseInt(options.get(pointer).toString());
String value = options.get(pointer).toString();
return ItemStack.builder(item)
.displayName(name.getAssembled(p))
.customName(name.getAssembled(p))
.lore(TranslatedComponent.byId("optionCommon#value").setColor(NamedTextColor.GOLD).getAssembled(p)
.append(Component.text(": ")).append(Component.text(amount)))
.append(Component.text(": ")).append(Component.text(value)))
.build();
}
@ -56,6 +57,10 @@ public abstract class Option<T> {
return Integer.parseInt(getAsString());
}
public boolean getAsBoolean() {
return Objects.equals(getAsString(), "true") || Objects.equals(getAsString(), "1");
}
public String getAsString() {
return currentValue.toString();
}

View File

@ -6,8 +6,8 @@ import net.minestom.server.item.Material;
import java.util.List;
public class BoolOption extends Option<Boolean> {
public class BoolOption extends Option<String> {
public BoolOption(String id, Material item, TranslatedComponent name) {
super(id, item, name, List.of(true, false));
super(id, item, name, List.of("true", "false"));
}
}

View File

@ -17,8 +17,8 @@ import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerTickEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import net.minestom.server.network.packet.server.play.ParticlePacket;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull;
@ -38,7 +38,7 @@ public class AcidRain extends StatelessGame {
.setFrequency(0.09)
.build();
public AcidRain() {
super(Dimension.OVERWORLD.DIMENSION, "acidRain", new LastWinsScore());
super(Dimension.OVERWORLD.key, "acidRain", new LastWinsScore());
setGenerator(
new CircularPlateTerrainGenerator(radius)
.setPlateHeight(50)
@ -62,13 +62,13 @@ public class AcidRain extends StatelessGame {
MinecraftServer.getSchedulerManager().submitTask(() -> {
getPlayers().forEach(player -> {
player.sendPacket(ParticleCreator.createParticlePacket(Particle.SNEEZE, 0, 60, 0, radius, radius, radius, 500));
player.sendPacket(ParticleCreator.createParticlePacket(Particle.ITEM_SLIME, 0, 60, 0, radius, radius, radius, 500));
player.sendPacket(new ParticlePacket(Particle.SNEEZE, 0, 60, 0, radius, radius, radius, 1f, 500));
player.sendPacket(new ParticlePacket(Particle.ITEM_SLIME, 0, 60, 0, radius, radius, radius, 1f, 500));
});
if(!isRunning) return TaskSchedule.stop();
return TaskSchedule.millis(100);
}, ExecutionType.ASYNC);
}, ExecutionType.TICK_END);
MinecraftServer.getSchedulerManager().submitTask(() -> {
generationOffset++;
@ -76,7 +76,7 @@ public class AcidRain extends StatelessGame {
if(!isRunning) return TaskSchedule.stop();
return TaskSchedule.millis((long) NumberUtil.map(50 - difficulty, 0, 50, 100, 1000));
}, ExecutionType.ASYNC);
}, ExecutionType.TICK_END);
MinecraftServer.getSchedulerManager().submitTask(() -> {
difficulty++;

View File

@ -15,6 +15,11 @@ public class AcidRainFactory implements GameFactory {
return TranslatedComponent.byId("game_AcidRain#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_AcidRain#description");
}
@Override
public Material symbol() {
return Material.SLIME_BALL;

View File

@ -0,0 +1,111 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
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.metadata.other.FallingBlockMeta;
import net.minestom.server.event.entity.EntityTickEvent;
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.Scheduler;
import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
class AnvilRun extends StatelessGame {
final int spawnHeight = 30;
final int radius;
int anvilsPerSecond;
final int seconds;
final int anvilHeight = 200;
final List<Pos> anvilSpawnPositions = new ArrayList<>();
public AnvilRun(int radius, int seconds) {
super(Dimension.OVERWORLD.key, "Anvil Run", new LastWinsScore());
this.radius = radius;
this.seconds = seconds;
this.setGenerator(new CircularPlateTerrainGenerator(radius));
eventNode().addListener(EntityTickEvent.class, this::onEntityTick);
}
@Override
protected void onLoad(@NotNull 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;
anvilSpawnPositions.add(new Pos(x+0.5, anvilHeight, z+0.5));
batch.setBlock(x, spawnHeight-1, z, Block.SNOW_BLOCK);
}
}
this.anvilsPerSecond = anvilSpawnPositions.size() / this.seconds;
Collections.shuffle(anvilSpawnPositions);
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
}
protected void spawnAnvil(Pos spawnPosition) {
Entity anvil = new Entity(EntityType.FALLING_BLOCK);
((FallingBlockMeta) anvil.getEntityMeta()).setBlock(Block.ANVIL);
anvil.setInstance(this, spawnPosition);
}
@Override
protected void onStart() {
super.onStart();
Scheduler scheduler = MinecraftServer.getSchedulerManager();
for(int i=0; i<this.anvilSpawnPositions.size(); i++) {
final int j = i;
scheduler.scheduleTask(
() -> spawnAnvil(this.anvilSpawnPositions.get(j)),
TaskSchedule.millis(
(long) Math.floor((double) i/this.anvilsPerSecond * 1000)
),
TaskSchedule.stop()
);
}
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
super.onPlayerMove(playerMoveEvent);
if(isBeforeBeginning && playerMoveEvent.getNewPosition().y() < spawnHeight - 2) {
playerMoveEvent.setCancelled(true);
playerMoveEvent.getPlayer().teleport(getSpawn());
return;
}
if(playerMoveEvent.getNewPosition().y() < spawnHeight - 2) getScore().insertResult(playerMoveEvent.getPlayer());
}
protected void onEntityTick(@NotNull EntityTickEvent entityTickEvent) {
if(!entityTickEvent.getEntity().getEntityType().equals(EntityType.FALLING_BLOCK)) return;
Pos anvilPosition = entityTickEvent.getEntity().getPosition();
if(anvilPosition.y() > spawnHeight + 0.5) return;
if(anvilPosition.y() < spawnHeight - 3) entityTickEvent.getEntity().remove();
if(this.getBlock(anvilPosition.withY(spawnHeight-1)).isAir()) return;
this.setBlock(anvilPosition.withY(spawnHeight-1), Block.AIR);
}
@Override
public Pos getSpawn() {
return new Pos(0, spawnHeight, 0);
}
}

View File

@ -0,0 +1,41 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun;
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.game.stateless.config.ConfigManager;
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 AnvilRunFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_AnvilRun#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_AnvilRun#description");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 5, 10, 15, 20, 25, 30))
.addOption(new NumericOption("seconds", Material.STICK, TranslatedComponent.byId("optionCommon#seconds"), 10, 30, 60, 90, 120));
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) {
return new AnvilRun(configuration.get("radius").getAsInt(), configuration.get("seconds").getAsInt()).setParent(parent);
}
@Override
public Material symbol() {
return Material.ANVIL;
}
}

View File

@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
public class Backrooms extends StatelessGame {
public Backrooms() {
super(Dimension.NETHER.DIMENSION, "Backrooms", new NoScore());
super(Dimension.NETHER.key, "Backrooms", new NoScore());
BackroomsGenerator generator = new BackroomsGenerator();
setGenerator(unit -> generator.generateRoom(unit, 50));
}

View File

@ -21,7 +21,7 @@ import net.minestom.server.event.item.PickupItemEvent;
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.AnvilLoader;
import net.minestom.server.instance.anvil.AnvilLoader;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.timer.ExecutionType;
@ -38,7 +38,7 @@ public class Bedwars extends StatelessGame {
public Bedwars() throws IOException {
super(Dimension.OVERWORLD.DIMENSION, "Bedwars", new LastWinsScore());
super(Dimension.OVERWORLD.key, "Bedwars", new LastWinsScore());
setChunkLoader(new AnvilLoader(Resource.GAME_MAP.getPath().resolve("bedwars/test")));
Configuration config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(Resource.GAME_MAP.getPath().resolve("bedwars/test/config.yml").toFile());
@ -78,7 +78,7 @@ public class Bedwars extends StatelessGame {
});
return TaskSchedule.stop();
}, ExecutionType.SYNC);
}, ExecutionType.TICK_END);
}

View File

@ -6,31 +6,22 @@ import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.util.GeneratorUtils;
import io.github.bloepiloepi.pvp.events.ProjectileHitEvent;
import io.github.bloepiloepi.pvp.projectile.CustomEntityProjectile;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.*;
import net.minestom.server.entity.metadata.arrow.ArrowMeta;
import net.minestom.server.entity.metadata.other.PrimedTntMeta;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.item.ItemUpdateStateEvent;
import net.minestom.server.event.player.PlayerItemAnimationEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
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.Enchantment;
import net.minestom.server.item.ItemHideFlag;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.tag.Tag;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.time.TimeUnit;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
public class BowSpleef extends StatelessGame {
@ -39,48 +30,48 @@ public class BowSpleef extends StatelessGame {
private final int radius = 30;
private final int totalElevation = 50;
public BowSpleef() {
super(Dimension.OVERWORLD.DIMENSION, "bowSpleef", new LastWinsScore());
super(Dimension.OVERWORLD.key, "bowSpleef", new LastWinsScore());
// eventNode().addListener( TODO implement bow mechanism
// EventListener
// .builder(PlayerItemAnimationEvent.class)
// .handler(playerItemAnimationEvent -> playerItemAnimationEvent.getPlayer().setTag(CHARGE_BOW_SINCE, System.currentTimeMillis()))
// .filter(playerItemAnimationEvent -> playerItemAnimationEvent.getItemAnimationType() == PlayerItemAnimationEvent.ItemAnimationType.BOW)
// .build()
// );
//
// eventNode().addListener(
// EventListener
// .builder(ItemUpdateStateEvent.class)
// .handler(event -> {
// final Player player = event.getPlayer();
// final double chargedFor = (System.currentTimeMillis() - player.getTag(CHARGE_BOW_SINCE)) / 1000D;
// final double power = MathUtils.clamp((chargedFor * chargedFor + 2 * chargedFor) / 2D, 0, 1);
//
// if (power > 0.2) {
// final CustomEntityProjectile projectile = new CustomEntityProjectile(player, EntityType.ARROW);
// final ArrowMeta meta = (ArrowMeta) projectile.getEntityMeta();
// meta.setCritical(power >= 0.9);
// projectile.scheduleRemove(Duration.of(100, TimeUnit.SERVER_TICK));
// meta.setOnFire(true);
//
// final Pos position = player.getPosition().add(0, player.getEyeHeight(), 0);
// projectile.setInstance(Objects.requireNonNull(player.getInstance()), position);
//
// final Vec direction = projectile.getPosition().direction();
// projectile.shootFrom(position.add(direction).sub(0, 0.2, 0), power * 3, 1.0);
// projectile.setTag(ARROW_FIRST_HIT, true);
// }
// })
// .filter(itemUpdateStateEvent -> itemUpdateStateEvent.getItemStack().material() == Material.BOW)
// .build()
// );
eventNode().addListener(
EventListener
.builder(PlayerItemAnimationEvent.class)
.handler(playerItemAnimationEvent -> playerItemAnimationEvent.getPlayer().setTag(CHARGE_BOW_SINCE, System.currentTimeMillis()))
.filter(playerItemAnimationEvent -> playerItemAnimationEvent.getItemAnimationType() == PlayerItemAnimationEvent.ItemAnimationType.BOW)
.build()
);
eventNode().addListener(
EventListener
.builder(ItemUpdateStateEvent.class)
.handler(event -> {
final Player player = event.getPlayer();
final double chargedFor = (System.currentTimeMillis() - player.getTag(CHARGE_BOW_SINCE)) / 1000D;
final double power = MathUtils.clamp((chargedFor * chargedFor + 2 * chargedFor) / 2D, 0, 1);
if (power > 0.2) {
final CustomEntityProjectile projectile = new CustomEntityProjectile(player, EntityType.ARROW, true);
final ArrowMeta meta = (ArrowMeta) projectile.getEntityMeta();
meta.setCritical(power >= 0.9);
projectile.scheduleRemove(Duration.of(100, TimeUnit.SERVER_TICK));
projectile.setOnFire(true);
final Pos position = player.getPosition().add(0, player.getEyeHeight(), 0);
projectile.setInstance(Objects.requireNonNull(player.getInstance()), position);
final Vec direction = projectile.getPosition().direction();
projectile.shoot(position.add(direction).sub(0, 0.2, 0), power * 3, 1.0);
projectile.setTag(ARROW_FIRST_HIT, true);
}
})
.filter(itemUpdateStateEvent -> itemUpdateStateEvent.getItemStack().material() == Material.BOW)
.build()
);
eventNode().addListener(
EventListener
.builder(ProjectileHitEvent.ProjectileBlockHitEvent.class)
.builder(ProjectileCollideWithBlockEvent.class)
.handler(projectileBlockHitEvent -> {
CustomEntityProjectile projectile = projectileBlockHitEvent.getEntity();
Entity projectile = projectileBlockHitEvent.getEntity();
if(!projectile.getTag(ARROW_FIRST_HIT)) {
projectile.remove();
return;
@ -108,7 +99,7 @@ public class BowSpleef extends StatelessGame {
eventNode().addListener(
EventListener
.builder(ProjectileHitEvent.ProjectileEntityHitEvent.class)
.builder(ProjectileCollideWithEntityEvent.class)
.handler(projectileEntityHitEvent -> projectileEntityHitEvent.setCancelled(true))
.build()
);
@ -135,9 +126,8 @@ public class BowSpleef extends StatelessGame {
0,
ItemStack
.builder(Material.BOW)
.displayName(TranslatedComponent.byId("bow").getAssembled(player))
.meta(builder -> builder.enchantment(Enchantment.FLAME, (short) 1).build())
.meta(builder -> builder.hideFlag(ItemHideFlag.HIDE_ENCHANTS))
.customName(TranslatedComponent.byId("bow").getAssembled(player))
.glowing(true)
.build()
);
});

View File

@ -12,7 +12,12 @@ import java.util.Map;
public class BowSpleefFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("");
return TranslatedComponent.byId("game_BowSpleef#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_BowSpleef#description");
}
@Override

View File

@ -6,9 +6,7 @@ import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.world.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import io.github.bloepiloepi.pvp.config.AttackConfig;
import io.github.bloepiloepi.pvp.config.DamageConfig;
import io.github.bloepiloepi.pvp.config.PvPConfig;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
@ -23,17 +21,18 @@ class Deathcube extends StatelessGame {
final int percentage;
public Deathcube(int radius, int height, int percentage, int pvpEnabled) {
super(Dimension.THE_END.DIMENSION, "Deathcube", new FirstWinsScore());
super(Dimension.THE_END.key, "Deathcube", new FirstWinsScore());
this.radius = radius;
this.height = height + 49;
this.percentage = percentage;
this.setGenerator(new CircularPlateTerrainGenerator(radius+10).setPlateHeight(50));
if(pvpEnabled == 1) eventNode().addChild(
PvPConfig.emptyBuilder()
.damage(DamageConfig.legacyBuilder().fallDamage(false))
.attack(AttackConfig.legacyBuilder().attackCooldown(true))
.build().createNode()
CombatFeatures.empty()
.add(CombatFeatures.VANILLA_ATTACK)
.add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build().createNode()
);
System.out.println(radius);
}
@ -60,12 +59,20 @@ class Deathcube extends StatelessGame {
@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() < 48) {
playerMoveEvent.setCancelled(true);
playerMoveEvent.getPlayer().teleport(getSpawn());
return;
}
if(isBeforeBeginning && playerMoveEvent.getNewPosition().y() > 51.5) {
playerMoveEvent.setCancelled(true);
return;
}
if(playerMoveEvent.getNewPosition().y() > height) getScore().insertResult(playerMoveEvent.getPlayer());
}
@Override
public Pos getSpawn() {
return new Pos(0, 50, 30);
return new Pos(0, 50, -(radius+5));
}
}

View File

@ -28,7 +28,7 @@ public class DeathcubeFactory implements GameFactory {
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30))
.addOption(new NumericOption("height", Material.SCAFFOLDING, TranslatedComponent.byId("optionCommon#height"), 10, 30, 50))
.addOption(new NumericOption("percentage", Material.COBWEB, TranslatedComponent.byId("game_Deathcube#optionPercentageBlocks"), 5, 7, 9, 11, 13))
.addOption(new NumericOption("pvpEnabled", Material.STICK, TranslatedComponent.byId("game_Deathcube#optionPvpEnabled"), 1, 0));
.addOption(new NumericOption("pvpEnabled", Material.STICK, TranslatedComponent.byId("game_Deathcube#optionPvpEnabled"), 0, 1));
}

View File

@ -17,6 +17,7 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.*;
@ -26,7 +27,6 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.ParticlePacket;
import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.sound.SoundEvent;
import org.jetbrains.annotations.NotNull;
@ -40,6 +40,7 @@ public class ElytraRace extends StatelessGame {
private final ValeGenerator vale = new ValeGenerator();
private final int gameHeight = 0;
private final int seaLevel = -55;
private final int ringSpacing = 100;
private final int ringCount;
@ -57,12 +58,12 @@ public class ElytraRace extends StatelessGame {
private final Map<Player, CheckPointData> playerCheckpoints = new HashMap<>();
public ElytraRace(int ringCount) {
super(Dimension.OVERWORLD.DIMENSION, "ElytraRace", new FirstWinsScore());
super(Dimension.OVERWORLD.key, "ElytraRace", new FirstWinsScore());
this.ringCount = ringCount;
setGenerator(vale);
vale.setCalculateSeaLevel(point -> -55);
vale.setCalculateSeaLevel(point -> seaLevel);
vale.setXShiftMultiplier(integer -> NumberUtil.map(integer, 50, 500, 0, 1));
vale.addMixIn(new PlaneTerrainGenerator(gameHeight, Block.BARRIER));
@ -106,9 +107,7 @@ public class ElytraRace extends StatelessGame {
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
Point spawnpoint = new Pos(vale.getXShiftAtZ(0), -46, 0);
GeneratorUtils.iterateArea(spawnpoint.sub(2, 0, 2), spawnpoint.add(2, 0, 2), point -> {
setBlock(point, BlockPallet.STREET.rnd());
});
GeneratorUtils.iterateArea(spawnpoint.sub(5, 0, 5), spawnpoint.add(5, 0, 5), point -> setBlock(point, BlockPallet.STREET.rnd()));
generateRing(ringSpacing);
generateRing(ringSpacing * 2);
@ -118,9 +117,9 @@ public class ElytraRace extends StatelessGame {
@Override
protected void onStart() {
getPlayers().forEach(player -> {
player.getInventory().setChestplate(ItemStack.of(Material.ELYTRA));
player.getInventory().setEquipment(EquipmentSlot.CHESTPLATE, (byte) 0, ItemStack.of(Material.ELYTRA));
for(int i = 0; i < 3; i++) {
player.getInventory().setItemStack(i, ItemStack.builder(boostMaterial).displayName(TranslatedComponent.byId("boost").getAssembled(player)).build());
player.getInventory().setItemStack(i, ItemStack.builder(boostMaterial).customName(TranslatedComponent.byId("boost").getAssembled(player)).build());
}
addResetItemToPlayer(player);
});
@ -131,6 +130,11 @@ public class ElytraRace extends StatelessGame {
Player player = playerMoveEvent.getPlayer();
Point newPos = playerMoveEvent.getNewPosition();
if(isBeforeBeginning && playerMoveEvent.getNewPosition().y() < getSpawn().y()) {
player.teleport(getSpawn());
return;
}
playerCheckpoints.putIfAbsent(player, new CheckPointData(ringSpacing, ringSpacing * 2));
if(newPos.z() > generatedUntil - ringSpacing) {
@ -144,7 +148,7 @@ public class ElytraRace extends StatelessGame {
if(newPos.y() > gameHeight - 5) {
Point particlePoint = newPos.withY(gameHeight);
ParticlePacket particle = ParticleCreator.createParticlePacket(
ParticlePacket particle = new ParticlePacket(
Particle.WAX_ON,
particlePoint.blockX(),
particlePoint.blockY(),
@ -152,6 +156,7 @@ public class ElytraRace extends StatelessGame {
20,
0,
30,
1f,
Math.toIntExact((long) NumberUtil.map(newPos.y(), gameHeight - 5, gameHeight, 50, 500))
);
player.sendPacket(particle);
@ -164,6 +169,7 @@ public class ElytraRace extends StatelessGame {
if(newPos.z() > ringCount * ringSpacing) {
getScore().insertResult(player);
player.setGameMode(GameMode.SPECTATOR);
player.setFlyingWithElytra(false);
}
}
@ -173,7 +179,7 @@ public class ElytraRace extends StatelessGame {
}
private void addResetItemToPlayer(Player p) {
p.getInventory().setItemStack(8, ItemStack.builder(resetMaterial).displayName(TranslatedComponent.byId("reset").getAssembled(p)).build());
p.getInventory().setItemStack(8, ItemStack.builder(resetMaterial).customName(TranslatedComponent.byId("reset").getAssembled(p)).build());
}
private Point getRingPositionAtZ(int z) {
@ -189,8 +195,8 @@ public class ElytraRace extends StatelessGame {
Point ringPos = getRingPositionAtZ(zPos);
GeneratorUtils.iterateArea(
ringPos.sub(100, 0, 0).withY(getDimensionType().getMinY()),
ringPos.add(100, 0, 0).withY(gameHeight),
ringPos.sub(100, 0, 0).withY(0),
ringPos.add(100, 0, 0).withY(seaLevel),
point -> batch.setBlock(point, Block.BARRIER)
);
GeneratorUtils.iterateArea(

View File

@ -14,7 +14,12 @@ import java.util.Map;
public class ElytraRaceFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("");
return TranslatedComponent.byId("game_ElytraRace#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_ElytraRace#description");
}
@Override
@ -25,7 +30,7 @@ public class ElytraRaceFactory implements GameFactory {
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("ringCount", Material.DIAMOND_BLOCK, TranslatedComponent.byId("ringCount"), 5, 10, 20, 30, 40, 50));
.addOption(new NumericOption("ringCount", Material.DIAMOND_BLOCK, TranslatedComponent.byId("game_ElytraRace#ringCount"), 5, 10, 20, 30, 40, 50));
}
@Override

View File

@ -0,0 +1,99 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.jumpDive;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.PointsWinScore;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.world.BlockPallet;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.coordinate.Pos;
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.WeakHashMap;
import java.util.concurrent.CompletableFuture;
public class JumpDive extends StatelessGame {
private final int radius;
private final int height;
private final int timeLimit;
private final WeakHashMap<Player, Integer> scores = new WeakHashMap<>();
public JumpDive(int radius, int height, int timeLimit) {
super(Dimension.OVERWORLD.key, "jumpDive", new PointsWinScore());
this.radius = radius;
this.height = height;
this.timeLimit = timeLimit;
}
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = -radius*2; x <= radius*2; x++) {
for(int z = -radius*2; z <= radius*2; z++) {
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) {
batch.setBlock(x, height, z, BlockPallet.STONE.rnd());
} else {
batch.setBlock(x, 0, z, BlockPallet.GROUND.rnd());
batch.setBlock(x, 1, z, Block.WATER);
}
}
}
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
}
@Override
protected void onStart() {
setTimeLimit(timeLimit);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
Player p = playerMoveEvent.getPlayer();
if(
p.isOnGround() && playerMoveEvent.getNewPosition().y() < height
|| playerMoveEvent.getNewPosition().y() < 0
|| isBeforeBeginning && playerMoveEvent.getNewPosition().y() < height
) {
p.teleport(getSpawn());
playerMoveEvent.setCancelled(true);
}
if(
playerMoveEvent.getNewPosition().y() <= 1
&& playerMoveEvent.getNewPosition().distance(0, 1, 0) < radius + 0.5
&& !(!isBeforeBeginning && !isRunning)
) {
setBlock(playerMoveEvent.getNewPosition().withY(1), Block.REDSTONE_BLOCK);
scores.merge(p, 1, Integer::sum);
p.teleport(getSpawn());
playerMoveEvent.setCancelled(true);
p.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 2f, 2f));
}
}
@Override
protected void onStop() {
getPlayers().forEach(player -> getScore().insertResult(player, scores.getOrDefault(player, 0)));
}
@Override
public Pos getSpawn() {
double theta = rnd.nextDouble() * 2 * Math.PI;
double spawnRadius = radius + 2;
double x = spawnRadius * Math.cos(theta);
double z = spawnRadius * Math.sin(theta);
return new Pos(x, height + 2, z).withLookAt(new Pos(0, height, 0));
}
}

View File

@ -0,0 +1,43 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.jumpDive;
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 JumpDiveFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_jumpDive#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_jumpDive#description");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 5, 8, 10, 12, 14, 16))
.addOption(new NumericOption("height", Material.SCAFFOLDING, TranslatedComponent.byId("optionCommon#height"), 30, 60, 90))
.addOption(new NumericOption("timeLimit", Material.CLOCK, TranslatedComponent.byId("optionCommon#seconds"), 60, 120, 180, 240, 300));
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new JumpDive(configuration.get("radius").getAsInt(), configuration.get("height").getAsInt(), configuration.get("timeLimit").getAsInt()).setParent(parent);
}
@Override
public Material symbol() {
return Material.WATER_BUCKET;
}
}

View File

@ -10,7 +10,6 @@ import eu.mhsl.minenet.minigames.world.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.SquarePlateTerrainGenerator;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerMoveEvent;
@ -33,7 +32,7 @@ class Minerun extends StatelessGame {
private final int afterFinishLine = 10;
public Minerun(int width, int length, int minePercentage) {
super(Dimension.THE_END.DIMENSION, "Minerun", new FirstWinsScore());
super(Dimension.THE_END.key, "Minerun", new FirstWinsScore());
setGenerator(new SquarePlateTerrainGenerator(width, length + preRun + afterFinishLine).setPlateHeight(50).setGenerateBorders(true));
this.width = width;
@ -87,7 +86,6 @@ class Minerun extends StatelessGame {
if(Intersect.withPressurePlate(this, BlockPallet.PRESSURE_PLATES, middle)) { //Player died
p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.PLAYER, 1f, 1f));
p.setPose(Entity.Pose.DYING);
p.teleport(new Pos(p.getPosition().x(), getSpawn().y(), getSpawn().z()));
}

View File

@ -22,7 +22,7 @@ public class MinerunFactory implements GameFactory {
return new ConfigManager()
.addOption(new NumericOption("width", Material.OAK_FENCE, TranslatedComponent.byId("optionCommon#width"), 10, 30, 50, 100))
.addOption(new NumericOption("length", Material.ZOMBIE_HEAD, TranslatedComponent.byId("optionCommon#length"), 50, 100, 150, 200))
.addOption(new NumericOption("percentage", Material.LIGHT_WEIGHTED_PRESSURE_PLATE, TranslatedComponent.byId("game_Minerun#optionPercentageMiens"), 30, 40, 50, 60, 70));
.addOption(new NumericOption("percentage", Material.LIGHT_WEIGHTED_PRESSURE_PLATE, TranslatedComponent.byId("game_Minerun#optionPercentageMines"), 30, 40, 50, 60, 70));
}
@Override

View File

@ -26,7 +26,7 @@ public class Spleef extends StatelessGame {
final int totalElevation = 50;
public Spleef(int radius, int stackCount) {
super(Dimension.OVERWORLD.DIMENSION, "Spleef", new LastWinsScore());
super(Dimension.OVERWORLD.key, "Spleef", new LastWinsScore());
getScore().setIgnoreLastPlayers(1);
this.radius = radius;
@ -61,13 +61,7 @@ public class Spleef extends StatelessGame {
player.getInventory().addItemStack(
ItemStack
.builder(Material.DIAMOND_SHOVEL)
.displayName(TranslatedComponent.byId("game_Spleef#shovelName").getAssembled(player))
.meta(
builder -> builder
.enchantment(Enchantment.EFFICIENCY, (short) 99)
.hideFlag(ItemHideFlag.HIDE_ENCHANTS)
.build()
)
.customName(TranslatedComponent.byId("game_Spleef#shovelName").getAssembled(player))
.build()
);
player.setHeldItemSlot((byte) 0);
@ -84,6 +78,7 @@ public class Spleef extends StatelessGame {
}
private void destroyBlock(PlayerStartDiggingEvent event) {
if(!isRunning) return;
setBlock(event.getBlockPosition(), Block.AIR);
}

View File

@ -33,7 +33,7 @@ public class SpleefFactory implements GameFactory {
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("game_Spleef#radius"), 10, 20, 30))
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 10, 20, 30))
.addOption(new NumericOption("stackCount", Material.SCAFFOLDING, TranslatedComponent.byId("game_Spleef#stackCount"), 1, 2, 3, 4, 5));
}

View File

@ -3,28 +3,32 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.stickfight;
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.BatchUtil;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import io.github.bloepiloepi.pvp.config.*;
import io.github.bloepiloepi.pvp.events.FinalAttackEvent;
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.Player;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
public class Stickfight extends StatelessGame {
private final double radius = 20;
private final WeakHashMap<Player, Pos> spawnPoints = new WeakHashMap<>();
public Stickfight() {
super(Dimension.OVERWORLD.DIMENSION, "Stickfight", new LastWinsScore());
super(Dimension.OVERWORLD.key, "Stickfight", new LastWinsScore());
eventNode().addChild(
PvPConfig.emptyBuilder()
.damage(DamageConfig.legacyBuilder().fallDamage(false))
.attack(AttackConfig.legacyBuilder().attackCooldown(true))
.build().createNode()
CombatFeatures.empty()
.add(CombatFeatures.VANILLA_ATTACK)
.add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build().createNode()
);
eventNode().addListener(FinalAttackEvent.class, finalAttackEvent -> {
@ -37,21 +41,56 @@ public class Stickfight extends StatelessGame {
@Override
protected void onLoad(@NotNull 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);
setBlock(0, 50, 0, Block.DIAMOND_BLOCK);
}
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
@Override
protected void start() {
List<Player> players = getPlayers().stream().toList();
int numPlayers = players.size();
for (int i = 0; i < numPlayers; i++) {
double angle = (2 * Math.PI / numPlayers) * i;
int spawnX = (int) (radius * Math.cos(angle));
int spawnZ = (int) (radius * Math.sin(angle));
int spawnY = 50;
Pos spawnpoint = new Pos(spawnX, spawnY + 1, spawnZ).add(0.5);
spawnPoints.put(players.get(i), spawnpoint.withLookAt(getSpawn()));
players.get(i).teleport(spawnpoint);
generateBridge(spawnX, spawnY, spawnZ);
}
setBlock(0, 50, 0, Block.GOLD_BLOCK);
super.start();
}
private void generateBridge(int startX, int startY, int startZ) {
int steps = (int) (radius * 1.5);
for (int i = 0; i < steps; i++) {
double t = (double) i / steps;
int x = (int) (startX * (1 - t));
int z = (int) (startZ * (1 - t));
setBlock(x, startY, z, Block.SANDSTONE);
}
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(isBeforeBeginning) playerMoveEvent.setCancelled(true);
if(!spawnPoints.containsKey(playerMoveEvent.getPlayer())) {
playerMoveEvent.setCancelled(true);
return;
}
if(isBeforeBeginning) {
if(spawnPoints.get(playerMoveEvent.getPlayer()).distance(playerMoveEvent.getNewPosition()) < 1) return;
playerMoveEvent.setCancelled(true);
playerMoveEvent.getPlayer().teleport(spawnPoints.get(playerMoveEvent.getPlayer()));
}
if(playerMoveEvent.getNewPosition().y() < 40) {
playerMoveEvent.getPlayer().teleport(new Pos(0, 51, 0));
playerMoveEvent.getPlayer().teleport(spawnPoints.get(playerMoveEvent.getPlayer()));
}
}

View File

@ -0,0 +1,160 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game.TetrisGame;
import eu.mhsl.minenet.minigames.instance.Dimension;
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.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.*;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
import java.util.*;
class Tetris extends StatelessGame {
private final Map<Player, TetrisGame> tetrisGames = new WeakHashMap<>();
private final int nextTetrominoesCount;
private final boolean isFast;
private final boolean hasCombat;
private boolean setTimeLimit = false;
private final long randomSeed;
public Tetris(int nextTetrominoesCount, boolean isFast, boolean hasCombat) {
super(Dimension.THE_END.key, "Tetris", new PointsWinScore());
this.eventNode()
.addListener(PlayerUseItemEvent.class, this::onPlayerInteract)
.addListener(PlayerHandAnimationEvent.class, this::onPlayerAttack)
.addListener(PlayerTickEvent.class, this::onPlayerTick);
this.nextTetrominoesCount = nextTetrominoesCount;
this.isFast = isFast;
this.hasCombat = hasCombat;
Random random = new Random();
this.randomSeed = random.nextLong();
}
@Override
protected void onStart() {
this.getEntities().stream()
.filter(entity -> entity.getEntityType().equals(Tetromino.getGhostEntityType()))
.forEach(Entity::remove);
if(this.hasCombat) {
this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values()));
}
this.tetrisGames.forEach((player, tetrisGame) -> tetrisGame.start());
}
@Override
protected void onStop() {
this.tetrisGames.forEach((player, tetrisGame) -> {
tetrisGame.loose();
this.getScore().insertResult(player, tetrisGame.getScore());
tetrisGame.sidebar.removeViewer(player);
});
}
@Override
protected void onPlayerLeave(Player p) {
this.tetrisGames.get(p).sidebar.removeViewer(p);
this.letPlayerLoose(p);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent event) {
Player player = event.getPlayer();
Pos currentPosition = event.getNewPosition();
TetrisGame tetrisGame = this.tetrisGames.get(player);
if(tetrisGame == null) {
event.setCancelled(true);
return;
}
if(tetrisGame.lost) return;
if(player.getGameMode() == GameMode.SPECTATOR) return;
if(player.inputs().forward()) tetrisGame.pressedButton(TetrisGame.Button.W);
if(player.inputs().backward()) tetrisGame.pressedButton(TetrisGame.Button.S);
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) {
TetrisGame tetrisGame = this.tetrisGames.get(player);
player.setGameMode(GameMode.SPECTATOR);
player.setInvisible(true);
this.getScore().insertResult(player, tetrisGame.getScore());
boolean allGamesLost = this.tetrisGames.values().stream()
.filter(game -> !game.lost)
.toList()
.isEmpty();
if(!this.setTimeLimit && !allGamesLost) {
this.setTimeLimit(90);
this.setTimeLimit = true;
}
}
@Override
protected boolean onPlayerJoin(Player p) {
p.getInventory().setItemStack(0, ItemStack.builder(Material.BIRCH_BUTTON).customName(Component.text("Controller")).build());
p.setSprinting(false);
if(this.tetrisGames.get(p) == null) {
this.tetrisGames.put(p, new TetrisGame(
this,
this.getSpawn().sub(6, 8, 15).add(this.tetrisGames.size()*30, 0, 0),
Tetromino.Shape.J,
this.nextTetrominoesCount,
this.isFast,
this.hasCombat,
this.randomSeed
));
this.tetrisGames.get(p).generate();
this.tetrisGames.values().forEach(tetrisGame -> tetrisGame.updateOtherTetrisGames(this.tetrisGames.values()));
}
TetrisGame tetrisGame = this.tetrisGames.get(p);
p.teleport(tetrisGame.getPlayerSpawnPosition());
tetrisGame.sidebar.addViewer(p);
return super.onPlayerJoin(p);
}
@Override
public Pos getSpawn() {
return new Pos(0, 30, 15).withView(180, 0);
}
}

View File

@ -0,0 +1,43 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris;
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.game.stateless.config.ConfigManager;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.common.BoolOption;
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 TetrisFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_Tetris#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_Tetris#description");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("nextTetrominoesCount", Material.LADDER, TranslatedComponent.byId("game_Tetris#nextTetrominoesCount"), 3, 4, 5, 1, 2))
.addOption(new BoolOption("isFast", Material.MINECART, TranslatedComponent.byId("game_Tetris#isFast")))
.addOption(new BoolOption("hasCombat", Material.DIAMOND_SWORD, TranslatedComponent.byId("game_Tetris#hasCombat")));
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) {
return new Tetris(configuration.get("nextTetrominoesCount").getAsInt(), configuration.get("isFast").getAsBoolean(), configuration.get("hasCombat").getAsBoolean()).setParent(parent);
}
@Override
public Material symbol() {
return Material.PURPLE_WOOL;
}
}

View File

@ -0,0 +1,191 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import org.apache.commons.lang3.ArrayUtils;
import java.util.Random;
public class Playfield {
private final Pos lowerLeftCorner;
private final StatelessGame instance;
private final static int height = 22;
private final static Block scoreBlock = Block.STONE;
private final int nextTetrominoesCount;
private final Random random;
public Playfield(Pos lowerLeftCorner, StatelessGame instance, int nextTetrominoesCount) {
this.nextTetrominoesCount = nextTetrominoesCount;
this.lowerLeftCorner = lowerLeftCorner;
this.instance = instance;
this.random = new Random();
}
public Pos getPlayerSpawnPosition() {
return this.lowerLeftCorner.add(6, 9, 20).withView(180, 0);
}
public Pos getTetrominoSpawnPosition() {
return this.lowerLeftCorner.add(5, 21, 1);
}
public Pos getHoldPosition() {
return this.lowerLeftCorner.add(-4, 18, 1);
}
public Pos getNextPosition() {
return this.lowerLeftCorner.add(15, 18, 1);
}
public Pos getScorePosition() {
return this.lowerLeftCorner.add(-5, height+3, 0);
}
public void generate() {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
// actual playfield:
for(int x=0; x<12; x++) {
for(int y = 0; y< height; y++) {
batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.GLASS);
batch.setBlock(this.lowerLeftCorner.add(x, y, -1), Block.BLACK_CONCRETE);
if(x==0 || x==11 || y==0) {
batch.setBlock(this.lowerLeftCorner.add(x, y, 1), Block.GRAY_CONCRETE);
batch.setBlock(this.lowerLeftCorner.add(x, y, 0), Block.GRAY_CONCRETE);
}
}
}
// hold position:
for(int x = 0; x < 4; x++) {
for(int y = 0; y < 4; y++) {
batch.setBlock(this.getHoldPosition().add(x-1, y-1, -1), Block.QUARTZ_BLOCK);
}
}
// next positions:
for(int x = 0; x < 4; x++) {
for(int y = -4*this.nextTetrominoesCount+4; y < 4; y++) {
batch.setBlock(this.getNextPosition().add(x-1, y-1, -1), Block.QUARTZ_BLOCK);
}
}
batch.setBlock(this.getPlayerSpawnPosition().sub(0, 1, 0), Block.STONE);
batch.setBlock(this.getPlayerSpawnPosition().sub(1, 1, 0), Block.STONE);
batch.setBlock(this.getPlayerSpawnPosition().sub(1, 1, 1), Block.STONE);
batch.setBlock(this.getPlayerSpawnPosition().sub(0, 1, 1), Block.STONE);
BatchUtil.loadAndApplyBatch(batch, this.instance, () -> {});
}
public int removeFullLines() {
int removedLinesCounter = 0;
for(int y = 1; y< height; y++) {
boolean isFullLine = true;
for(int x=1; x<11; x++) {
if(this.instance.getBlock(this.lowerLeftCorner.add(x, y, 1)) == Block.AIR) isFullLine = false;
}
if(isFullLine) {
this.removeFullLine(y);
removedLinesCounter += 1;
y -= 1;
}
}
return removedLinesCounter;
}
public void addLines(int lines) {
int xPosMissing = this.random.nextInt(1, 10);
for (int i = 0; i < lines; i++) {
this.moveAllLinesUp();
for (int x = 1; x < 11; x++) {
if(x != xPosMissing) {
this.instance.setBlock(this.lowerLeftCorner.add(x, 1, 1), Block.LIGHT_GRAY_CONCRETE);
} else {
this.instance.setBlock(this.lowerLeftCorner.add(x, 1, 1), Block.AIR);
}
}
}
}
public void updateAttackingLines(int attackingLines) {
for (int y = 0; y < height + 5; y++) {
if(attackingLines > 0) {
this.instance.setBlock(this.lowerLeftCorner.add(12, y, 1), Block.REDSTONE_BLOCK);
attackingLines -= 1;
} else {
this.instance.setBlock(this.lowerLeftCorner.add(12, y, 1), Block.AIR);
}
}
}
public void updateScore(int score) {
this.removeDigits();
String scoreString = String.valueOf(score);
char[] characters = scoreString.toCharArray();
ArrayUtils.reverse(characters);
for(int i = 6; i > 0; i--) {
char digit;
if(i <= characters.length) {
digit = characters[i-1];
} else {
digit = '0';
}
this.displayDigit(digit, 6-i);
}
}
private void displayDigit(char digit, int positionFromLeft) {
int[][] digitArray;
switch (digit) {
case '1' -> digitArray = new int[][]{{0,0,1},{0,1,1},{0,0,1},{0,0,1},{0,0,1}};
case '2' -> digitArray = new int[][]{{1,1,1},{0,0,1},{1,1,1},{1,0,0},{1,1,1}};
case '3' -> digitArray = new int[][]{{1,1,1},{0,0,1},{0,1,1},{0,0,1},{1,1,1}};
case '4' -> digitArray = new int[][]{{1,0,1},{1,0,1},{1,1,1},{0,0,1},{0,0,1}};
case '5' -> digitArray = new int[][]{{1,1,1},{1,0,0},{1,1,1},{0,0,1},{1,1,1}};
case '6' -> digitArray = new int[][]{{1,1,1},{1,0,0},{1,1,1},{1,0,1},{1,1,1}};
case '7' -> digitArray = new int[][]{{1,1,1},{0,0,1},{0,1,0},{0,1,0},{0,1,0}};
case '8' -> digitArray = new int[][]{{1,1,1},{1,0,1},{1,1,1},{1,0,1},{1,1,1}};
case '9' -> digitArray = new int[][]{{1,1,1},{1,0,1},{1,1,1},{0,0,1},{1,1,1}};
default -> digitArray = new int[][]{{1,1,1},{1,0,1},{1,0,1},{1,0,1},{1,1,1}};
}
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 5; y++) {
if(digitArray[4-y][x] == 1) this.instance.setBlock(this.getScorePosition().add(positionFromLeft*4+x, y, 0), scoreBlock);
}
}
}
private void removeDigits() {
for (int x = 0; x < 4 * 6; x++) {
for (int y = 0; y < 5; y++) {
this.instance.setBlock(this.getScorePosition().add(x, y, 0), Block.AIR);
}
}
}
private void moveAllLinesUp() {
for (int y = height + 3; y > 1; y--) {
for (int x = 1; x < 11; x++) {
Block blockBeneath = this.instance.getBlock(this.lowerLeftCorner.add(x, y - 1, 1));
this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), blockBeneath);
}
}
}
private void removeFullLine(int positionY) {
for(int y = positionY; y< height; y++) {
for(int x=1; x<11; x++) {
Block blockAbove = this.instance.getBlock(this.lowerLeftCorner.add(x, y+1, 1));
this.instance.setBlock(this.lowerLeftCorner.add(x, y, 1), blockAbove);
}
}
}
}

View File

@ -0,0 +1,318 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import net.kyori.adventure.text.Component;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.scoreboard.Sidebar;
import net.minestom.server.timer.Scheduler;
import net.minestom.server.timer.TaskSchedule;
import java.util.*;
public class TetrisGame {
private final StatelessGame instance;
private final Playfield playfield;
private final boolean isFast;
private int level = 1;
private int lines = 0;
private int score = 0;
private int combo = 0;
private int attackingLines = 0;
public boolean lost = false;
public boolean paused = true;
private final boolean hasCombat;
public Tetromino currentTetromino;
private final List<Tetromino> nextTetrominoes = new ArrayList<>();
private Tetromino holdTetromino;
private final List<Tetromino> tetrominoBag = new ArrayList<>();
private boolean holdPossible = true;
private final Pos nextPosition;
private final Pos holdPosition;
private final Pos tetrominoSpawnPosition;
public Sidebar sidebar = new Sidebar(Component.text("Info:"));
private final Map<Button, Long> lastPresses = new HashMap<>();
private final List<TetrisGame> otherTetrisGames = new ArrayList<>();
private final Random random;
public enum Button {
W,
A,
S,
D,
mouseLeft,
mouseRight,
space
}
public TetrisGame(StatelessGame instance, Pos lowerLeftCorner, Tetromino.Shape startTetrominoShape, int nextTetrominoesCount, boolean isfast, boolean hasCombat, long randomSeed) {
this.isFast = isfast;
this.hasCombat = hasCombat;
this.instance = instance;
this.playfield = new Playfield(lowerLeftCorner, this.instance, nextTetrominoesCount);
this.random = new Random(randomSeed);
this.holdPosition = this.playfield.getHoldPosition();
this.nextPosition = this.playfield.getNextPosition();
this.tetrominoSpawnPosition = this.playfield.getTetrominoSpawnPosition();
this.buildSidebar();
this.currentTetromino = new Tetromino(this.instance, startTetrominoShape);
for (int i = 0; i < nextTetrominoesCount; i++) {
this.updateNextTetrominoes();
}
}
public void pressedButton(Button button) {
final int standardButtonDelay = 100;
final int buttonDebounce = 70;
if(this.lastPresses.getOrDefault(button, 0L) >= System.currentTimeMillis()-standardButtonDelay) return;
this.lastPresses.put(button, System.currentTimeMillis());
if(button == Button.W) this.lastPresses.put(button, System.currentTimeMillis()+buttonDebounce);
if(button == Button.S) this.lastPresses.put(button, System.currentTimeMillis()-buttonDebounce);
if(this.lost || this.paused) return;
switch (button) {
case A -> this.currentTetromino.moveLeft();
case S -> this.moveDown();
case D -> this.currentTetromino.moveRight();
case W -> this.hardDrop();
case mouseLeft -> this.currentTetromino.rotate(false);
case mouseRight -> this.currentTetromino.rotate(true);
case space -> this.switchHold();
}
}
public Pos getPlayerSpawnPosition() {
return this.playfield.getPlayerSpawnPosition();
}
public void start() {
this.paused = false;
Scheduler scheduler = MinecraftServer.getSchedulerManager();
scheduler.submitTask(() -> {
if(this.lost) return TaskSchedule.stop();
int standardTickDelay = 40;
if(this.isFast) standardTickDelay = 20;
TaskSchedule nextTick = TaskSchedule.tick(Math.round((float) standardTickDelay /this.level));
if(this.paused) return nextTick;
this.tick();
return nextTick;
});
this.updateInfo();
this.nextTetrominoes.forEach(tetromino -> {
double xChange = -tetromino.getXChange();
tetromino.setPosition(this.nextPosition.sub(xChange, 4*this.nextTetrominoes.indexOf(tetromino), 0));
tetromino.drawAsEntities();
});
}
public void generate() {
this.playfield.generate();
this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
this.currentTetromino.draw(false);
}
public void tick() {
if(this.lost || this.paused) return;
if(!this.currentTetromino.moveDown()) {
this.setActiveTetrominoDown();
}
}
public int getScore() {
return this.score;
}
public void updateOtherTetrisGames(Collection<TetrisGame> tetrisGames) {
List<TetrisGame> games = new ArrayList<>(tetrisGames);
games.remove(this);
games.removeIf(tetrisGame -> tetrisGame.lost);
this.otherTetrisGames.clear();
this.otherTetrisGames.addAll(games);
}
public void getAttacked(int lines) {
if(this.hasCombat && !this.lost) {
this.attackingLines += lines;
this.playfield.updateAttackingLines(this.attackingLines);
}
}
public void loose() {
this.lost = true;
}
private boolean moveDown() {
if(!this.currentTetromino.moveDown()) {
this.setActiveTetrominoDown();
return false;
}
this.score += 1;
this.updateInfo();
return true;
}
private boolean hardDrop() {
if(!this.currentTetromino.moveDown()) {
this.setActiveTetrominoDown();
return false;
}
this.score += 2;
this.updateInfo();
while(this.currentTetromino.moveDown()) {
this.score += 2;
this.updateInfo();
}
this.setActiveTetrominoDown();
return true;
}
private boolean switchHold() {
if(!this.holdPossible) return false;
Tetromino newCurrentTetromino;
if(this.holdTetromino == null) {
newCurrentTetromino = this.nextTetrominoes.removeFirst();
newCurrentTetromino.remove();
this.updateNextTetrominoes();
} else {
newCurrentTetromino = this.holdTetromino;
this.holdTetromino.remove();
}
this.currentTetromino.remove();
this.holdTetromino = new Tetromino(this.instance, this.currentTetromino.getShape());
this.currentTetromino = newCurrentTetromino;
this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
this.currentTetromino.draw();
if(!this.currentTetromino.moveDown()) this.loose();
double xChange = this.holdTetromino.getXChange();
this.holdTetromino.setPosition(this.holdPosition.add(xChange, 0, 0));
this.holdTetromino.drawAsEntities();
this.holdPossible = false;
return true;
}
private void updateNextTetrominoes() {
if(this.tetrominoBag.isEmpty()) {
for(Tetromino.Shape shape : Tetromino.Shape.values()) {
this.tetrominoBag.add(new Tetromino(this.instance, shape));
}
Collections.shuffle(this.tetrominoBag, this.random);
}
if(!this.nextTetrominoes.isEmpty()) this.nextTetrominoes.forEach(Tetromino::remove);
Tetromino newTetromino = this.tetrominoBag.removeFirst();
this.nextTetrominoes.add(newTetromino);
this.nextTetrominoes.forEach(tetromino -> {
double xChange = -tetromino.getXChange();
tetromino.setPosition(this.nextPosition.sub(xChange, 4*this.nextTetrominoes.indexOf(tetromino), 0));
tetromino.drawAsEntities();
});
}
private void buildSidebar() {
this.sidebar.createLine(new Sidebar.ScoreboardLine(
"0",
Component.text("Score: "),
0
));
this.sidebar.createLine(new Sidebar.ScoreboardLine(
"1",
Component.text("Lines: "),
0
));
this.sidebar.createLine(new Sidebar.ScoreboardLine(
"2",
Component.text("Level: "),
1
));
}
private void updateInfo() {
this.playfield.updateScore(this.score);
this.sidebar.updateLineScore("0", this.score);
this.sidebar.updateLineScore("1", this.lines);
this.sidebar.updateLineScore("2", this.level);
}
private void setActiveTetrominoDown() {
this.currentTetromino.removeOwnEntities();
this.currentTetromino = this.nextTetrominoes.removeFirst();
this.currentTetromino.remove();
this.updateNextTetrominoes();
int removedLines = this.playfield.removeFullLines();
int combatLines = 0;
this.combo += 1;
switch (removedLines) {
case 0 -> this.combo = 0;
case 1 -> {
this.lines += 1;
this.score += 40 * this.level;
}
case 2 -> {
combatLines = 1;
this.lines += 2;
this.score += 100 * this.level;
}
case 3 -> {
combatLines = 2;
this.lines += 3;
this.score += 300 * this.level;
}
case 4 -> {
combatLines = 4;
this.lines += 4;
this.score += 1200 * this.level;
}
}
this.score += 50 * this.combo * this.level;
if(this.combo >= 2) {
combatLines += (int) Math.floor((double) this.combo /2);
}
if(this.hasCombat && this.attackingLines > 0) {
if(combatLines > 0 && this.attackingLines >= combatLines) {
this.attackingLines -= combatLines;
combatLines = 0;
} else if(combatLines > 0) {
combatLines -= this.attackingLines;
this.attackingLines = 0;
} else {
this.playfield.addLines(this.attackingLines);
this.attackingLines = 0;
}
this.playfield.updateAttackingLines(this.attackingLines);
}
if(this.hasCombat && !this.otherTetrisGames.isEmpty()) {
Collections.shuffle(this.otherTetrisGames);
this.otherTetrisGames.getFirst().getAttacked(combatLines);
}
this.level = (int) Math.floor((double) this.lines / 10) + 1;
this.holdPossible = true;
this.updateInfo();
this.currentTetromino.setPosition(this.tetrominoSpawnPosition);
this.currentTetromino.draw();
if(!this.currentTetromino.moveDown()) {
this.loose();
}
}
}

View File

@ -0,0 +1,246 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.tetris.game;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.metadata.other.FallingBlockMeta;
import net.minestom.server.instance.block.Block;
import net.minestom.server.tag.Tag;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
public class Tetromino {
private final Shape shape;
private final StatelessGame instance;
private Pos position;
private int[][] shapeArray;
private final static EntityType ghostEntityType = EntityType.FALLING_BLOCK;
private final UUID uuid;
private final static Tag<String> uuidTag = Tag.String("uuid");
public enum Shape {
I,
J,
L,
O,
S,
T,
Z
}
public Tetromino(StatelessGame instance, Shape shape) {
this.instance = instance;
this.shape = shape;
this.uuid = UUID.randomUUID();
switch (this.shape) {
case I -> this.shapeArray = new int[][]{{0, 0, 0, 0}, {1, 1, 1, 1}, {0, 0, 0, 0}, {0, 0, 0, 0}};
case J -> this.shapeArray = new int[][]{{1,0,0}, {1,1,1}, {0,0,0}};
case L -> this.shapeArray = new int[][]{{0,0,1}, {1,1,1}, {0,0,0}};
case O -> this.shapeArray = new int[][]{{1,1}, {1,1}};
case S -> this.shapeArray = new int[][]{{0,1,1}, {1,1,0}, {0,0,0}};
case T -> this.shapeArray = new int[][]{{0,1,0}, {1,1,1}, {0,0,0}};
case Z -> this.shapeArray = new int[][]{{1,1,0}, {0,1,1}, {0,0,0}};
}
}
public static EntityType getGhostEntityType() {
return ghostEntityType;
}
public void setPosition(Pos newPosition) {
this.position = newPosition;
}
public boolean rotate(boolean clockwise) {
int[][] newShapeArray = this.getTurnedShapeArray(clockwise);
return this.checkCollisionAndMove(this.position, newShapeArray);
}
public boolean moveDown() {
Pos newPosition = this.position.sub(0, 1, 0);
return this.checkCollisionAndMove(newPosition, this.shapeArray);
}
public boolean moveLeft() {
Pos newPosition = this.position.sub(1, 0, 0);
return this.checkCollisionAndMove(newPosition, this.shapeArray);
}
public boolean moveRight() {
Pos newPosition = this.position.add(1, 0, 0);
return this.checkCollisionAndMove(newPosition, this.shapeArray);
}
public void draw() {
this.draw(true);
}
public void draw(boolean withGhost) {
if(withGhost) {
Pos ghostPos = this.position;
while (!this.checkCollision(ghostPos.sub(0, 1, 0), this.shapeArray)) {
ghostPos = ghostPos.sub(0, 1, 0);
}
Pos positionChange = this.position.sub(ghostPos);
this.getBlockPositions().forEach(pos -> {
Entity ghostBlock = new Entity(ghostEntityType);
((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getGhostBlock());
ghostBlock.setNoGravity(true);
ghostBlock.setGlowing(true);
ghostBlock.setTag(uuidTag, this.uuid.toString());
ghostBlock.setInstance(this.instance, pos.sub(positionChange).add(0.5, 0, 0.5));
});
}
this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, this.getColoredBlock()));
}
public void drawAsEntities() {
this.getBlockPositions().forEach(pos -> {
Entity ghostBlock = new Entity(ghostEntityType);
((FallingBlockMeta) ghostBlock.getEntityMeta()).setBlock(this.getColoredBlock());
ghostBlock.setNoGravity(true);
ghostBlock.setTag(uuidTag, this.uuid.toString());
ghostBlock.setInstance(this.instance, pos.add(0.5, 0, 0.5));
});
}
public void remove() {
this.removeOwnEntities();
this.getBlockPositions().forEach(pos -> this.instance.setBlock(pos, Block.AIR));
}
public Block getColoredBlock() {
Block returnBlock;
switch (this.shape) {
case I -> returnBlock = Block.LIGHT_BLUE_CONCRETE;
case J -> returnBlock = Block.BLUE_CONCRETE;
case L -> returnBlock = Block.ORANGE_CONCRETE;
case O -> returnBlock = Block.YELLOW_CONCRETE;
case S -> returnBlock = Block.GREEN_CONCRETE;
case T -> returnBlock = Block.PURPLE_CONCRETE;
case Z -> returnBlock = Block.RED_CONCRETE;
default -> returnBlock = Block.WHITE_CONCRETE;
}
return returnBlock;
}
public void removeOwnEntities() {
this.instance.getEntities().stream()
.filter(entity -> {
String tagValue = entity.getTag(uuidTag);
if(tagValue == null) return false;
return entity.getTag(uuidTag).equals(this.uuid.toString());
})
.forEach(Entity::remove);
}
public double getXChange() {
switch (this.shape) {
case O, I -> {
return 0;
}
case null, default -> {
return 0.5;
}
}
}
public Shape getShape() {
return this.shape;
}
private Block getGhostBlock() {
Block returnBlock;
switch (this.shape) {
case I -> returnBlock = Block.LIGHT_BLUE_STAINED_GLASS;
case J -> returnBlock = Block.BLUE_STAINED_GLASS;
case L -> returnBlock = Block.ORANGE_STAINED_GLASS;
case O -> returnBlock = Block.YELLOW_STAINED_GLASS;
case S -> returnBlock = Block.GREEN_STAINED_GLASS;
case T -> returnBlock = Block.PURPLE_STAINED_GLASS;
case Z -> returnBlock = Block.RED_STAINED_GLASS;
default -> returnBlock = Block.WHITE_STAINED_GLASS;
}
return returnBlock;
}
private int[][] getTurnedShapeArray(boolean clockwise) {
int iterations = 1;
if(!clockwise) iterations = 3;
int arrayLength = this.shapeArray.length;
int[][] startArray = Arrays.stream(this.shapeArray).map(int[]::clone).toArray(int[][]::new);
int[][] returnArray = new int[arrayLength][arrayLength];
for(int k=0; k<iterations; k++) {
for(int i=0; i<arrayLength; i++) {
for(int j=0; j<arrayLength; j++) {
returnArray[i][arrayLength-1-j] = startArray[j][i];
}
}
startArray = Arrays.stream(returnArray).map(int[]::clone).toArray(int[][]::new);
}
return returnArray;
}
private boolean isPartOfTetromino(Pos position) {
return this.getBlockPositions().stream()
.anyMatch(pos -> pos.equals(position));
}
private List<Pos> getBlockPositions() {
return this.getBlockPositions(this.position, this.shapeArray);
}
private List<Pos> getBlockPositions(Pos position, int[][] shapeArray) {
List<Pos> returnList = new ArrayList<>();
if(position == null) return returnList;
int arrayLength = shapeArray.length;
for(int x=0; x<arrayLength; x++) {
for(int y=0; y<arrayLength; y++) {
if(shapeArray[arrayLength-1-y][x] == 1) {
switch (this.shape) {
case I -> returnList.add(position.add(x-1, y-2, 0));
case O -> returnList.add(position.add(x, y, 0));
default -> returnList.add(position.add(x-1, y-1, 0));
}
}
}
}
return returnList;
}
private boolean checkCollision(Pos newPosition, int[][] newShapeArray) {
List<Pos> newBlockPositions = this.getBlockPositions(newPosition, newShapeArray);
for(Pos pos : newBlockPositions) {
if(this.isPartOfTetromino(pos)) continue;
if(this.instance.getBlock(pos) == this.getGhostBlock()) continue;
if(this.instance.getBlock(pos) != Block.AIR) return true;
}
return false;
}
private boolean checkCollisionAndMove(Pos newPosition, int[][] newShapeArray) {
if(!this.checkCollision(newPosition, newShapeArray)) {
this.remove();
this.shapeArray = Arrays.stream(newShapeArray).map(int[]::clone).toArray(int[][]::new);
this.setPosition(newPosition);
this.draw();
return true;
}
return false;
}
}

View File

@ -7,10 +7,7 @@ import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
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.metadata.other.PrimedTntMeta;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
@ -27,7 +24,7 @@ public class TntRun extends StatelessGame {
final int radius;
final int stackCount;
public TntRun(int radius, int stackCount) {
super(Dimension.OVERWORLD.DIMENSION, "tntRun", new LastWinsScore());
super(Dimension.OVERWORLD.key, "tntRun", new LastWinsScore());
this.radius = radius;
this.stackCount = stackCount;
setGenerator(new CircularPlateTerrainGenerator(radius));
@ -51,7 +48,13 @@ public class TntRun extends StatelessGame {
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(playerMoveEvent.getNewPosition().y() < totalElevation) {
if(isBeforeBeginning) {
playerMoveEvent.getPlayer().teleport(getSpawn());
return;
}
playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
getScore().insertResult(playerMoveEvent.getPlayer());
}
@ -67,14 +70,14 @@ public class TntRun extends StatelessGame {
setBlock(firstLocation, Block.AIR);
setBlock(secondLocation, Block.AIR);
Entity fallingTnt = new Entity(EntityType.TNT);
PrimedTntMeta fallingTntMeta = (PrimedTntMeta) fallingTnt.getEntityMeta();
fallingTntMeta.setFuseTime(20);
fallingTnt.setInstance(this, secondLocation);
// Entity fallingTnt = new Entity(EntityType.TNT);
// PrimedTntMeta fallingTntMeta = (PrimedTntMeta) fallingTnt.getEntityMeta();
// fallingTntMeta.setFuseTime(20);
// fallingTnt.setInstance(this, secondLocation);
}
}
}
}, TaskSchedule.millis(500), TaskSchedule.stop(), ExecutionType.ASYNC);
}, TaskSchedule.millis(500), TaskSchedule.stop(), ExecutionType.TICK_END);
}
}

View File

@ -14,7 +14,12 @@ import java.util.Map;
public class TntRunFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_tntRun#name");
return TranslatedComponent.byId("game_TntRun#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_TntRun#description");
}
@Override
@ -25,8 +30,8 @@ public class TntRunFactory implements GameFactory {
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("radius", Material.STICK, TranslatedComponent.byId("game_tntRun#radius"), 20, 30, 50, 60))
.addOption(new NumericOption("levels", Material.SCAFFOLDING, TranslatedComponent.byId("game_tntRun#levels"), 1, 2, 3, 4, 5));
.addOption(new NumericOption("radius", Material.STICK, TranslatedComponent.byId("optionCommon#radius"), 20, 30, 50, 60))
.addOption(new NumericOption("levels", Material.SCAFFOLDING, TranslatedComponent.byId("game_TntRun#levels"), 1, 2, 3, 4, 5));
}
@Override

View File

@ -3,23 +3,74 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.generator.MazeGenerator;
import eu.mhsl.minenet.minigames.score.NoScore;
import eu.mhsl.minenet.minigames.score.LastWinsScore;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.Player;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Towerdefense extends StatelessGame {
private final Random random = new Random();
private final AbsoluteBlockBatch mazeBatch = new AbsoluteBlockBatch();
private final List<Pos> mazePath = new ArrayList<>();
private List<TowerdefenseRoom> instances = new ArrayList<>();
public Towerdefense() {
super(Dimension.NETHER.DIMENSION, "Towerdefense", new NoScore());
super(Dimension.NETHER.key, "Towerdefense", new LastWinsScore());
setGenerator(new MazeGenerator());
this.generateMaze();
}
private void generateMaze() {
Pos position = new Pos(0, 0, 0);
this.addMazePosition(position, Block.GREEN_WOOL);
List<Integer> previousDirections = new ArrayList<>();
int direction = 1; // 0 -> right; 1 -> straight; 2 -> left
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 3; j++) {
position = position.add(direction-1,0,direction%2);
this.addMazePosition(position, Block.WHITE_WOOL);
}
int origin = 0;
int bound = 3;
long rightLeftDifference = previousDirections.stream().filter(integer -> integer == 0).count() - previousDirections.stream().filter(integer -> integer == 2).count();
if(rightLeftDifference >= 2 || direction == 2) origin = 1;
if(rightLeftDifference <= -2 || direction == 0) bound = 2;
direction = this.random.nextInt(origin, bound);
previousDirections.add(direction);
}
this.addMazePosition(position, Block.WHITE_WOOL);
this.addMazePosition(position.add(0,0,1), Block.WHITE_WOOL);
this.addMazePosition(position.add(0,0,2), Block.RED_WOOL);
}
private void addMazePosition(Pos position, Block pathBlock) {
this.mazeBatch.setBlock(position, pathBlock);
this.mazePath.add(position.add(0.5,1,0.5));
}
public AbsoluteBlockBatch getMazeBatch() {
return this.mazeBatch;
}
public List<Pos> getMazePath() {
return this.mazePath;
}
@Override
protected boolean onPlayerJoin(Player p) {
p.getInventory().setItemStack(1, ItemStack.of(Material.ARMOR_STAND));
TowerdefenseRoom newRoom = new TowerdefenseRoom(p, this);
this.instances.add(newRoom);
p.setInstance(newRoom);
newRoom.startWave(List.of(EntityType.ENDERMAN, EntityType.BLAZE, EntityType.PLAYER, EntityType.HORSE, EntityType.ARMOR_STAND, EntityType.SKELETON));
return false;
}
}

View File

@ -0,0 +1,58 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.generator.MazeGenerator;
import eu.mhsl.minenet.minigames.util.BatchUtil;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.*;
import net.minestom.server.entity.attribute.Attribute;
import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.timer.TaskSchedule;
import java.util.List;
import java.util.UUID;
public class TowerdefenseRoom extends InstanceContainer {
private final Player player;
private final Towerdefense game;
public TowerdefenseRoom(Player player, Towerdefense game) {
super(UUID.randomUUID(), Dimension.OVERWORLD.key);
MinecraftServer.getInstanceManager().registerInstance(this);
this.player = player;
this.game = game;
this.player.setGameMode(GameMode.ADVENTURE);
this.player.setAllowFlying(true);
this.player.getInventory().setItemStack(0, ItemStack.of(Material.ARMOR_STAND));
setGenerator(new MazeGenerator());
BatchUtil.loadAndApplyBatch(this.game.getMazeBatch(), this, () -> {});
}
public void startWave(List<EntityType> entities) {
int counter = 0;
for(EntityType entityType : entities) {
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
this.addEntity(new EntityCreature(entityType));
return TaskSchedule.stop();
}, TaskSchedule.millis(800L*counter));
counter++;
}
}
private void addEntity(EntityCreature entity) {
entity.setInstance(this, this.game.getMazePath().getFirst());
entity.getAttribute(Attribute.MOVEMENT_SPEED).setBaseValue(0.15);
entity.getNavigator().setPathTo(this.game.getMazePath().get(1), 0.7, () -> changeEntityGoal(entity, 1));
}
private void changeEntityGoal(EntityCreature entity, int positionIndex) {
if(positionIndex == this.game.getMazePath().size()-1) {
return;
}
entity.getNavigator().setPathTo(this.game.getMazePath().get(positionIndex+1), 0.7, () -> changeEntityGoal(entity, positionIndex+1));
}
}

View File

@ -37,7 +37,7 @@ class TrafficLightRace extends StatelessGame {
private final List<Pos> trafficLights = new ArrayList<>();
public TrafficLightRace(int width, int length) {
super(Dimension.THE_END.DIMENSION, "Ampelrennen", new FirstWinsScore());
super(Dimension.THE_END.key, "Ampelrennen", new FirstWinsScore());
this.width = width;
this.length = length;
@ -150,7 +150,7 @@ class TrafficLightRace extends StatelessGame {
BatchUtil.loadAndApplyBatch(changeLightsBatch, this, () -> {});
return phase.taskScheduleRandomDuration();
}, ExecutionType.SYNC);
}, ExecutionType.TICK_END);
}
@Override

View File

@ -17,6 +17,11 @@ public class TrafficLightRaceFactory implements GameFactory {
return TranslatedComponent.byId("game_TrafficlightRace#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_TrafficlightRace#description");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()

View File

@ -9,7 +9,7 @@ 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.anvil.AnvilLoader;
import java.nio.file.Path;
@ -30,7 +30,7 @@ public class Hub extends MineNetInstance implements Spawnable {
}
private Hub() {
super(Dimension.THE_END.DIMENSION);
super(Dimension.THE_END.key);
setChunkLoader(new AnvilLoader(Path.of("maps/hub")));
setTime(18000);

View File

@ -5,7 +5,6 @@ import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
import net.minestom.server.entity.Player;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.ItemHideFlag;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
@ -16,9 +15,8 @@ public class HubInventory extends InteractableInventory {
setClickableItem(
ItemStack
.builder(Material.WRITABLE_BOOK)
.displayName(TranslatedComponent.assemble("hub#create", p))
.customName(TranslatedComponent.assemble("hub#create", p))
.lore(TranslatedComponent.assemble("hub#create_description", p))
.meta(metaBuilder -> metaBuilder.hideFlag(ItemHideFlag.HIDE_ATTRIBUTES))
.build(),
12,
itemClick -> Room.createRoom(itemClick.getPlayer()),
@ -28,7 +26,7 @@ public class HubInventory extends InteractableInventory {
setClickableItem(
ItemStack
.builder(Material.KNOWLEDGE_BOOK)
.displayName(TranslatedComponent.assemble("hub#join", p))
.customName(TranslatedComponent.assemble("hub#join", p))
.lore(TranslatedComponent.assemble("hub#join_description", p))
.build(),
14,

View File

@ -29,7 +29,7 @@ public class JoinInventory extends InteractableInventory {
setClickableItem(
ItemStack.builder(Material.GREEN_STAINED_GLASS_PANE)
.displayName(Component.text(prefix))
.customName(Component.text(prefix))
.build(),
0,
itemClick -> {}
@ -51,7 +51,7 @@ public class JoinInventory extends InteractableInventory {
typedText = formatInput(typedText);
Optional<Room> target = Room.getRoom(MinecraftServer.getConnectionManager().findPlayer(typedText));
Optional<Room> target = Room.getRoom(MinecraftServer.getConnectionManager().findOnlinePlayer(typedText));
if(target.isPresent())
Room.setRoom(player, target.get());
else

View File

@ -17,7 +17,7 @@ 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.PlayerDisconnectEvent;
import net.minestom.server.instance.AnvilLoader;
import net.minestom.server.instance.anvil.AnvilLoader;
import java.util.*;
import java.util.logging.Logger;
@ -41,7 +41,7 @@ public class Room extends MineNetInstance implements Spawnable {
}
public static void deleteRoom(Room room) {
logger.info("Deleting room " + room.uniqueId);
logger.info("Deleting room " + room.uuid);
rooms.remove(room);
players.values().removeAll(Collections.singleton(room));
room.getAllMembers().forEach(player -> MoveInstance.move(player, Hub.INSTANCE));
@ -65,6 +65,7 @@ public class Room extends MineNetInstance implements Spawnable {
p.clearTitle();
p.getInventory().clear();
p.setGameMode(GameMode.ADVENTURE);
p.setInvisible(false);
rooms.add(room);
players.put(p, room);
MoveInstance.move(p, room);
@ -85,14 +86,14 @@ public class Room extends MineNetInstance implements Spawnable {
private GameSelector gameSelector;
private final Tournament tournament = new Tournament();
private Room(Player owner) {
super(Dimension.THE_END.DIMENSION);
super(Dimension.THE_END.key);
this.apiDriven = false;
construct();
setOwner(owner);
}
protected Room() {
super(Dimension.THE_END.DIMENSION);
super(Dimension.THE_END.key);
this.apiDriven = true;
construct();
}

View File

@ -10,7 +10,6 @@ import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
import eu.mhsl.minenet.minigames.util.InventoryItemAlignment;
import net.minestom.server.entity.Player;
import net.minestom.server.inventory.InventoryType;
import net.minestom.server.item.ItemHideFlag;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
@ -29,7 +28,7 @@ public class MinigameSelectInventory extends InteractableInventory {
for (GameType type : GameType.values()) {
setClickableItem(
ItemStack.builder(type.getIcon())
.displayName(type.getTitle().getAssembled(p))
.customName(type.getTitle().getAssembled(p))
.lore(type.getDescription().addWrap().getWrappedAssembled(p))
.build(),
itemAlignment.next().get(),
@ -58,9 +57,8 @@ public class MinigameSelectInventory extends InteractableInventory {
setClickableItem(
ItemStack.builder(gameFactory.symbol())
.displayName(gameFactory.name().getAssembled(p))
.customName(gameFactory.name().getAssembled(p))
.lore(gameFactory.description().addWrap().getWrappedAssembled(p))
.meta(metaBuilder -> metaBuilder.hideFlag(ItemHideFlag.HIDE_ATTRIBUTES))
.build(),
offset + itemAlignment.next().get(),
itemClick -> itemClick.getPlayer().openInventory(new GameConfigurationInventory(room, itemClick.getPlayer(), gameFactory))

View File

@ -10,7 +10,7 @@ import net.minestom.server.instance.block.Block;
public class Transfer extends MineNetInstance implements Spawnable {
public Transfer() {
super(Dimension.THE_END.DIMENSION);
super(Dimension.THE_END.key);
eventNode().addListener(PlayerMoveEvent.class, CommonEventHandles::cancel);
setBlock(0, 0, 0, Block.BARRIER);
}
@ -19,4 +19,4 @@ public class Transfer extends MineNetInstance implements Spawnable {
public Pos getSpawn() {
return new Pos(0.5, 1, 0.5);
}
}
}

View File

@ -28,10 +28,10 @@ public class Languages {
}
public Lang getLanguage(Player p) {
return getLanguage(p.getSettings().getLocale());
return getLanguage(p.getSettings().locale().toString()); // TODO funktioniert die locale noch?
}
public Lang getLanguage(String mapId) {
return languages.computeIfAbsent(mapId, unused -> languages.computeIfAbsent(defaultLanguage, (key) -> new DummyLang()));
return languages.computeIfAbsent(mapId.toLowerCase(), unused -> languages.computeIfAbsent(defaultLanguage, (key) -> new DummyLang()));
}
private void readAll() {

View File

@ -10,7 +10,7 @@ import java.util.Set;
public class LastWinsScore extends Score {
@Override
public void insertResultImplementation(Set<Player> p) {
getScores().add(0, p);
getScores().addFirst(p);
}
@Override

View File

@ -0,0 +1,65 @@
package eu.mhsl.minenet.minigames.score;
import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.TranslatableMessage;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.message.type.TitleMessage;
import eu.mhsl.minenet.minigames.util.MapUtil;
import net.minestom.server.entity.Player;
import java.time.Duration;
import java.util.*;
import java.util.stream.Collectors;
public class PointsWinScore extends Score {
private Map<Set<Player>, Integer> scoreOrder = new HashMap<>();
@Override
protected void insertResultImplementation(Set<Player> p, int currentPoints) {
this.scoreOrder.put(p, currentPoints);
this.scoreOrder = MapUtil.sortByValue(this.scoreOrder);
getScores().clear();
this.scoreOrder.forEach((player, integer) -> getScores().addFirst(player));
}
@Override
protected void insertResultImplementation(Set<Player> p) {
this.insertResultImplementation(p, 0);
}
@Override
public void setDone() {
if(isClosed()) return;
close();
new ChatMessage(Icon.STAR, true)
.appendTranslated("score#result")
.newLine()
.indent()
.numberedList(
getScores()
.stream()
.filter(players -> !players.stream()
.filter(player -> !player.getUsername().isBlank())
.toList()
.isEmpty())
.map(players -> players
.stream()
.filter(player -> scoreOrder.get(Set.of(player)) != null)
.map(player -> player.getUsername()+" : "+scoreOrder.get(Set.of(player)).toString())
.collect(Collectors.joining(", "))
)
.toList()
)
.undent()
.newLine()
.appendTranslated("score#thanks")
.send(instance.getPlayers());
instance.stop();
}
@Override
protected TranslatableMessage scoreMessage() {
return new TitleMessage(Duration.ofMillis(1000), Duration.ofSeconds(1)).appendTranslated("score#death");
}
}

View File

@ -8,6 +8,7 @@ import net.minestom.server.entity.Player;
import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
import net.minestom.server.event.player.PlayerDisconnectEvent;
import org.apache.commons.lang3.NotImplementedException;
import java.util.ArrayList;
import java.util.List;
@ -22,10 +23,19 @@ public abstract class Score {
public Score() {}
public Score(int ignoreLastPlayers) {
this.ignoreLastPlayers = ignoreLastPlayers;
protected abstract void insertResultImplementation(Set<Player> p);
protected void insertResultImplementation(Set<Player> p, int points) {
throw new NotImplementedException("This Score type is not able to process points");
}
public void insertResult(Player p) {
this.insertResultProcessor(p, () -> this.insertResultImplementation(Set.of(p)));
}
public void insertResult(Player p, int points) {
this.insertResultProcessor(p, () -> this.insertResultImplementation(Set.of(p), points));
}
public void attachListeners() {
this.instance.eventNode()
@ -45,15 +55,8 @@ public abstract class Score {
setDone();
}
}
protected abstract void insertResultImplementation(Set<Player> p);
protected abstract TranslatableMessage scoreMessage();
public void insertResult(Player p) {
if(hasResult(p)) return;
this.scoreMessage().send(p);
this.insertResultImplementation(Set.of(p));
this.checkGameEnd();
}
protected abstract TranslatableMessage scoreMessage();
public void insertRemainingPlayers(Set<Player> players) {
this.insertResultImplementation(players.stream().filter(p -> !hasResult(p)).collect(Collectors.toSet()));
@ -93,10 +96,19 @@ public abstract class Score {
instance.stop();
}
private void insertResultProcessor(Player p, Runnable callback) {
if(hasResult(p)) return;
this.scoreMessage().send(p);
callback.run();
this.checkGameEnd();
}
public boolean isClosed() {
return isClosed;
}
public void close() { isClosed = true; }
protected void onGameEnd() {
this.instance.stop();
}

View File

@ -10,7 +10,7 @@ import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.*;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.AnvilLoader;
import net.minestom.server.instance.anvil.AnvilLoader;
import java.util.List;
@ -19,17 +19,19 @@ public class TournamentDisplay extends MineNetInstance implements Spawnable {
private final Tournament tournament;
private final Pos[] placePositions = new Pos[] {
new Pos(8.5, -57, 21.5, 180, 0),
new Pos(9.5, -58, 21.5, 180, 0),
new Pos(7.5, -59, 21.5, 180, 0)
new Pos(8.5, -56, 22.5, 180, 0),
new Pos(12.5, -57, 20.5, 180, 0),
new Pos(4.5, -58, 20.5, 180, 0)
};
public TournamentDisplay(Tournament tournament) {
super(Dimension.OVERWORLD.DIMENSION);
super(Dimension.OVERWORLD.key);
setChunkLoader(new AnvilLoader(Resource.RESULT_DISPLAY.getPath()));
this.places = tournament.getPlaces();
this.tournament = tournament;
this.places.forEach(player -> player.setGameMode(GameMode.ADVENTURE));
eventNode().addListener(PlayerMoveEvent.class, playerMoveEvent -> {
if(isOnDisplay(playerMoveEvent.getPlayer()) && !playerMoveEvent.getNewPosition().sameBlock(placePositions[getRankPosition(playerMoveEvent.getPlayer())])) {
playerMoveEvent.setCancelled(true);
@ -62,6 +64,6 @@ public class TournamentDisplay extends MineNetInstance implements Spawnable {
@Override
public Pos getSpawn() {
return new Pos(8.5, -55, 8.5);
return new Pos(8.5, -59, 11.5);
}
}

View File

@ -1,30 +0,0 @@
package eu.mhsl.minenet.minigames.server.provider;
import eu.mhsl.minenet.minigames.util.UuidUtil;
import net.minestom.server.MinecraftServer;
import net.minestom.server.network.UuidProvider;
import net.minestom.server.network.player.PlayerConnection;
import net.minestom.server.utils.mojang.MojangUtils;
import java.util.UUID;
import java.util.logging.Logger;
public class ByPlayerNameUuidProvider implements UuidProvider {
@Override
public UUID provide(PlayerConnection playerConnection, String username) {
try {
if(MinecraftServer.getConnectionManager().getPlayer(username) != null) throw new IllegalStateException();
String client = MojangUtils.fromUsername(username).get("id").getAsString();
return UuidUtil.unTrimm(client);
} catch (NullPointerException e) {
Logger.getGlobal().info("Player " + username + " is unknown by Mojang! (Using random UUID)");
} catch (IllegalStateException e) {
Logger.getGlobal().info("Player with the username " + username + " is already online.");
playerConnection.disconnect();
}
return UUID.randomUUID();
}
}

View File

@ -28,10 +28,6 @@ public class InteractableEntity extends EntityCreature {
.addListener(PlayerEntityInteractEvent.class, this::onInteract) //TODO Why are some of these listeners not working?
.addListener(EntityAttackEvent.class, this::onAttack);
System.out.println(eventNode().getChildren());
System.out.println(eventNode().getParent().getChildren());
}
private void setInstanceEvent(@NotNull AddEntityToInstanceEvent addEntityToInstanceEvent) {

View File

@ -60,7 +60,7 @@ public class InteractableInventory extends Inventory {
protected void setDummyItem(Material material, int slot) {
this.setDummyItem(
ItemStack.builder(material).displayName(Component.text("")).build(),
ItemStack.builder(material).customName(Component.text("")).build(),
slot
);
}

View File

@ -3,7 +3,6 @@ package eu.mhsl.minenet.minigames.skin;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.TaskSchedule;
import java.util.HashMap;
@ -12,19 +11,15 @@ import java.util.Map;
public class SkinCache {
private static final Map<String, PlayerSkin> skins = new HashMap<>();
public static PlayerSkin getSkin(Player p) {
return SkinCache.getSkin(p.getUsername());
}
public static PlayerSkin getSkin(String p) {
if(!skins.containsKey(p)) skins.put(p, PlayerSkin.fromUsername(p));
return skins.get(p);
}
public static void applySkin(Player p) {
MinecraftServer.getSchedulerManager().submitTask(() -> {
MinecraftServer.getSchedulerManager().scheduleTask(() -> {
p.setSkin(SkinCache.getSkin(p.getUsername()));
return TaskSchedule.stop();
}, ExecutionType.ASYNC);
}, TaskSchedule.millis(500));
}
}

View File

@ -130,25 +130,10 @@ public class InventoryItemAlignment {
}.get(count);
}
public static class ItemOffset {
private final int x;
private final int z;
public ItemOffset(int x, int z) {
this.x = x;
this.z = z;
}
public int getX() {
return x;
}
public int getZ() {
return z;
}
public record ItemOffset(int x, int z) {
public int get() {
return x + (z * 9);
return x + (z * 9);
}
}
}
}

View File

@ -0,0 +1,20 @@
package eu.mhsl.minenet.minigames.util;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new ArrayList<>(map.entrySet());
list.sort(Map.Entry.comparingByValue());
Map<K, V> result = new LinkedHashMap<>();
for (Map.Entry<K, V> entry : list) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
}

View File

@ -1,40 +0,0 @@
package eu.mhsl.minenet.minigames.util;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin;
import net.minestom.server.network.packet.server.play.PlayerInfoUpdatePacket;
import net.minestom.server.network.packet.server.play.SpawnPlayerPacket;
import java.util.List;
public class PacketUtil {
public static void resendPlayerList(Player p) {
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(player -> {
if(player.getUuid().equals(p.getUuid())) return;
final PlayerSkin skin = player.getSkin();
List<PlayerInfoUpdatePacket.Property> properties =
skin != null ? List.of(new PlayerInfoUpdatePacket.Property("textures", skin.textures(), skin.signature())) : List.of();
p.sendPacket(
new PlayerInfoUpdatePacket(PlayerInfoUpdatePacket.Action.ADD_PLAYER,
new PlayerInfoUpdatePacket.Entry(
player.getUuid(),
player.getUsername(),
properties,
true,
0,
GameMode.SURVIVAL,
null,
null
)
)
);
p.sendPacket(
new SpawnPlayerPacket(player.getEntityId(), player.getUuid(), player.getPosition())
);
});
}
}

View File

@ -3,7 +3,7 @@ package eu.mhsl.minenet.minigames.util;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.PluginMessagePacket;
import net.minestom.server.network.packet.server.common.PluginMessagePacket;
public class PluginMessageUtil {
private static final String bungeeTargetSelector = "bungeecord:main";

View File

@ -1,5 +0,0 @@
package eu.mhsl.minenet.minigames.util;
public abstract class Static {
public abstract void load(); //TODO REMOVE
}

View File

@ -24,6 +24,6 @@ public class WeatherUtils {
} else {
return TaskSchedule.stop();
}
}, ExecutionType.ASYNC);
}, ExecutionType.TICK_END);
}
}

View File

@ -53,7 +53,7 @@ public class CircularPlateTerrainGenerator extends PlateTerrainGenerator {
double distance = bottom.distance(new Pos(0, 0, 0));
if(distance <= this.size && generatePlate()) {
unit.modifier().fill(bottom, bottom.add(1, 50, 1), platePallet.rnd());
unit.modifier().fill(bottom, bottom.add(1, plateHeight, 1), platePallet.rnd());
continue;
}

View File

@ -67,7 +67,7 @@ public class SquarePlateTerrainGenerator extends PlateTerrainGenerator {
}
if(generateBorders) {
Runnable generateBorder = () -> unit.modifier().fill(bottom, bottom.add(1, DimensionType.OVERWORLD.getMaxY(), 1), Block.BARRIER);
Runnable generateBorder = () -> unit.modifier().fill(bottom, bottom.add(1, DimensionType.VANILLA_MAX_Y, 1), Block.BARRIER);
if(bottom.z() <= length+1 && bottom.z() >= -1 && bottom.x() >= -1 && bottom.x() <= width+1) {
if(bottom.x() == -1 || bottom.x() == width+1) {

View File

@ -17,4 +17,5 @@ api:
port: 8080
admins:
- minetec
- minetec
- 28Pupsi28

View File

@ -23,7 +23,11 @@ other_description;Games which does not fit into other Categories;Spiele welche n
pvp;Player vs Player;Spieler gegen Spieler
pvp_description;Fight against other Players;Kämpfe gegen andere Spieler
pve;Player vs Enviroment;Spieler gegen Umwelt
pve_description;Surivie the world or fight entities;Überlebe die Welt oder kämpfe gegen Mobs
pve_description;Survive the world or fight entities;Überlebe die Welt oder kämpfe gegen Mobs
jumpnrun;jump and run;jump and run
jumpnrun_description;Proof your jump-and-run skills;Stelle deine jump-and-run Fähigkeiten unter Beweis
prototype;Prototype;Prototyp
prototype_description;Prototype games;Prototyp Spiele
;;
ns:hub#;;
invTitle;MineNet Servernetwork;MineNet Servernetzwerk
@ -36,7 +40,7 @@ join_notFound;Lobby not found: ;Lobby konnte nicht gefunden werden:
;;
ns:score#;;
result;Results;Ergebnisse
thanks;Thank you for Playing;Danke für's spielen
thanks;Thank you for Playing;Danke für's Spielen
finish;You did it;Du hast es geschafft
death;You are out;Du hast verloren
done;Finish;Fertig
@ -55,6 +59,7 @@ width;Width;Breite
length;Length;Länge
height;Height;Höhe
radius;Radius;Radius
seconds;Seconds;Sekunden
;;
ns:room#;;
invTitle;Select a Minigame;Wähle einen Spielmodus
@ -64,15 +69,26 @@ noOptionDescription;There are no options for this Game;Es gibt keine Einstellung
ns:GameFactory#;;
missingDescription;No description;Keine Beschreibung
;;
ns:game_TntRun#;;
name;TNT run;TNT Rennen
description;The tnt at the ground disappears, don't fall;Das TNT am Boden verschwindet, falle nicht herunter
levels;levels;Ebenen
;;
ns:game_ElytraRace#;;
name;Elytra race;Elytra Rennen
description;Be fast while flying through the rings;Sei schnell während du durch die Ringe fliegst
ringCount;ring count;Anzahl der Ringe
;;
ns:game_Minerun#;;
name;Minerun;Minenrennen
description;Ditch deadly Mines in the ground an be the first in the goal;Weiche den tödlichen Bodenmienen aus und sei der erste im Ziel
optionPercentageMines;Percentage of Miens;Prozentsatz der Minen
optionPercentageMines;Percentage of mines;Prozentsatz der Minen
;;
ns:game_Deathcube#;;
name;Deathcube;Todeswürfel
description;Find a way to jump higher and be the first on the top;Finde einen weg nach oben und sei der erste im Ziel
optionPercentageBlocks;Percentage of Blocks;Prozentsatz der Blöcke
optionPvpEnabled;pvp enabled;PvP aktiviert
;;
ns:game_Stickfight#;;
name;Stickfight;Stockschlacht
@ -82,6 +98,14 @@ ns:game_TrafficlightRace#;;
name;Red light green light;Rotes licht, Grünes licht
description;Only go forward if the Trafficlights show green;Gehe nur bei Grün vorran
;;
ns:game_AcidRain#;;
name;Acid rain;Säureregen
description;Stay under the holey roof to dodge acid rain;Bleib unter dem löchrigen Dach um dem sauren Regen auszuweichen
;;
ns:game_BowSpleef#;;
name;Bow spleef;Bogen Spleef
description;Spleef other players and be the last survivor;Zerstöre Blöcke unter anderen Spielern und sei der letzte im Feld
;;
ns:game_Towerdefense#;;
name;Towerdefense;Towerdefense
description;Protect the path ????;??????
@ -89,4 +113,20 @@ description;Protect the path ????;??????
ns:game_Spleef#;;
name;Spleef;Spleef;
description;Spleef other players and be the last survivor;Zerstöre Blöcke unter anderen Spielern und sei der letzte im Feld
shovelName;Snow thrower;Schneeflug
shovelName;Snow thrower;Schneeflug
stackCount;levels;Ebenen
;;
ns:game_Tetris#;;
name;Tetris;Tetris
description;Sort falling blocks and clear lines;Sortiere fallende Blöcke und kläre Linien
nextTetrominoesCount;Number of upcoming Tetrominos displayed;Anzahl der angezeigten kommenden Tetrominos
isFast;Fast mode;Schneller Modus
hasCombat;Competitive mode;Kompetitiver Modus
;;
ns:game_AnvilRun#;;
name;Anvil run;Anvil run
description;Run away from falling anvils;Renne von fallenden Ambossen davon
;;
ns:game_jumpDive#;;
name;Jump dive;Wassersprung
description;Jump into the water, avoiding already used spots!;Springe ins wasser an stellen, in denen noch niemand zuvor gelandet ist!

Can't render this file because it has a wrong number of fields in line 114.