146 Commits

Author SHA1 Message Date
8f6950f9af configure IntelliJ project settings and add .gitignore for IDE and Gradle 2025-10-16 01:07:28 +02:00
794dc1dbb1 reformatted project 2025-10-16 00:58:52 +02:00
cf0499df44 Merge pull request 'develop-fairScoreboard' (#4) from develop-fairScoreboard into develop
Reviewed-on: #4
Reviewed-by: Elias Müller <elias@elias-mueller.com>
2025-10-15 22:25:34 +00:00
0b65a62016 Merge branch 'develop' into develop-fairScoreboard 2025-10-15 22:25:24 +00:00
c301e775c9 added translation to all messages, ChatFormatHandler and new chat icons 2025-10-16 00:24:48 +02:00
d083ca3e1a fix: include '!' in regex for language file processing 2025-10-15 22:57:45 +02:00
50200b46ae Merge pull request 'develop-turtleGame' (#6) from develop-turtleGame into develop
Reviewed-on: #6
Reviewed-by: Elias Müller <elias@elias-mueller.com>
2025-10-15 20:21:27 +00:00
46a0f6e5be Merge remote-tracking branch 'origin/develop-turtleGame' into develop-turtleGame 2025-10-15 22:20:14 +02:00
758c51a2e1 Merge remote-tracking branch 'origin/develop' into develop-turtleGame
# Conflicts:
#	src/main/resources/lang/locales.map.csv
2025-10-15 22:19:39 +02:00
fd3f51c018 Merge pull request 'added SpaceSnake' (#5) from develop-spaceSnake into develop
Reviewed-on: #5
Reviewed-by: Lars Neuhaus <larslukasneuhaus@gmx.de>
2025-10-15 20:11:37 +00:00
be6b6da68e fix: prevent null instance in Turtle adaptView method 2025-10-15 22:01:10 +02:00
9f71523a07 lowered snack count 2025-10-15 21:56:48 +02:00
6d8c5ed917 solved pr comments 2025-10-15 21:33:17 +02:00
35dc924104 added null ckeck for boostTask and boostRefillTask 2025-10-15 21:30:11 +02:00
eff5e36987 solved some pr comments 2025-10-15 21:26:02 +02:00
9e2125cba3 Merge remote-tracking branch 'origin/develop' into develop-turtleGame
# Conflicts:
#	src/main/resources/lang/locales.map.csv
2025-10-15 21:06:04 +02:00
c8bf5f9186 added turtle game to pve 2025-10-15 21:04:46 +02:00
1830307f4b increased boost refill when eating flowers, changed speed options 2025-10-15 21:03:12 +02:00
3dfff84c61 changed left player detection to use hasResult of Score 2025-10-15 20:55:30 +02:00
6076c0ca15 Refactored player state management in SpaceSnake and implemented endgame handling 2025-10-15 20:54:26 +02:00
41028e3389 SpaceSnake displayBlock to Fallingblock
powerup detection via boundingbox
2025-10-15 20:36:52 +02:00
bc3f5f58a4 prevent diamond block as building block in SpaceSnake 2025-10-15 19:28:48 +02:00
512805de05 Merge branch 'develop' into develop-spaceSnake 2025-10-15 00:52:30 +02:00
9596800889 fixed extra space in lambda expression in SpaceSnake spawn calculation 2025-10-15 00:51:50 +02:00
a8a15a1c7c adjusted SpaceSnake spawn position and random bounds 2025-10-15 00:51:08 +02:00
db78ff33ce fixed typo in game name: renamed SNAKE3D to SPACESNAKE 2025-10-15 00:46:34 +02:00
5bb07596a1 added SpaceSnake game and related assets 2025-10-15 00:42:11 +02:00
c4aaa7acf9 added flowers and grass to HeightTerrainGenerator 2025-10-11 15:17:23 +02:00
097438886c added stickfight start and working length option 2025-10-11 12:22:50 +02:00
ae59482d7c solved pr comment 2025-10-11 11:36:01 +02:00
123c01da14 added possibility for same scores Tournament 2025-10-11 01:07:40 +02:00
e871c0bcb5 added possibility for same scores in PointsWinScore 2025-10-11 00:19:02 +02:00
c3f5170c33 added random height variations for elytra race gates 2025-10-10 22:53:56 +02:00
90832aacd0 added some globalRestrictions 2025-10-10 16:56:26 +02:00
dccb57b056 added LowestPointsWinScore and Stickfight win condition 2025-10-10 16:15:02 +02:00
368356c739 fixed unbreakable snow in Spleef 2025-10-10 15:20:43 +02:00
14a7e0c25f removed knockback for finished players in TrafficLightRace 2025-10-10 15:09:43 +02:00
398c3666e4 deathcube spectator mode when done 2025-10-10 12:00:12 +02:00
d5910b4b54 renamed methods 2025-10-06 17:40:08 +02:00
ec76dd5c85 added boost charge when eating snacks 2025-10-06 17:31:04 +02:00
84de61388e improved speed mechanic and bomb spawning, added countdown for last player 2025-10-05 18:24:46 +02:00
96170e9486 Merge pull request 'added BlockBreakRace' (#3) from develop-blockBreakRace into develop
Reviewed-on: #3
Reviewed-by: Lars Neuhaus <larslukasneuhaus@gmx.de>
2025-10-05 08:03:04 +00:00
9a97b746bc Merge branch 'develop' into develop-blockBreakRace 2025-10-05 08:02:56 +00:00
dece9c13b7 added translations 2025-10-05 00:19:37 +02:00
39fb7f4956 added boost mechanic 2025-10-05 00:13:56 +02:00
a2afc49d20 refactored BlockBreakRace to show players all items before the game starts 2025-10-04 21:38:50 +02:00
20b93cc9ae added BlockBreakRace game and related assets 2025-10-04 21:34:40 +02:00
75314748da removed sidebar, added names for items 2025-10-04 18:32:27 +02:00
61aa7543be improved sidebar (ordered and colored) 2025-10-04 16:29:03 +02:00
2fac287e1e added sidebar 2025-10-04 16:11:10 +02:00
2a6f2f2a44 added particle effects and sounds 2025-10-04 15:39:19 +02:00
382d850605 added better speed mechanic 2025-10-04 14:03:44 +02:00
a49b3b20cc Merge remote-tracking branch 'origin/develop' into develop-turtleGame 2025-10-04 13:53:17 +02:00
148b5fc634 fixed spectator mode after playing tetris 2025-10-04 13:50:53 +02:00
abf907af24 added todos 2025-10-04 13:49:49 +02:00
8bd0ab1974 fixed error after game ends 2025-10-04 13:39:57 +02:00
2c92553a8a added bombs 2025-10-04 13:15:57 +02:00
f26c3a9e6d improved entity collision check while generating 2025-10-04 00:36:50 +02:00
81524cfecf added snacks with collision, switched to multiplayer arena 2025-10-04 00:09:19 +02:00
f2fc4835c3 started random snack generation 2025-10-03 19:32:52 +02:00
abcb23d96a made turtle movement clean 2025-10-03 18:47:11 +02:00
eabbb312b9 Merge remote-tracking branch 'refs/remotes/origin/develop' into develop-turtleGame 2025-10-03 17:29:36 +02:00
fa69d4976d symbols and fastbridge description 2025-09-19 21:48:33 +02:00
e4fff421f5 added fastbridge terrain generator 2025-09-19 21:41:01 +02:00
e6bded1c9e implemented fastbridge gameplay 2025-09-13 19:01:21 +02:00
d98cebd86f added turtleGame playfield and movement 2025-09-02 22:29:47 +02:00
c87d318421 started turtleGame 2025-09-02 18:22:14 +02:00
37a63e10b0 WIP: Fastbridge 2025-08-09 00:06:11 +02:00
13cc6c30b5 highground finished 2025-07-26 19:03:48 +02:00
3dd41979f7 WIP: highground 2025-07-25 23:04:03 +02:00
a4c46bc298 sumo renamed 2025-07-25 20:31:50 +02:00
aaad777f9b added Sumo Minigame 2025-07-25 20:22:45 +02:00
c62c7cfd1a added Sumo Minigame 2025-07-19 01:33:37 +02:00
4575164e80 Merge branch 'develop' into develop-hannes
# Conflicts:
#	build.gradle
#	src/main/java/eu/mhsl/minenet/minigames/instance/game/GameList.java
2025-07-18 21:09:37 +02:00
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
cc371a9c12 Test game 2024-11-02 21:53:17 +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
204 changed files with 5140 additions and 1981 deletions

148
.gitignore vendored
View File

@@ -1,3 +1,120 @@
# Created by https://www.toptal.com/developers/gitignore/api/gradle,intellij,java
# Edit at https://www.toptal.com/developers/gitignore?templates=gradle,intellij,java
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
# https://plugins.jetbrains.com/plugin/7973-sonarlint
.idea/**/sonarlint/
# SonarQube Plugin
# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
.idea/**/sonarIssues.xml
# Markdown Navigator plugin
# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
.idea/**/markdown-navigator.xml
.idea/**/markdown-navigator-enh.xml
.idea/**/markdown-navigator/
# Cache file creation bug
# See https://youtrack.jetbrains.com/issue/JBR-2257
.idea/$CACHE_FILE$
# CodeStream plugin
# https://plugins.jetbrains.com/plugin/12206-codestream
.idea/codestream.xml
# Azure Toolkit for IntelliJ plugin
# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
.idea/**/azureSettings.xml
### Java ###
# Compiled class file # Compiled class file
*.class *.class
@@ -23,8 +140,35 @@
hs_err_pid* hs_err_pid*
replay_pid* replay_pid*
.idea ### Gradle ###
.gradle .gradle
build/* **/build/
!src/**/build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Avoid ignore Gradle wrappper properties
!gradle-wrapper.properties
# Cache of project
.gradletasknamecache
# Eclipse Gradle plugin generated files
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
### Gradle Patch ###
# Java heap dump
*.hprof
# End of https://www.toptal.com/developers/gitignore/api/gradle,intellij,java
/resources/ /resources/
/build/
/bin/

3
.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

16
.idea/codeStyles/Project.xml generated Normal file
View File

@@ -0,0 +1,16 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<codeStyleSettings language="JAVA">
<option name="SPACE_BEFORE_IF_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_TRY_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="false" />
<option name="SPACE_BEFORE_SYNCHRONIZED_PARENTHESES" value="false" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

5
.idea/codeStyles/codeStyleConfig.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

6
.idea/compiler.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="21" />
</component>
</project>

View File

@@ -0,0 +1,7 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="UnqualifiedFieldAccess" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnqualifiedMethodAccess" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

40
.idea/jarRepositories.xml generated Normal file
View File

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven3" />
<option name="name" value="maven3" />
<option name="url" value="https://oss.sonatype.org/content/repositories/snapshots" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven2" />
<option name="name" value="maven2" />
<option name="url" value="https://repo.unnamed.team/repository/unnamed-public/" />
</remote-repository>
<remote-repository>
<option name="id" value="maven4" />
<option name="name" value="maven4" />
<option name="url" value="https://jitpack.io" />
</remote-repository>
<remote-repository>
<option name="id" value="Google" />
<option name="name" value="Google" />
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
</remote-repository>
</component>
</project>

5
.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK" />
</project>

10
.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Minigames.main.iml" filepath="$PROJECT_DIR$/.idea/modules/Minigames.main.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/Minigames.test.iml" filepath="$PROJECT_DIR$/.idea/modules/Minigames.test.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/eu.mhsl.minenet.Minigames.main.iml" filepath="$PROJECT_DIR$/.idea/modules/eu.mhsl.minenet.Minigames.main.iml" />
</modules>
</component>
</project>

17
.idea/modules/Minigames.main.iml generated Normal file
View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
<projectReimportVersion>1</projectReimportVersion>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

13
.idea/modules/Minigames.test.iml generated Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
<projectReimportVersion>1</projectReimportVersion>
</configuration>
</facet>
</component>
</module>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
<projectReimportVersion>1</projectReimportVersion>
</configuration>
</facet>
</component>
</module>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
<projectReimportVersion>1</projectReimportVersion>
</configuration>
</facet>
</component>
</module>

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View File

@@ -10,8 +10,6 @@ group 'eu.mhsl.minenet'
version '1.0-SNAPSHOT' version '1.0-SNAPSHOT'
repositories { repositories {
//maven 'https://repo.unnamed.team/repository/unnamed-public/'
mavenCentral() mavenCentral()
google() google()
@@ -28,9 +26,16 @@ repositories {
} }
} }
allprojects {
repositories {
maven { url "https://jitpack.io" }
}
}
java { java {
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(17) languageVersion = JavaLanguageVersion.of(21)
} }
} }
@@ -39,28 +44,20 @@ dependencies {
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.9.0'
//https://jitpack.io/#Minestom/Minestom //https://jitpack.io/#Minestom/Minestom
// implementation 'com.github.Minestom:Minestom:c496ee357' implementation 'net.minestom:minestom-snapshots:fd51c8d17a'
// 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'
//Tools //Tools
implementation 'de.articdive:jnoise:3.0.2' implementation 'de.articdive:jnoise:3.0.2'
implementation 'net.md-5:bungeecord-config:1.19-R0.1-SNAPSHOT' implementation 'net.md-5:bungeecord-config:1.21-R0.3'
implementation 'org.apache.commons:commons-text:1.10.0' implementation 'org.apache.commons:commons-text:1.10.0'
implementation 'org.spongepowered:configurate-yaml:4.1.2' implementation 'org.spongepowered:configurate-yaml:4.1.2'
implementation 'com.sparkjava:spark-core:2.9.4' implementation 'com.sparkjava:spark-core:2.9.4'
implementation 'com.google.code.gson:gson:2.10.1' 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 //PvP
implementation 'com.github.TogAr2:MinestomPvP:35e5661' implementation 'io.github.TogAr2:MinestomPvP:PR62-SNAPSHOT'
//implementation 'com.github.TogAr2:MinestomPvP:135ec9e2b7'
// Hephaestus engine // Hephaestus engine
implementation("team.unnamed:hephaestus-api:0.2.1-SNAPSHOT") implementation("team.unnamed:hephaestus-api:0.2.1-SNAPSHOT")

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists 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 zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists 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 # See the License for the specific language governing permissions and
# limitations under the License. # 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 # (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 # 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 # 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 # ksh Gradle
# #
@@ -35,7 +37,7 @@
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»; # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»; # * 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: # Important for patching:
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (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. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +82,12 @@ do
esac esac
done done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # This is normally unused
# shellcheck disable=SC2034
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' ' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@@ -117,7 +118,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 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 [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
@@ -133,29 +134,36 @@ location of your Java installation."
fi fi
else else
JAVACMD=java 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 Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) 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 ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
case $MAX_FD in #( case $MAX_FD in #(
'' | soft) :;; #( '' | 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" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
fi fi
# Collect all arguments for the java eu.mhsl.minenet.minigames.command, stacking in reverse order: # Collect all arguments for the java command, stacking in reverse order:
# * args from the eu.mhsl.minenet.minigames.command line # * args from the command line
# * the main class name # * the main class name
# * -classpath # * -classpath
# * -D...appname settings # * -D...appname settings
@@ -193,11 +201,15 @@ if "$cygwin" || "$msys" ; then
done done
fi fi
# Collect all arguments for the java eu.mhsl.minenet.minigames.command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
# shell script including quotes and variable substitutions, so put them in DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded. # 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 -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -205,6 +217,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ 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. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
@@ -214,7 +232,7 @@ set -- \
# readarray ARGS < <( xargs -n1 <<<"$var" ) && # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@" # 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 # 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 # character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap # 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 See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@@ -25,7 +27,8 @@
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@@ -40,13 +43,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' eu.mhsl.minenet.gameList.command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@@ -56,16 +59,16 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
:execute :execute
@rem Setup the eu.mhsl.minenet.gameList.command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@@ -75,13 +78,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal 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.handler.Listeners;
import eu.mhsl.minenet.minigames.lang.Languages; import eu.mhsl.minenet.minigames.lang.Languages;
import eu.mhsl.minenet.minigames.server.tasks.TablistUpdateTask; 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.MinecraftServer;
import net.minestom.server.extras.bungee.BungeeCordProxy; import net.minestom.server.extras.bungee.BungeeCordProxy;
import net.minestom.server.extras.lan.OpenToLAN; import net.minestom.server.extras.lan.OpenToLAN;
@@ -26,6 +24,7 @@ public class Main {
private final static Logger logger = Logger.getGlobal(); private final static Logger logger = Logger.getGlobal();
public static ConfigurationNode globalConfig; public static ConfigurationNode globalConfig;
@SuppressWarnings("ResultOfMethodCallIgnored")
public static void main(String[] args) throws ConfigurateException { public static void main(String[] args) throws ConfigurateException {
//noinspection ResultOfMethodCallIgnored //noinspection ResultOfMethodCallIgnored
Resource.values(); // This initializes and preloads the enum and extracts the resources Resource.values(); // This initializes and preloads the enum and extracts the resources
@@ -42,14 +41,12 @@ public class Main {
logger.info("Initialize Minecraft server..."); logger.info("Initialize Minecraft server...");
MinecraftServer server = MinecraftServer.init(); MinecraftServer server = MinecraftServer.init();
PvpExtension.init(); // MinestomPvP.init();
MinecraftServer.setBrandName("mhsl.eu - minenet - credits to minestom"); MinecraftServer.setBrandName("mhsl.eu - minenet - credits to minestom");
MinecraftServer.setCompressionThreshold(serverConfig.node("compression-threshold").getInt(0)); MinecraftServer.setCompressionThreshold(serverConfig.node("compression-threshold").getInt(0));
System.setProperty("minestom.chunk-view-distance", String.valueOf(serverConfig.node("view-distance").getInt())); System.setProperty("minestom.chunk-view-distance", String.valueOf(serverConfig.node("view-distance").getInt()));
MinecraftServer.getConnectionManager().setUuidProvider(new ByPlayerNameUuidProvider());
Commands.values(); Commands.values();
Listeners.values(); Listeners.values();
new HttpServer(); new HttpServer();

View File

@@ -21,6 +21,7 @@ public enum Resource {
private final Path path; private final Path path;
private final String name; private final String name;
Resource(String name, boolean keepOutdated) { Resource(String name, boolean keepOutdated) {
this.name = name; this.name = name;
this.path = Path.of("resources/" + name); this.path = Path.of("resources/" + name);
@@ -28,7 +29,7 @@ public enum Resource {
try { try {
Logger.getLogger("ressource").info("extracting resource " + name + " ... "); Logger.getLogger("ressource").info("extracting resource " + name + " ... ");
ResourceUtils.extractResource(name, keepOutdated); ResourceUtils.extractResource(name, keepOutdated);
} catch (URISyntaxException | IOException e) { } catch(URISyntaxException | IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@@ -38,10 +39,10 @@ public enum Resource {
} }
public Path getPath() { public Path getPath() {
return path; return this.path;
} }
public String getName() { public String getName() {
return name; return this.name;
} }
} }

View File

@@ -12,11 +12,11 @@ public abstract class Controller<Q, R> implements Route {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Controller() { public Controller() {
this.requestType = ((Class<Q>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]); this.requestType = ((Class<Q>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
} }
@Override @Override
public Object handle(Request request, Response response) throws Exception { public Object handle(Request request, Response response) {
response.header("Access-Control-Allow-Origin", "*"); response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Methods", "*"); response.header("Access-Control-Allow-Methods", "*");
@@ -28,7 +28,7 @@ public abstract class Controller<Q, R> implements Route {
req = new Gson().fromJson(request.body(), this.requestType); req = new Gson().fromJson(request.body(), this.requestType);
} }
return new Gson().toJson(handle(req, response)); return new Gson().toJson(this.handle(req, response));
} }
public abstract R handle(Q request, Response response); public abstract R handle(Q request, Response response);

View File

@@ -10,6 +10,7 @@ import static spark.Spark.*;
public class HttpServer { public class HttpServer {
private static final ConfigurationNode apiConfig = Main.globalConfig.node("api"); private static final ConfigurationNode apiConfig = Main.globalConfig.node("api");
public HttpServer() { public HttpServer() {
if(!apiConfig.node("enabled").getBoolean()) return; if(!apiConfig.node("enabled").getBoolean()) return;

View File

@@ -6,8 +6,12 @@ import spark.Response;
import java.util.UUID; import java.util.UUID;
record Req(UUID room) {} record Req(UUID room) {
record Resp() {} }
record Resp() {
}
public class CloseRoom extends Controller<Req, Resp> { public class CloseRoom extends Controller<Req, Resp> {
@Override @Override
public Resp handle(Req request, Response response) { public Resp handle(Req request, Response response) {

View File

@@ -6,8 +6,12 @@ import spark.Response;
import java.util.UUID; import java.util.UUID;
record Req() {} record Req() {
record Resp(UUID uuid) {} }
record Resp(UUID uuid) {
}
public class CreateRoom extends Controller<Req, Resp> { public class CreateRoom extends Controller<Req, Resp> {
@Override @Override
public Resp handle(Req request, Response response) { public Resp handle(Req request, Response response) {

View File

@@ -8,8 +8,12 @@ import spark.Response;
import java.util.UUID; import java.util.UUID;
record Req(UUID player, UUID room) {} record Req(UUID player, UUID room) {
record Resp(String error) {} }
record Resp(String error) {
}
public class QueueRoom extends Controller<Req, Resp> { public class QueueRoom extends Controller<Req, Resp> {
@Override @Override
public Resp handle(Req request, Response response) { public Resp handle(Req request, Response response) {

View File

@@ -1,9 +1,8 @@
package eu.mhsl.minenet.minigames.command; package eu.mhsl.minenet.minigames.command;
import eu.mhsl.minenet.minigames.command.anonymous.SkinCommand;
import eu.mhsl.minenet.minigames.command.privileged.*;
import eu.mhsl.minenet.minigames.command.anonymous.HubCommand; import eu.mhsl.minenet.minigames.command.anonymous.HubCommand;
import eu.mhsl.minenet.minigames.command.anonymous.LeaveCommand; import eu.mhsl.minenet.minigames.command.anonymous.LeaveCommand;
import eu.mhsl.minenet.minigames.command.privileged.*;
import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
@@ -21,7 +20,6 @@ public enum Commands {
ROOM(new RoomCommand()), ROOM(new RoomCommand()),
UPDATE(new RefreshCommandsCommand()), UPDATE(new RefreshCommandsCommand()),
OP(new OpCommand()), OP(new OpCommand()),
FAKEPLAYER(new FakeplayerCommand()),
KICK(new KickCommand()), KICK(new KickCommand()),
SKIN(new SkinCommand()), SKIN(new SkinCommand()),
SETOWNER(new SetRoomOwnerCommand()), SETOWNER(new SetRoomOwnerCommand()),
@@ -34,14 +32,18 @@ public enum Commands {
PLAYERLIMIT(new PlayerLimitCommand()), PLAYERLIMIT(new PlayerLimitCommand()),
SETMEMORIAL(new SetMemorialCommand()); SETMEMORIAL(new SetMemorialCommand());
Commands(Command handler) {
MinecraftServer.getCommandManager().register(handler);
}
static { static {
MinecraftServer.getCommandManager().setUnknownCommandCallback((sender, command) -> { MinecraftServer.getCommandManager().setUnknownCommandCallback((sender, command) -> {
if(command.isBlank()) return; if(command.isBlank()) return;
new ChatMessage(Icon.ERROR).appendStatic("Unknown command").quote(command).send(sender); new ChatMessage(Icon.ERROR)
.appendTranslated("common#unknownCommand")
.appendSpace()
.quote(command)
.send(sender);
}); });
} }
Commands(Command handler) {
MinecraftServer.getCommandManager().register(handler);
}
} }

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.Command;
import net.minestom.server.command.builder.condition.CommandCondition; import net.minestom.server.command.builder.condition.CommandCondition;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@@ -10,27 +11,28 @@ import java.util.List;
public class PrivilegedCommand extends Command { public class PrivilegedCommand extends Command {
private final List<CommandCondition> conditions = new ArrayList<>(); private final List<CommandCondition> conditions = new ArrayList<>();
public PrivilegedCommand(@NotNull String name, @Nullable String... aliases) { public PrivilegedCommand(@NotNull String name, @Nullable String... aliases) {
super(name, aliases); super(name, aliases);
construct(); this.construct();
} }
public PrivilegedCommand(@NotNull String name) { public PrivilegedCommand(@NotNull String name) {
super(name); super(name);
construct(); this.construct();
} }
private void construct() { private void construct() {
addCondition(isPrivileged()); this.addCondition(this.isPrivileged());
setCondition((sender, commandString) -> conditions.parallelStream().allMatch(condition -> condition.canUse(sender, commandString))); this.setCondition((sender, commandString) -> this.conditions.parallelStream().allMatch(condition -> condition.canUse(sender, commandString)));
} }
protected CommandCondition isPrivileged() { protected CommandCondition isPrivileged() {
return (sender, commandString) -> sender.hasPermission("admin"); return (sender, commandString) -> ((Player) sender).getPermissionLevel() == 4;
} }
protected void addCondition(CommandCondition condition) { protected void addCondition(CommandCondition condition) {
conditions.add(condition); this.conditions.add(condition);
} }
} }

View File

@@ -1,8 +1,8 @@
package eu.mhsl.minenet.minigames.command.anonymous; package eu.mhsl.minenet.minigames.command.anonymous;
import eu.mhsl.minenet.minigames.util.MoveInstance;
import eu.mhsl.minenet.minigames.instance.hub.Hub; import eu.mhsl.minenet.minigames.instance.hub.Hub;
import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.util.MoveInstance;
import net.minestom.server.command.builder.Command; import net.minestom.server.command.builder.Command;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@@ -10,9 +10,13 @@ public class HubCommand extends Command {
public HubCommand() { public HubCommand() {
super("hub"); super("hub");
setCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Room); this.setCondition(
(sender, commandString) ->
((Player) sender).getInstance() instanceof Room room && !room.apiDriven
);
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
if(Room.getRoom((Player) sender).orElseThrow().apiDriven) return;
Room.unsetRoom((Player) sender); Room.unsetRoom((Player) sender);
MoveInstance.move((Player) sender, Hub.INSTANCE); MoveInstance.move((Player) sender, Hub.INSTANCE);
}); });

View File

@@ -9,8 +9,8 @@ public class LeaveCommand extends Command {
public LeaveCommand() { public LeaveCommand() {
super("leave"); super("leave");
setCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Game); this.setCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Game);
setDefaultExecutor((sender, context) -> Room.setOwnRoom((Player) sender)); this.setDefaultExecutor((sender, context) -> Room.setOwnRoom((Player) sender));
} }
} }

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.ActionBarMessage;
import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.message.type.TitleMessage; import eu.mhsl.minenet.minigames.message.type.TitleMessage;
import eu.mhsl.minenet.minigames.util.PacketUtil;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import java.util.ArrayList; import java.util.ArrayList;
@@ -15,15 +14,15 @@ public class DebugCommand extends PrivilegedCommand {
public DebugCommand() { public DebugCommand() {
super("debug"); super("debug");
setDefaultExecutor((sender, args) -> { this.setDefaultExecutor((sender, args) -> {
new ChatMessage(Icon.CHAT).appendTranslated("sample").send(sender); new ChatMessage(Icon.CHAT).appendTranslated("sample").send(sender);
new ActionBarMessage().appendTranslated("sample").send(sender); new ActionBarMessage().appendTranslated("sample").send(sender);
new TitleMessage().subtitle(subtitleMessage -> subtitleMessage.appendTranslated("sample")).appendTranslated("sample").send(sender); new TitleMessage().subtitle(subtitleMessage -> subtitleMessage.appendTranslated("sample")).appendTranslated("sample").send(sender);
List<String> testplayers = new ArrayList<>() { List<String> testplayers = new ArrayList<>() {
{ {
add("MineTec"); this.add("MineTec");
add("Goldi187"); this.add("Goldi187");
add("Test"); this.add("Test");
} }
}; };
new ChatMessage(Icon.STAR, true) new ChatMessage(Icon.STAR, true)
@@ -36,8 +35,6 @@ public class DebugCommand extends PrivilegedCommand {
.appendTranslated("score#thanks") .appendTranslated("score#thanks")
.send(sender); .send(sender);
PacketUtil.resendPlayerList(((Player) sender));
new ChatMessage(Icon.SCIENCE).appendStatic(((Player) sender).getUuid().toString()).send(sender); new ChatMessage(Icon.SCIENCE).appendStatic(((Player) sender).getUuid().toString()).send(sender);
}); });

View File

@@ -1,33 +0,0 @@
package eu.mhsl.minenet.minigames.command.privileged;
import eu.mhsl.minenet.minigames.command.PrivilegedCommand;
import eu.mhsl.minenet.minigames.instance.room.Room;
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;
public class FakeplayerCommand extends PrivilegedCommand {
public FakeplayerCommand() {
super("fakeplayer");
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)
);
} else {
new ChatMessage(Icon.ERROR).appendStatic("Du musst dich in einer Raumlobby befinden!").send(sender);
}
}
}, ArgumentType.String("name"));
}
}

View File

@@ -8,7 +8,7 @@ public class FlyCommand extends PrivilegedCommand {
public FlyCommand() { public FlyCommand() {
super("fly"); super("fly");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
Player p = (Player) sender; Player p = (Player) sender;
p.setVelocity(new Vec(0, 5, 0)); p.setVelocity(new Vec(0, 5, 0));
p.setFlying(!p.isFlying()); p.setFlying(!p.isFlying());

View File

@@ -7,7 +7,7 @@ import net.minestom.server.entity.Player;
public class GameStartCommand extends PrivilegedCommand { public class GameStartCommand extends PrivilegedCommand {
public GameStartCommand() { public GameStartCommand() {
super("gameStart"); super("gameStart");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
Player player = (Player) sender; Player player = (Player) sender;
if(player.getInstance() instanceof StatelessGame game) { if(player.getInstance() instanceof StatelessGame game) {
game.startAccessor(); game.startAccessor();

View File

@@ -7,7 +7,7 @@ import net.minestom.server.entity.Player;
public class GameStopCommand extends PrivilegedCommand { public class GameStopCommand extends PrivilegedCommand {
public GameStopCommand() { public GameStopCommand() {
super("gameStop"); super("gameStop");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
Player player = (Player) sender; Player player = (Player) sender;
if(player.getInstance() instanceof StatelessGame game) { if(player.getInstance() instanceof StatelessGame game) {
game.stop(); game.stop();

View File

@@ -12,7 +12,7 @@ public class GameTimeoutCommand extends PrivilegedCommand {
ArgumentInteger timeout = ArgumentType.Integer("timeout"); ArgumentInteger timeout = ArgumentType.Integer("timeout");
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> {
Player player = (Player) sender; Player player = (Player) sender;
if(player.getInstance() instanceof StatelessGame game) { if(player.getInstance() instanceof StatelessGame game) {
game.setTimeLimit(context.get(timeout)); game.setTimeLimit(context.get(timeout));

View File

@@ -11,7 +11,7 @@ public class GamemodeCommand extends PrivilegedCommand {
super("gamemode", "gm"); super("gamemode", "gm");
addSyntax((sender, context) -> ((Player) sender).setGameMode( this.addSyntax((sender, context) -> ((Player) sender).setGameMode(
context.get("target")), context.get("target")),
ArgumentType.Enum("target", GameMode.class).setFormat(ArgumentEnum.Format.LOWER_CASED) ArgumentType.Enum("target", GameMode.class).setFormat(ArgumentEnum.Format.LOWER_CASED)
); );

View File

@@ -1,17 +1,18 @@
package eu.mhsl.minenet.minigames.command.privileged; package eu.mhsl.minenet.minigames.command.privileged;
import eu.mhsl.minenet.minigames.command.PrivilegedCommand; import eu.mhsl.minenet.minigames.command.PrivilegedCommand;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.util.Monitoring; import eu.mhsl.minenet.minigames.util.Monitoring;
public class GcCommand extends PrivilegedCommand { public class GcCommand extends PrivilegedCommand {
private static long lastRun = System.currentTimeMillis(); private static long lastRun = System.currentTimeMillis();
public GcCommand() { public GcCommand() {
super("gc"); super("gc");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
long nextRun = (lastRun - (System.currentTimeMillis() - 30*1000)) / 1000; long nextRun = (lastRun - (System.currentTimeMillis() - 30 * 1000)) / 1000;
if(nextRun > 0) { if(nextRun > 0) {
new ChatMessage(Icon.ERROR).appendStatic("Please wait ").appendStatic(String.valueOf(nextRun)).appendStatic(" seconds before running GC again!").send(sender); new ChatMessage(Icon.ERROR).appendStatic("Please wait ").appendStatic(String.valueOf(nextRun)).appendStatic(" seconds before running GC again!").send(sender);
return; return;
@@ -26,7 +27,7 @@ public class GcCommand extends PrivilegedCommand {
new ChatMessage(Icon.SUCCESS).appendStatic("Garbage collector ran successfully!").newLine() new ChatMessage(Icon.SUCCESS).appendStatic("Garbage collector ran successfully!").newLine()
.appendStatic("before: ").appendStatic(String.valueOf(before)).appendStatic("MB").newLine() .appendStatic("before: ").appendStatic(String.valueOf(before)).appendStatic("MB").newLine()
.appendStatic("now: ").appendStatic(String.valueOf(after)).appendStatic("MB").newLine() .appendStatic("now: ").appendStatic(String.valueOf(after)).appendStatic("MB").newLine()
.appendStatic("difference: ").appendStatic(String.valueOf(before-after)).appendStatic("MB") .appendStatic("difference: ").appendStatic(String.valueOf(before - after)).appendStatic("MB")
.send(sender); .send(sender);
}); });
} }

View File

@@ -13,7 +13,7 @@ public class InstanceProxyMoveCommand extends PrivilegedCommand {
ArgumentWord serverArgument = new ArgumentWord("server"); ArgumentWord serverArgument = new ArgumentWord("server");
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> {
Instance room = ((Player) sender).getInstance(); Instance room = ((Player) sender).getInstance();
room.getPlayers().forEach(player -> { room.getPlayers().forEach(player -> {
Room.unsetRoom(player); Room.unsetRoom(player);

View File

@@ -11,22 +11,22 @@ public class KickCommand extends PrivilegedCommand {
public KickCommand() { public KickCommand() {
super("kick"); super("kick");
addSyntax( this.addSyntax(
(sender, context) -> (sender, context) ->
kick(context.getRaw("player"), ""), this.kick(context.getRaw("player"), ""),
ArgumentType.Entity("player").onlyPlayers(true) ArgumentType.Entity("player").onlyPlayers(true)
); );
addSyntax( this.addSyntax(
(sender, context) -> (sender, context) ->
kick(context.getRaw("player"), context.getRaw("reason")), this.kick(context.getRaw("player"), context.getRaw("reason")),
ArgumentType.Entity("player").onlyPlayers(true), ArgumentType.Entity("player").onlyPlayers(true),
ArgumentType.String("reason") ArgumentType.String("reason")
); );
} }
private void kick(String playername, String reason) { private void kick(String playername, String reason) {
Player playerToKick = MinecraftServer.getConnectionManager().findPlayer(playername); Player playerToKick = MinecraftServer.getConnectionManager().findOnlinePlayer(playername);
Objects.requireNonNull(playerToKick).kick(reason); Objects.requireNonNull(playerToKick).kick(reason);
} }
} }

View File

@@ -1,8 +1,8 @@
package eu.mhsl.minenet.minigames.command.privileged; package eu.mhsl.minenet.minigames.command.privileged;
import eu.mhsl.minenet.minigames.command.PrivilegedCommand; import eu.mhsl.minenet.minigames.command.PrivilegedCommand;
import eu.mhsl.minenet.minigames.lang.Languages;
import eu.mhsl.minenet.minigames.lang.Lang; import eu.mhsl.minenet.minigames.lang.Lang;
import eu.mhsl.minenet.minigames.lang.Languages;
import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.TranslatableMessage; import eu.mhsl.minenet.minigames.message.TranslatableMessage;
import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.message.type.ChatMessage;
@@ -13,11 +13,11 @@ public class LangTestCommand extends PrivilegedCommand {
public LangTestCommand() { public LangTestCommand() {
super("langtest"); super("langtest");
setDefaultExecutor((sender, context) -> sendMessage(Languages.getInstance().getLanguage((Player) sender), "sample").send(sender)); this.setDefaultExecutor((sender, context) -> this.sendMessage(Languages.getInstance().getLanguage((Player) sender), "sample").send(sender));
var targetString = ArgumentType.String("mapId"); var targetString = ArgumentType.String("mapId");
addSyntax((sender, context) -> sendMessage(Languages.getInstance().getLanguage((Player) sender), context.get("mapId")).send(sender), targetString); this.addSyntax((sender, context) -> this.sendMessage(Languages.getInstance().getLanguage((Player) sender), context.get("mapId")).send(sender), targetString);
} }
private TranslatableMessage sendMessage(Lang lang, String mapId) { private TranslatableMessage sendMessage(Lang lang, String mapId) {

View File

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

View File

@@ -10,8 +10,9 @@ public class PlayerLimitCommand extends PrivilegedCommand {
ArgumentInteger count = ArgumentType.Integer("count"); ArgumentInteger count = ArgumentType.Integer("count");
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> System.setProperty(
System.setProperty("minenet.playerlimit", String.valueOf(context.get(count))); "minenet.playerlimit",
}, count); String.valueOf(context.get(count))
), count);
} }
} }

View File

@@ -13,10 +13,11 @@ import java.net.http.HttpResponse;
public class PublishRewardCommand extends PrivilegedCommand { public class PublishRewardCommand extends PrivilegedCommand {
private final HttpClient rewardPublishClient = HttpClient.newHttpClient(); private final HttpClient rewardPublishClient = HttpClient.newHttpClient();
public PublishRewardCommand() { public PublishRewardCommand() {
super("publishReward"); super("publishReward");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
try { try {
Room room = Room.getRoom((Player) sender).orElseThrow(); Room room = Room.getRoom((Player) sender).orElseThrow();
TournamentDisplay world = new TournamentDisplay(room.getTournament()); TournamentDisplay world = new TournamentDisplay(room.getTournament());
@@ -24,14 +25,14 @@ public class PublishRewardCommand extends PrivilegedCommand {
String rewardRequestJson = new Gson().toJson(room.getTournament().getRewards()); String rewardRequestJson = new Gson().toJson(room.getTournament().getRewards());
HttpRequest giveRewardsRequest = HttpRequest.newBuilder() 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)) .POST(HttpRequest.BodyPublishers.ofString(rewardRequestJson))
.build(); .build();
room.getTournament().getRewards(); room.getTournament().getRewards();
HttpResponse<Void> rawResponse = rewardPublishClient.send(giveRewardsRequest, HttpResponse.BodyHandlers.discarding()); HttpResponse<Void> rawResponse = this.rewardPublishClient.send(giveRewardsRequest, HttpResponse.BodyHandlers.discarding());
sender.sendMessage(String.format("Rewards published: HTTP %s", rawResponse.statusCode())); sender.sendMessage(String.format("Rewards published: HTTP %s", rawResponse.statusCode()));
} catch (Exception e) { } catch(Exception e) {
sender.sendMessage(e.getMessage()); sender.sendMessage(e.getMessage());
} }
}); });

View File

@@ -1,8 +1,8 @@
package eu.mhsl.minenet.minigames.command.privileged; package eu.mhsl.minenet.minigames.command.privileged;
import eu.mhsl.minenet.minigames.command.PrivilegedCommand; import eu.mhsl.minenet.minigames.command.PrivilegedCommand;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@@ -10,7 +10,7 @@ public class RefreshCommandsCommand extends PrivilegedCommand {
public RefreshCommandsCommand() { public RefreshCommandsCommand() {
super("refreshCommands"); super("refreshCommands");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(Player::refreshCommands); MinecraftServer.getConnectionManager().getOnlinePlayers().forEach(Player::refreshCommands);
new ChatMessage(Icon.SUCCESS).appendStatic("Updated command syntax!").send(sender); new ChatMessage(Icon.SUCCESS).appendStatic("Updated command syntax!").send(sender);
}); });

View File

@@ -1,10 +1,10 @@
package eu.mhsl.minenet.minigames.command.privileged; package eu.mhsl.minenet.minigames.command.privileged;
import eu.mhsl.minenet.minigames.command.PrivilegedCommand; import eu.mhsl.minenet.minigames.command.PrivilegedCommand;
import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.TranslatableMessage; import eu.mhsl.minenet.minigames.message.TranslatableMessage;
import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.instance.room.Room;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -13,7 +13,7 @@ public class RoomCommand extends PrivilegedCommand {
public RoomCommand() { public RoomCommand() {
super("room"); super("room");
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
TranslatableMessage out = new ChatMessage(Icon.SCIENCE).appendStatic("Rooms:").newLine(); TranslatableMessage out = new ChatMessage(Icon.SCIENCE).appendStatic("Rooms:").newLine();
Room.getAllRooms().forEach((roomInstance) -> out Room.getAllRooms().forEach((roomInstance) -> out

View File

@@ -20,15 +20,15 @@ public class SetMemorialCommand extends PrivilegedCommand {
ArgumentString titleArgument = ArgumentType.String("title"); ArgumentString titleArgument = ArgumentType.String("title");
ArgumentString loreArgument = ArgumentType.String("lore"); ArgumentString loreArgument = ArgumentType.String("lore");
materialArgument.setSuggestionCallback((sender, context, suggestion) -> { materialArgument.setSuggestionCallback(
Material (sender, context, suggestion) -> Material
.values() .values()
.stream() .stream()
.map(material -> new SuggestionEntry(material.name(), Component.text(material.name()))) .map(material -> new SuggestionEntry(material.name(), Component.text(material.name())))
.forEach(suggestion::addEntry); .forEach(suggestion::addEntry)
}); );
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> {
Room Room
.getRoom((Player) sender) .getRoom((Player) sender)
.orElseThrow() .orElseThrow()

View File

@@ -22,15 +22,15 @@ public class SetRewardCommand extends PrivilegedCommand {
ArgumentWord materialArgument = ArgumentType.Word("material"); ArgumentWord materialArgument = ArgumentType.Word("material");
ArgumentStringArray amountsArgument = ArgumentType.StringArray("amount"); ArgumentStringArray amountsArgument = ArgumentType.StringArray("amount");
materialArgument.setSuggestionCallback((sender, context, suggestion) -> { materialArgument.setSuggestionCallback(
Material (sender, context, suggestion) -> Material
.values() .values()
.stream() .stream()
.map(material -> new SuggestionEntry(material.name(), Component.text(material.name()))) .map(material -> new SuggestionEntry(material.name(), Component.text(material.name())))
.forEach(suggestion::addEntry); .forEach(suggestion::addEntry)
}); );
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> {
Room Room
.getRoom((Player) sender) .getRoom((Player) sender)
.orElseThrow() .orElseThrow()

View File

@@ -15,21 +15,21 @@ public class SetRoomOwnerCommand extends PrivilegedCommand {
public SetRoomOwnerCommand() { public SetRoomOwnerCommand() {
super("setRoomOwner"); super("setRoomOwner");
addCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Room); this.addCondition((sender, commandString) -> ((Player) sender).getInstance() instanceof Room);
setDefaultExecutor((sender, context) -> { this.setDefaultExecutor((sender, context) -> {
if(sender instanceof Player p) { if(sender instanceof Player p) {
Room.getRoom(p).orElseThrow().setOwner(p); Room.getRoom(p).orElseThrow().setOwner(p);
new ChatMessage(Icon.SUCCESS).appendStatic("You are now the owner of this room!").send(sender); new ChatMessage(Icon.SUCCESS).appendTranslated("room#ownerSelf").send(sender);
} }
}); });
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> {
System.out.println("Test"); System.out.println("Test");
if(sender instanceof Player p) { 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)); Room.getRoom(p).orElseThrow().setOwner(Objects.requireNonNull(newOwner));
new ChatMessage(Icon.SUCCESS).appendStatic("The new owner has been set!").send(sender); new ChatMessage(Icon.SUCCESS).appendTranslated("room#ownerSet").send(sender);
} }
}, ArgumentType.Entity("player").onlyPlayers(true)); }, ArgumentType.Entity("player").onlyPlayers(true));
} }

View File

@@ -1,15 +1,15 @@
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.command.builder.arguments.ArgumentType;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.entity.PlayerSkin; import net.minestom.server.entity.PlayerSkin;
public class SkinCommand extends Command { public class SkinCommand extends PrivilegedCommand {
public SkinCommand() { public SkinCommand() {
super("skin"); super("skin");
addSyntax((sender, context) -> { this.addSyntax((sender, context) -> {
if(sender instanceof Player p) { if(sender instanceof Player p) {
p.setSkin(PlayerSkin.fromUsername(context.getRaw("target"))); p.setSkin(PlayerSkin.fromUsername(context.getRaw("target")));
} }

View File

@@ -1,14 +1,17 @@
package eu.mhsl.minenet.minigames.handler; package eu.mhsl.minenet.minigames.handler;
import eu.mhsl.minenet.minigames.handler.global.*; import eu.mhsl.minenet.minigames.handler.global.AddEntityToInstanceEventListener;
import eu.mhsl.minenet.minigames.handler.global.ChatFormatHandler;
import eu.mhsl.minenet.minigames.handler.global.PlayerLeaveHandler;
import eu.mhsl.minenet.minigames.handler.global.PlayerLoginHandler;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.event.EventListener; import net.minestom.server.event.EventListener;
public enum Listeners { public enum Listeners {
SPAWN(new AddEntityToInstanceEventListener()), SPAWN(new AddEntityToInstanceEventListener()),
CHAT(new PlayerChatHandler()),
LOGIN(new PlayerLoginHandler()), LOGIN(new PlayerLoginHandler()),
LEAVE(new PlayerLeaveHandler()); LEAVE(new PlayerLeaveHandler()),
CHAT(new ChatFormatHandler());
Listeners(EventListener<?> event) { Listeners(EventListener<?> event) {
MinecraftServer.getGlobalEventHandler().addListener(event); MinecraftServer.getGlobalEventHandler().addListener(event);

View File

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

View File

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

View File

@@ -1,5 +1,9 @@
package eu.mhsl.minenet.minigames.handler.global; package eu.mhsl.minenet.minigames.handler.global;
import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener; import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.PlayerDisconnectEvent; import net.minestom.server.event.player.PlayerDisconnectEvent;
@@ -14,7 +18,11 @@ public class PlayerLeaveHandler implements EventListener<PlayerDisconnectEvent>
@Override @Override
public @NotNull Result run(@NotNull PlayerDisconnectEvent event) { public @NotNull Result run(@NotNull PlayerDisconnectEvent event) {
Player p = event.getPlayer(); Player p = event.getPlayer();
// new ChatMessage(Icon.SCIENCE).appendStatic("unübersetzter Leavetext: ").appendStatic(p.getDisplayName()).send(MinecraftServer.getConnectionManager().getOnlinePlayers()); new ChatMessage(Icon.LEAVE)
.appendStatic(p.getName().color(NamedTextColor.GRAY))
.appendSpace()
.appendTranslated("common#leave", NamedTextColor.DARK_GRAY)
.send(MinecraftServer.getConnectionManager().getOnlinePlayers());
return Result.SUCCESS; return Result.SUCCESS;
} }
} }

View File

@@ -2,6 +2,7 @@ package eu.mhsl.minenet.minigames.handler.global;
import eu.mhsl.minenet.minigames.Main; import eu.mhsl.minenet.minigames.Main;
import eu.mhsl.minenet.minigames.api.QueuedPlayerRooms; import eu.mhsl.minenet.minigames.api.QueuedPlayerRooms;
import eu.mhsl.minenet.minigames.instance.hub.Hub;
import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.instance.transfer.Transfer; import eu.mhsl.minenet.minigames.instance.transfer.Transfer;
import eu.mhsl.minenet.minigames.skin.SkinCache; import eu.mhsl.minenet.minigames.skin.SkinCache;
@@ -9,9 +10,9 @@ import eu.mhsl.minenet.minigames.util.MoveInstance;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener; import net.minestom.server.event.EventListener;
import net.minestom.server.event.player.PlayerLoginEvent; import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import eu.mhsl.minenet.minigames.instance.hub.Hub; import net.minestom.server.network.packet.server.play.TeamsPacket;
import net.minestom.server.permission.Permission; import net.minestom.server.scoreboard.Team;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.spongepowered.configurate.serialize.SerializationException; import org.spongepowered.configurate.serialize.SerializationException;
@@ -20,14 +21,19 @@ import java.util.Objects;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Logger; 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 @Override
public @NotNull Class<PlayerLoginEvent> eventType() { public @NotNull Class<AsyncPlayerConfigurationEvent> eventType() {
return PlayerLoginEvent.class; return AsyncPlayerConfigurationEvent.class;
} }
@Override @Override
public @NotNull Result run(@NotNull PlayerLoginEvent event) { public @NotNull Result run(@NotNull AsyncPlayerConfigurationEvent event) {
Player p = event.getPlayer(); Player p = event.getPlayer();
Transfer transferInstance = new Transfer(); Transfer transferInstance = new Transfer();
@@ -38,13 +44,14 @@ public class PlayerLoginHandler implements EventListener<PlayerLoginEvent> {
MinecraftServer.getSchedulerManager().scheduleTask( MinecraftServer.getSchedulerManager().scheduleTask(
() -> { () -> {
p.setTeam(globalTeam);
if(pushQueue != null) { if(pushQueue != null) {
Room.setRoom(p, Room.getRoom(pushQueue).orElseThrow()); Room.setRoom(p, Room.getRoom(pushQueue).orElseThrow());
} else { } else {
MoveInstance.move(p, Hub.INSTANCE); MoveInstance.move(p, Hub.INSTANCE);
} }
}, },
TaskSchedule.seconds(5), TaskSchedule.seconds(1),
TaskSchedule.stop() TaskSchedule.stop()
); );
@@ -52,14 +59,13 @@ public class PlayerLoginHandler implements EventListener<PlayerLoginEvent> {
try { try {
if(Objects.requireNonNull(Main.globalConfig.node("admins").getList(String.class)).stream().anyMatch(s -> s.equalsIgnoreCase(p.getUsername()))) { 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) {
} }
} catch (SerializationException | NullPointerException ignored) {}
Logger.getLogger("user").info(p.getUsername() + " joined"); Logger.getLogger("user").info(p.getUsername() + " joined");
// new ChatMessage(Icon.SCIENCE).appendStatic("unübersetzter Jointext: ").appendStatic(p.getUsername()).send(MinecraftServer.getConnectionManager().getOnlinePlayers());
return Result.SUCCESS; return Result.SUCCESS;
} }
} }

View File

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

View File

@@ -7,17 +7,18 @@ import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent; import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
import net.minestom.server.instance.Instance; import net.minestom.server.instance.Instance;
import net.minestom.server.instance.InstanceContainer; import net.minestom.server.instance.InstanceContainer;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
import java.util.UUID; import java.util.UUID;
public class MineNetInstance extends InstanceContainer { public class MineNetInstance extends InstanceContainer {
public MineNetInstance(DimensionType type) { public MineNetInstance(DynamicRegistry.Key<DimensionType> type) {
super(UUID.randomUUID(), type); super(UUID.randomUUID(), type);
MinecraftServer.getInstanceManager().registerInstance(this); MinecraftServer.getInstanceManager().registerInstance(this);
eventNode() this.eventNode()
.addListener(AddEntityToInstanceEvent.class, this::onEntityAdd) .addListener(AddEntityToInstanceEvent.class, this::onEntityAdd)
.addListener(RemoveEntityFromInstanceEvent.class, this::onEntityRemove); .addListener(RemoveEntityFromInstanceEvent.class, this::onEntityRemove);
} }
@@ -36,6 +37,7 @@ public class MineNetInstance extends InstanceContainer {
/** /**
* Called when Player joins this instance * Called when Player joins this instance
*
* @param p player who is joining * @param p player who is joining
* @return setCanceled * @return setCanceled
*/ */
@@ -45,18 +47,15 @@ public class MineNetInstance extends InstanceContainer {
/** /**
* Called when Player leaves this instance * Called when Player leaves this instance
*
* @param p player who is leaving * @param p player who is leaving
*/ */
protected void onPlayerLeave(Player p) { protected void onPlayerLeave(Player p) {
} }
/**
*
* @param target
*/
public void destroy(Instance target) { public void destroy(Instance target) {
getPlayers().forEach(player -> { this.getPlayers().forEach(player -> {
if(target != null) if(target != null)
player.setInstance(target); player.setInstance(target);
else else

View File

@@ -1,14 +1,14 @@
package eu.mhsl.minenet.minigames.instance.game; package eu.mhsl.minenet.minigames.instance.game;
import eu.mhsl.minenet.minigames.instance.MineNetInstance; import eu.mhsl.minenet.minigames.instance.MineNetInstance;
import eu.mhsl.minenet.minigames.instance.Spawnable;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.GameFactory; 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.Option;
import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.Icon; import eu.mhsl.minenet.minigames.message.Icon;
import eu.mhsl.minenet.minigames.message.type.ChatMessage; import eu.mhsl.minenet.minigames.message.type.ChatMessage;
import eu.mhsl.minenet.minigames.score.Score; import eu.mhsl.minenet.minigames.score.Score;
import eu.mhsl.minenet.minigames.util.CommonEventHandles; import eu.mhsl.minenet.minigames.util.CommonEventHandles;
import eu.mhsl.minenet.minigames.instance.Spawnable;
import eu.mhsl.minenet.minigames.instance.room.Room;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
@@ -16,6 +16,7 @@ import net.minestom.server.event.item.ItemDropEvent;
import net.minestom.server.event.player.PlayerBlockBreakEvent; import net.minestom.server.event.player.PlayerBlockBreakEvent;
import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.event.player.PlayerBlockPlaceEvent;
import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.timer.ExecutionType; import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
@@ -27,69 +28,72 @@ import java.util.concurrent.CompletableFuture;
import java.util.logging.Logger; import java.util.logging.Logger;
public abstract class Game extends MineNetInstance implements Spawnable { public abstract class Game extends MineNetInstance implements Spawnable {
protected final Random rnd = new Random();
protected final Logger logger;
protected Room parentRoom; protected Room parentRoom;
protected boolean isRunning = false; protected boolean isRunning = false;
protected boolean isBeforeBeginning = true; protected boolean isBeforeBeginning = true;
protected final Random rnd = new Random(); //TODO better way than ths? public Game(DynamicRegistry.Key<DimensionType> dimensionType) {
protected final Logger logger;
public Game(DimensionType dimensionType) {
super(dimensionType); super(dimensionType);
MinecraftServer.getInstanceManager().registerInstance(this); MinecraftServer.getInstanceManager().registerInstance(this);
logger = Logger.getLogger("Game:" + getUniqueId()); this.logger = Logger.getLogger("Game:" + this.getUuid());
eventNode() this.eventNode()
.addListener(PlayerMoveEvent.class, this::onPlayerMove) .addListener(PlayerMoveEvent.class, this::onPlayerMove)
.addListener(PlayerBlockBreakEvent.class, this::onBlockBreak) .addListener(PlayerBlockBreakEvent.class, this::onBlockBreak)
.addListener(PlayerBlockPlaceEvent.class, this::onBlockPlace) .addListener(PlayerBlockPlaceEvent.class, this::onBlockPlace)
.addListener(ItemDropEvent.class, this::onItemDrop); .addListener(ItemDropEvent.class, this::onItemDrop);
} }
public static void initialize(GameFactory factory, List<Option<?>> options, Player owner) {
try {
Room originRoom = Room.getRoom(owner).orElseThrow();
Game game = factory.manufacture(originRoom, options);
game.load();
originRoom.moveMembersToInstance(game);
new ChatMessage(Icon.INFO)
.appendTranslated(factory.name())
.newLine()
.appendTranslated(factory.description())
.send(originRoom.getAllMembers());
} catch(Exception e) {
new ChatMessage(Icon.ERROR).appendStatic("Instance crashed: " + e.getMessage()).send(owner);
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> Room.getRoom(owner).orElseThrow().moveMembersToRoomLobby());
e.printStackTrace(System.err);
}
}
public Game setParent(Room parentRoom) { public Game setParent(Room parentRoom) {
this.parentRoom = parentRoom; this.parentRoom = parentRoom;
return this; return this;
} }
public static void initialize(GameFactory factory, List<Option<?>> options, Player owner) {
try {
Game game = factory.manufacture(Room.getRoom(owner).orElseThrow(), options);
game.load();
Room.getRoom(owner).orElseThrow().moveMembersToInstance(game);
} catch (Exception e) {
new ChatMessage(Icon.ERROR).appendStatic("Instance crashed: " + e.getMessage()).send(owner);
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> Room.getRoom(owner).orElseThrow().moveMembersToRoomLobby());
e.printStackTrace(System.err);
}
}
/** /**
* Load and start countdown * Load and start countdown
*/ */
public void load() { public void load() {
scheduler().submitTask(() -> { this.scheduler().submitTask(() -> {
CompletableFuture<Void> callback = new CompletableFuture<>(); CompletableFuture<Void> callback = new CompletableFuture<>();
this.onLoad(callback); this.onLoad(callback);
// callback.whenComplete((unused, throwable) -> this.start()); // callback.whenComplete((unused, throwable) -> this.start());
return TaskSchedule.stop(); return TaskSchedule.stop();
}, ExecutionType.ASYNC); }, ExecutionType.TICK_END);
} }
protected void start() { protected void start() {
isRunning = true; this.isRunning = true;
isBeforeBeginning = false; this.isBeforeBeginning = false;
this.onStart(); this.onStart();
} }
public void stop() { public void stop() {
isRunning = false; this.isRunning = false;
this.onStop(); this.onStop();
this.unload(); this.unload();
} }
@@ -97,12 +101,12 @@ public abstract class Game extends MineNetInstance implements Spawnable {
public void unload() { public void unload() {
this.onUnload(); this.onUnload();
getPlayers().forEach(Room::setOwnRoom); this.getPlayers().forEach(Room::setOwnRoom);
scheduler().scheduleTask(() -> { this.scheduler().scheduleTask(() -> {
logger.info("stopping game instance " + this.uniqueId); this.logger.info("stopping game instance " + this.uuid);
getPlayers().forEach(player -> player.kick("timeout")); this.getPlayers().forEach(player -> player.kick("timeout"));
MinecraftServer.getInstanceManager().unregisterInstance(this); MinecraftServer.getInstanceManager().unregisterInstance(this);
@@ -113,10 +117,14 @@ public abstract class Game extends MineNetInstance implements Spawnable {
callback.complete(null); callback.complete(null);
} }
protected void onStart() {} protected void onStart() {
protected void onStop() {} }
protected void onUnload() {}
protected void onStop() {
}
protected void onUnload() {
}
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
@@ -140,7 +148,7 @@ public abstract class Game extends MineNetInstance implements Spawnable {
} }
protected void checkAbandoned() { protected void checkAbandoned() {
scheduleNextTick((instance) -> { this.scheduleNextTick((instance) -> {
if(instance.getPlayers().isEmpty()) this.unload(); if(instance.getPlayers().isEmpty()) this.unload();
}); });
} }
@@ -150,10 +158,10 @@ public abstract class Game extends MineNetInstance implements Spawnable {
} }
public boolean isRunning() { public boolean isRunning() {
return isRunning; return this.isRunning;
} }
public Pos getSpawn() { public Pos getSpawn() {
return new Pos(0,50,0); return new Pos(0, 50, 0);
} }
} }

View File

@@ -1,44 +1,64 @@
package eu.mhsl.minenet.minigames.instance.game; 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.config.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.acidRain.AcidRainFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun.AnvilRunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms.BackroomsFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms.BackroomsFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bedwars.BedwarsFactory; 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.blockBreakRace.BlockBreakRaceFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef.BowSpleefFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube.DeathcubeFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube.DeathcubeFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.elytraRace.ElytraRaceFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.fastbridge.FastbridgeFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.highGround.HighGroundFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.jumpDive.JumpDiveFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.minerun.MinerunFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.minerun.MinerunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.spaceSnake.SpaceSnakeFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.spleef.SpleefFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.spleef.SpleefFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.stickfight.StickFightFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.stickfight.StickFightFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.sumo.SumoFactory;
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.tntrun.TntRunFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.towerdefense.TowerdefenseFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.trafficlightrace.TrafficLightRaceFactory; import eu.mhsl.minenet.minigames.instance.game.stateless.types.trafficlightrace.TrafficLightRaceFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.types.turtleGame.TurtleGameFactory;
public enum GameList { public enum GameList {
DEATHCUBE(new DeathcubeFactory(), GameType.JUMPNRUN), DEATHCUBE(new DeathcubeFactory(), GameType.JUMPNRUN),
STICKFIGHT(new StickFightFactory(), GameType.PVP),
MINERUN(new MinerunFactory(), GameType.JUMPNRUN), MINERUN(new MinerunFactory(), GameType.JUMPNRUN),
TRAFFICLIGHTRACE(new TrafficLightRaceFactory(), GameType.OTHER), TRAFFICLIGHTRACE(new TrafficLightRaceFactory(), GameType.OTHER),
STICKFIGHT(new StickFightFactory(), GameType.PROTOTYPE),
TOWERDEFENSE(new TowerdefenseFactory(), GameType.PROTOTYPE), TOWERDEFENSE(new TowerdefenseFactory(), GameType.PROTOTYPE),
BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE), BEDWARS(new BedwarsFactory(), GameType.PROTOTYPE),
BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE), BACKROOMS(new BackroomsFactory(), GameType.PROTOTYPE),
BOWSPLEEF(new BowSpleefFactory(), GameType.PROTOTYPE),
TETRIS(new TetrisFactory(), GameType.OTHER),
TNTRUN(new TntRunFactory(), GameType.OTHER), TNTRUN(new TntRunFactory(), GameType.OTHER),
ANVILRUN(new AnvilRunFactory(), GameType.PVE),
ACIDRAIN(new AcidRainFactory(), GameType.PVE), ACIDRAIN(new AcidRainFactory(), GameType.PVE),
TURTLEGAME(new TurtleGameFactory(), GameType.PVE),
ELYTRARACE(new ElytraRaceFactory(), GameType.PVP), ELYTRARACE(new ElytraRaceFactory(), GameType.PVP),
SPLEEF(new SpleefFactory(), GameType.PVP), SPLEEF(new SpleefFactory(), GameType.PVP),
BOWSPLEEF(new BowSpleefFactory(), GameType.PVP); JUMPDIVE(new JumpDiveFactory(), GameType.JUMPNRUN),
SUMO(new SumoFactory(), GameType.PVP),
HIGHGROUND(new HighGroundFactory(), GameType.PVP),
FASTBRIDGE(new FastbridgeFactory(), GameType.OTHER),
BLOCKBREAKRACE(new BlockBreakRaceFactory(), GameType.OTHER),
SPACESNAKE(new SpaceSnakeFactory(), GameType.PVP);
private final GameFactory factory; private final GameFactory factory;
private final GameType type; private final GameType type;
GameList(GameFactory factory, GameType type) { GameList(GameFactory factory, GameType type) {
this.factory = factory; this.factory = factory;
this.type = type; this.type = type;
} }
public GameFactory getFactory() { public GameFactory getFactory() {
return this.factory; return this.factory;
} }
public GameType getType() { public GameType getType() {
return type; return this.type;
} }
} }

View File

@@ -22,15 +22,15 @@ public enum GameType {
} }
public Material getIcon() { public Material getIcon() {
return icon; return this.icon;
} }
public TranslatedComponent getTitle() { public TranslatedComponent getTitle() {
return title; return this.title;
} }
public TranslatedComponent getDescription() { public TranslatedComponent getDescription() {
return description; return this.description;
} }

View File

@@ -9,7 +9,9 @@ import eu.mhsl.minenet.minigames.score.Score;
import net.kyori.adventure.audience.Audience; import net.kyori.adventure.audience.Audience;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.registry.DynamicRegistry;
import net.minestom.server.timer.ExecutionType; import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.Task;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import net.minestom.server.world.DimensionType; import net.minestom.server.world.DimensionType;
@@ -19,10 +21,12 @@ import java.util.concurrent.CompletableFuture;
public class StatelessGame extends Game { public class StatelessGame extends Game {
private final String name; private final String name;
private final Score score; private final Score score;
private Task timeLimitTask;
private int timeLimit = 0; private int timeLimit = 0;
private int timePlayed = 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); super(dimensionType);
this.score = score; this.score = score;
this.name = gameName; this.name = gameName;
@@ -33,29 +37,36 @@ public class StatelessGame extends Game {
} }
public String getName() { public String getName() {
return name; return this.name;
} }
public void setTimeLimit(int limit) { public void setTimeLimit(int limit) {
this.timeLimit = limit; this.timeLimit = limit;
if(timeLimit > 0) { if(this.timeLimitTask != null) {
scheduler().submitTask(() -> { this.timeLimitTask.cancel();
if(!isRunning || timeLimit == 0) return TaskSchedule.stop(); this.timePlayed = 0;
if(timeLimit <= timePlayed) { }
stop(); if(this.timeLimit > 0) {
this.timeLimitTask = this.scheduler().submitTask(() -> {
if(!this.isRunning || this.timeLimit == 0) return TaskSchedule.stop();
if(this.timeLimit <= this.timePlayed) {
this.stop();
return TaskSchedule.stop(); return TaskSchedule.stop();
} }
int timeLeft = timeLimit - timePlayed; int timeLeft = this.timeLimit - this.timePlayed;
switch (timeLeft) { switch(timeLeft) {
case 60, 30, 10, 5, 4, 3, 2, 1 -> case 90, 60, 30, 10, 5, 4, 3, 2, 1 -> new ChatMessage(Icon.TIME)
new ChatMessage(Icon.SCIENCE).appendStatic("Noch " + timeLeft + " Sekunden!").send(getPlayers()); .appendStatic(String.valueOf(timeLeft))
.appendSpace()
.appendTranslated(timeLeft == 1 ? "common#secondsLeft_singular" : "common#secondsLeft_plural")
.send(this.getPlayers());
} }
timePlayed++; this.timePlayed++;
return TaskSchedule.seconds(1); return TaskSchedule.seconds(1);
}, ExecutionType.SYNC); }, ExecutionType.TICK_START);
} }
} }
@@ -69,37 +80,48 @@ public class StatelessGame extends Game {
* When overriding make sure to call this::start after countdown! * When overriding make sure to call this::start after countdown!
*/ */
protected CompletableFuture<Void> countdownStart() { protected CompletableFuture<Void> countdownStart() {
return new Countdown(TitleMessage.class) Duration fadeIn = Duration.ofMillis(300);
.countdown(Audience.audience(getPlayers()), 5, countdownModifier -> countdownModifier.message = new TitleMessage(Duration.ofMillis(300), Duration.ofMillis(700)) Duration stay = Duration.ofMillis(700);
.subtitle(subtitleMessage -> subtitleMessage.appendStatic(Component.text("in ", NamedTextColor.DARK_GREEN))
.appendStatic(Component.text(countdownModifier.timeLeft, NamedTextColor.GREEN))
.appendStatic(Component.text(" seconds", NamedTextColor.DARK_GREEN))));
}
return new Countdown()
.countdown(
Audience.audience(this.getPlayers()),
5,
modifier -> modifier.message = new TitleMessage(fadeIn, stay)
.subtitle(subtitleMessage -> subtitleMessage
.appendTranslated("common#startIn", NamedTextColor.DARK_GREEN)
.appendSpace()
.appendStatic(Component.text(modifier.timeLeft, NamedTextColor.GREEN))
.appendSpace()
.appendTranslated(modifier.timeLeft == 1 ? "common#second" : "common#seconds", NamedTextColor.DARK_GREEN)
)
);
}
public void startAccessor() { public void startAccessor() {
this.start(); this.start();
} }
@Override @Override
protected void start() { protected void start() {
score.setInstance(this); this.score.setInstance(this);
score.attachListeners(); this.score.attachListeners();
countdownStart().thenRun(super::start); this.countdownStart().thenRun(super::start);
} }
@Override @Override
public void stop() { public void stop() {
isRunning = false; this.isRunning = false;
this.onStop(); this.onStop();
getScore().insertRemainingPlayers(getPlayers()); this.getScore().insertRemainingPlayers(this.getPlayers());
this.publishScore(getScore()); this.publishScore(this.getScore());
countdownUnload(); this.countdownUnload();
} }
private void countdownUnload() { private void countdownUnload() {
new TitleMessage(Duration.ofSeconds(1)).appendTranslated("score#done").send(getPlayers()); new TitleMessage(Duration.ofSeconds(1)).appendTranslated("score#done").send(this.getPlayers());
scheduler().scheduleTask(this::unload, TaskSchedule.seconds(5), TaskSchedule.stop()); this.scheduler().scheduleTask(this::unload, TaskSchedule.seconds(5), TaskSchedule.stop());
} }
} }

View File

@@ -5,12 +5,12 @@ import java.util.ArrayList;
public class ConfigManager { public class ConfigManager {
private final ArrayList<Option<?>> items = new ArrayList<>(); private final ArrayList<Option<?>> items = new ArrayList<>();
public ConfigManager addOption(Option option) { public ConfigManager addOption(Option<?> option) {
items.add(option); this.items.add(option);
return this; return this;
} }
public ArrayList<Option<?>> getAll() { public ArrayList<Option<?>> getAll() {
return items; return this.items;
} }
} }

View File

@@ -4,15 +4,14 @@ import eu.mhsl.minenet.minigames.instance.game.Game;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.Restriction; import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.Restriction;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.RestrictionData; import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.RestrictionData;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.RestrictionHandler; import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.RestrictionHandler;
import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory; import eu.mhsl.minenet.minigames.shared.inventory.InteractableInventory;
import eu.mhsl.minenet.minigames.util.InventoryItemAlignment; import eu.mhsl.minenet.minigames.util.InventoryItemAlignment;
import eu.mhsl.minenet.minigames.instance.room.Room;
import net.kyori.adventure.sound.Sound; import net.kyori.adventure.sound.Sound;
import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.MinecraftServer; import net.minestom.server.MinecraftServer;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.EventListener;
import net.minestom.server.event.instance.AddEntityToInstanceEvent; import net.minestom.server.event.instance.AddEntityToInstanceEvent;
import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent; import net.minestom.server.event.instance.RemoveEntityFromInstanceEvent;
import net.minestom.server.inventory.InventoryType; import net.minestom.server.inventory.InventoryType;
@@ -45,9 +44,9 @@ public class GameConfigurationInventory extends InteractableInventory {
ConfigManager config = factory.configuration(); ConfigManager config = factory.configuration();
setClickableItem( this.setClickableItem(
ItemStack.builder(Material.RED_WOOL) ItemStack.builder(Material.RED_WOOL)
.displayName( .customName(
TranslatedComponent.byId("common#back") TranslatedComponent.byId("common#back")
.setColor(NamedTextColor.RED) .setColor(NamedTextColor.RED)
.getAssembled(p) .getAssembled(p)
@@ -58,29 +57,29 @@ public class GameConfigurationInventory extends InteractableInventory {
true true
); );
setDummyItem(Material.BLACK_STAINED_GLASS_PANE,1); this.setDummyItem(Material.BLACK_STAINED_GLASS_PANE, 1);
setDummyItem( this.setDummyItem(
ItemStack.builder(Material.NAME_TAG) ItemStack.builder(Material.NAME_TAG)
.displayName( .customName(
factory.name().setColor(NamedTextColor.GOLD).getAssembled(p) factory.name().setColor(NamedTextColor.GOLD).getAssembled(p)
) )
.build(), .build(),
4 4
); );
setDummyItem(Material.BLACK_STAINED_GLASS_PANE,7); this.setDummyItem(Material.BLACK_STAINED_GLASS_PANE, 7);
updatePlayButton(); this.updatePlayButton();
for(int i = 9; i <= 17; i++) { for(int i = 9; i <= 17; i++) {
setDummyItem(Material.BLACK_STAINED_GLASS_PANE, i); this.setDummyItem(Material.BLACK_STAINED_GLASS_PANE, i);
} }
if(config == null) { if(config == null) {
setDummyItem( this.setDummyItem(
ItemStack.builder(Material.BARRIER) ItemStack.builder(Material.BARRIER)
.displayName( .customName(
TranslatedComponent.byId("room#noOption").setColor(NamedTextColor.RED).getAssembled(p) TranslatedComponent.byId("room#noOption").setColor(NamedTextColor.RED).getAssembled(p)
) )
.lore( .lore(
@@ -95,9 +94,9 @@ public class GameConfigurationInventory extends InteractableInventory {
InventoryItemAlignment itemAlignment = new InventoryItemAlignment(config.getAll().size(), 3); InventoryItemAlignment itemAlignment = new InventoryItemAlignment(config.getAll().size(), 3);
for(Option<?> item : config.getAll()) { for(Option<?> item : config.getAll()) {
InventoryItemAlignment.ItemOffset current = itemAlignment.next(); InventoryItemAlignment.ItemOffset current = itemAlignment.next();
map.put(offset + current.get(), item); this.map.put(offset + current.get(), item);
setDummyItem( this.setDummyItem(
item.getCurrent(p), item.getCurrent(p),
offset + current.get() offset + current.get()
); );
@@ -110,50 +109,50 @@ public class GameConfigurationInventory extends InteractableInventory {
protected void onClick(Player player, int slot, ClickType clickType, InventoryConditionResult inventoryConditionResult) { protected void onClick(Player player, int slot, ClickType clickType, InventoryConditionResult inventoryConditionResult) {
inventoryConditionResult.setCancel(true); inventoryConditionResult.setCancel(true);
if(!map.containsKey(slot)) return; if(!this.map.containsKey(slot)) return;
Option<?> item = map.get(slot); Option<?> item = this.map.get(slot);
setDummyItem( this.setDummyItem(
item.getNext(p), item.getNext(this.p),
slot slot
); );
update(); this.update();
} }
private void updatePlayButton() { private void updatePlayButton() {
RestrictionHandler restrictionHandler = factory.globalRestrictions(); RestrictionHandler restrictionHandler = this.factory.globalRestrictions();
RestrictionData restrictionData = new RestrictionData(room); RestrictionData restrictionData = new RestrictionData(this.room);
if(restrictionHandler.canPlay(restrictionData)) { if(restrictionHandler.canPlay(restrictionData)) {
setClickableItem( this.setClickableItem(
ItemStack.builder(restrictionHandler.getWarnings(restrictionData).size() > 0 ? Material.YELLOW_WOOL : Material.GREEN_WOOL) ItemStack.builder(!restrictionHandler.getWarnings(restrictionData).isEmpty() ? 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(this.p))
.lore(restrictionHandler.getWarnings(restrictionData).stream().map(translatedComponent -> translatedComponent.getAssembled(p)).collect(Collectors.toList())) .lore(restrictionHandler.getWarnings(restrictionData).stream().map(translatedComponent -> translatedComponent.getAssembled(this.p)).collect(Collectors.toList()))
.build(), .build(),
8, 8,
itemClick -> Game.initialize(factory, map.values().stream().toList(), itemClick.getPlayer()), itemClick -> Game.initialize(this.factory, this.map.values().stream().toList(), itemClick.getPlayer()),
true true
); );
} else { } else {
setClickableItem( this.setClickableItem(
ItemStack.builder(Material.RED_WOOL) ItemStack.builder(Material.RED_WOOL)
.displayName(TranslatedComponent.byId("restriction#fail").setColor(NamedTextColor.RED).getAssembled(p)) .customName(TranslatedComponent.byId("restriction#fail").setColor(NamedTextColor.RED).getAssembled(this.p))
.lore( .lore(
restrictionHandler.getRestrictions() restrictionHandler.getRestrictions()
.stream() .stream()
.filter(iRestriction -> iRestriction.calculate(restrictionData).type().equals(Restriction.Type.FAIL)) .filter(iRestriction -> iRestriction.calculate(restrictionData).type().equals(Restriction.Type.FAIL))
.map(iRestriction -> iRestriction.calculate(restrictionData).description().getAssembled(p)) .map(iRestriction -> iRestriction.calculate(restrictionData).description().getAssembled(this.p))
.collect(Collectors.toList())) .collect(Collectors.toList()))
.build(), .build(),
8, 8,
itemClick -> { itemClick -> {
if(restrictionHandler.canPlay(restrictionData)) { if(restrictionHandler.canPlay(restrictionData)) {
updatePlayButton(); this.updatePlayButton();
return; return;
} }
itemClick.getPlayer().playSound(Sound.sound(SoundEvent.ENTITY_SILVERFISH_DEATH, Sound.Source.AMBIENT, 1f, 1f)); itemClick.getPlayer().playSound(Sound.sound(SoundEvent.ENTITY_SILVERFISH_DEATH, Sound.Source.AMBIENT, 1f, 1f));
@@ -163,6 +162,6 @@ public class GameConfigurationInventory extends InteractableInventory {
} }
update(); this.update();
} }
} }

View File

@@ -12,9 +12,11 @@ import java.util.Map;
public interface GameFactory { public interface GameFactory {
TranslatedComponent name(); TranslatedComponent name();
default ConfigManager configuration() { default ConfigManager configuration() {
return null; return null;
} }
default RestrictionHandler globalRestrictions() { default RestrictionHandler globalRestrictions() {
return new RestrictionHandler(); return new RestrictionHandler();
} }
@@ -22,6 +24,7 @@ public interface GameFactory {
default Material symbol() { default Material symbol() {
return Material.GRASS_BLOCK; return Material.GRASS_BLOCK;
} }
default TranslatedComponent description() { default TranslatedComponent description() {
return TranslatedComponent.byId("GameFactory#missingDescription"); return TranslatedComponent.byId("GameFactory#missingDescription");
} }
@@ -29,17 +32,17 @@ public interface GameFactory {
Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception; Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception;
default Game manufacture(Room parent, List<Option<?>> configuration) throws Exception { default Game manufacture(Room parent, List<Option<?>> configuration) throws Exception {
if(configuration == null) return manufacture(parent); if(configuration == null) return this.manufacture(parent);
Map<String, Option<?>> cnf = new HashMap<>(); Map<String, Option<?>> cnf = new HashMap<>();
configuration.forEach(option -> cnf.put(option.getId(), option)); configuration.forEach(option -> cnf.put(option.getId(), option));
return manufacture(parent, cnf); return this.manufacture(parent, cnf);
} }
default Game manufacture(Room parent) throws Exception { default Game manufacture(Room parent) throws Exception {
if(this.configuration() == null) return manufacture(parent, List.of()); if(this.configuration() == null) return this.manufacture(parent, List.of());
return manufacture(parent, this.configuration().getAll()); return this.manufacture(parent, this.configuration().getAll());
} }
} }

View File

@@ -9,14 +9,15 @@ import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import java.util.List; import java.util.List;
import java.util.Objects;
public abstract class Option<T> { public abstract class Option<T> {
private RestrictionHandler restrictionHandler;
private final Material item; private final Material item;
private final TranslatedComponent name; private final TranslatedComponent name;
private final String id; private final String id;
protected T currentValue;
private final List<T> options; private final List<T> options;
protected T currentValue;
private RestrictionHandler restrictionHandler;
private int pointer = 0; private int pointer = 0;
public Option(String id, Material item, TranslatedComponent name, List<T> options) { public Option(String id, Material item, TranslatedComponent name, List<T> options) {
@@ -25,42 +26,45 @@ public abstract class Option<T> {
this.name = name; this.name = name;
this.options = options; this.options = options;
currentValue = options.get(0); this.currentValue = options.getFirst();
}
public RestrictionHandler getRestrictionHandler() {
return this.restrictionHandler;
} }
public void setRestrictionHandler(RestrictionHandler restrictionHandler) { public void setRestrictionHandler(RestrictionHandler restrictionHandler) {
this.restrictionHandler = restrictionHandler; this.restrictionHandler = restrictionHandler;
} }
public RestrictionHandler getRestrictionHandler() {
return restrictionHandler;
}
public ItemStack getNext(Player p) { public ItemStack getNext(Player p) {
if(++pointer >= options.size()) pointer = 0; if(++this.pointer >= this.options.size()) this.pointer = 0;
currentValue = options.get(pointer); this.currentValue = this.options.get(this.pointer);
return getCurrent(p); return this.getCurrent(p);
} }
public ItemStack getCurrent(Player p) { public ItemStack getCurrent(Player p) {
int amount = Integer.parseInt(options.get(pointer).toString()); String value = this.options.get(this.pointer).toString();
return ItemStack.builder(item) return ItemStack.builder(this.item)
.displayName(name.getAssembled(p)) .customName(this.name.getAssembled(p))
.lore(TranslatedComponent.byId("optionCommon#value").setColor(NamedTextColor.GOLD).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(); .build();
} }
public int getAsInt() { public int getAsInt() {
return Integer.parseInt(getAsString()); return Integer.parseInt(this.getAsString());
}
public boolean getAsBoolean() {
return Objects.equals(this.getAsString(), "true") || Objects.equals(this.getAsString(), "1");
} }
public String getAsString() { public String getAsString() {
return currentValue.toString(); return this.currentValue.toString();
} }
public String getId() { public String getId() {
return id; return this.id;
} }
} }

View File

@@ -6,8 +6,8 @@ import net.minestom.server.item.Material;
import java.util.List; import java.util.List;
public class BoolOption extends Option<Boolean> { public class BoolOption extends Option<String> {
public BoolOption(String id, Material item, TranslatedComponent name) { 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

@@ -10,7 +10,7 @@ public record Restriction(TranslatedComponent name, TranslatedComponent descript
this.warnMessage = warnMessage; this.warnMessage = warnMessage;
this.type = type; this.type = type;
if (this.warnMessage == null && this.type.equals(Type.WARN)) { if(this.warnMessage == null && this.type.equals(Type.WARN)) {
throw new IllegalStateException("warnMessage cannot be null when RestrictionType is WARN"); throw new IllegalStateException("warnMessage cannot be null when RestrictionType is WARN");
} }
} }

View File

@@ -22,18 +22,18 @@ public class RestrictionHandler {
} }
public List<IRestriction> getRestrictions() { public List<IRestriction> getRestrictions() {
return restrictions; return this.restrictions;
} }
public boolean canPlay(RestrictionData data) { public boolean canPlay(RestrictionData data) {
if(restrictions.size() < 1) return true; if(this.restrictions.isEmpty()) return true;
return this.restrictions.stream() return this.restrictions.stream()
.noneMatch(iRestriction -> iRestriction.calculate(data).type().equals(Restriction.Type.FAIL)); .noneMatch(iRestriction -> iRestriction.calculate(data).type().equals(Restriction.Type.FAIL));
} }
public List<TranslatedComponent> getWarnings(RestrictionData data) { public List<TranslatedComponent> getWarnings(RestrictionData data) {
List<TranslatedComponent> warnings = new ArrayList<>(); List<TranslatedComponent> warnings = new ArrayList<>();
for (IRestriction r : this.restrictions) { for(IRestriction r : this.restrictions) {
Restriction calculated = r.calculate(data); Restriction calculated = r.calculate(data);
if(!calculated.type().equals(Restriction.Type.WARN)) continue; if(!calculated.type().equals(Restriction.Type.WARN)) continue;

View File

@@ -17,8 +17,8 @@ import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerTickEvent; import net.minestom.server.event.player.PlayerTickEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block; 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.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.timer.ExecutionType; import net.minestom.server.timer.ExecutionType;
import net.minestom.server.timer.TaskSchedule; import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -27,26 +27,26 @@ import java.util.concurrent.CompletableFuture;
public class AcidRain extends StatelessGame { public class AcidRain extends StatelessGame {
final private int radius = 20;
private int generationOffset = 0;
final private int roofHeight = 55;
private int difficulty = 0;
final JNoise noise = JNoise.newBuilder() final JNoise noise = JNoise.newBuilder()
.fastSimplex() .fastSimplex()
.setSeed(rnd.nextLong()) .setSeed(this.rnd.nextLong())
.setFrequency(0.09) .setFrequency(0.09)
.build(); .build();
final private int radius = 20;
final private int roofHeight = 55;
private int generationOffset = 0;
private int difficulty = 0;
public AcidRain() { public AcidRain() {
super(Dimension.OVERWORLD.DIMENSION, "acidRain", new LastWinsScore()); super(Dimension.OVERWORLD.key, "acidRain", new LastWinsScore());
setGenerator( this.setGenerator(
new CircularPlateTerrainGenerator(radius) new CircularPlateTerrainGenerator(this.radius)
.setPlateHeight(50) .setPlateHeight(50)
.setPlatePallet(BlockPallet.STONE) .setPlatePallet(BlockPallet.STONE)
); );
eventNode().addListener(PlayerTickEvent.class, this::onPlayerTick); this.eventNode().addListener(PlayerTickEvent.class, this::onPlayerTick);
} }
@Override @Override
@@ -61,39 +61,40 @@ public class AcidRain extends StatelessGame {
MinecraftServer.getSchedulerManager().submitTask(() -> { MinecraftServer.getSchedulerManager().submitTask(() -> {
getPlayers().forEach(player -> { this.getPlayers().forEach(player -> {
player.sendPacket(ParticleCreator.createParticlePacket(Particle.SNEEZE, 0, 60, 0, radius, radius, radius, 500)); player.sendPacket(new ParticlePacket(Particle.SNEEZE, 0, 60, 0, this.radius, this.radius, this.radius, 1f, 500));
player.sendPacket(ParticleCreator.createParticlePacket(Particle.ITEM_SLIME, 0, 60, 0, radius, radius, radius, 500)); player.sendPacket(new ParticlePacket(Particle.ITEM_SLIME, 0, 60, 0, this.radius, this.radius, this.radius, 1f, 500));
}); });
if(!isRunning) return TaskSchedule.stop(); if(!this.isRunning) return TaskSchedule.stop();
return TaskSchedule.millis(100); return TaskSchedule.millis(100);
}, ExecutionType.ASYNC); }, ExecutionType.TICK_END);
MinecraftServer.getSchedulerManager().submitTask(() -> { MinecraftServer.getSchedulerManager().submitTask(() -> {
generationOffset++; this.generationOffset++;
generatePlatform(generationOffset); this.generatePlatform(this.generationOffset);
if(!isRunning) return TaskSchedule.stop(); if(!this.isRunning) return TaskSchedule.stop();
return TaskSchedule.millis((long) NumberUtil.map(50 - difficulty, 0, 50, 100, 1000)); return TaskSchedule.millis((long) NumberUtil.map(50 - this.difficulty, 0, 50, 100, 1000));
}, ExecutionType.ASYNC); }, ExecutionType.TICK_END);
MinecraftServer.getSchedulerManager().submitTask(() -> { MinecraftServer.getSchedulerManager().submitTask(() -> {
difficulty++; this.difficulty++;
if(difficulty >= 50) return TaskSchedule.stop(); if(this.difficulty >= 50) return TaskSchedule.stop();
return TaskSchedule.seconds(3); return TaskSchedule.seconds(3);
}); });
} }
@Override @Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(playerMoveEvent.getNewPosition().y() < 50) playerDeath(playerMoveEvent.getPlayer()); if(playerMoveEvent.getNewPosition().y() < 50) this.playerDeath(playerMoveEvent.getPlayer());
} }
private void onPlayerTick(PlayerTickEvent playerTickEvent) { private void onPlayerTick(PlayerTickEvent playerTickEvent) {
if(isBeforeBeginning) return; if(this.isBeforeBeginning) return;
if(getBlock(playerTickEvent.getPlayer().getPosition().withY(roofHeight)).isAir()) playerDeath(playerTickEvent.getPlayer()); if(this.getBlock(playerTickEvent.getPlayer().getPosition().withY(this.roofHeight)).isAir())
this.playerDeath(playerTickEvent.getPlayer());
} }
private void generatePlatform(long offset) { private void generatePlatform(long offset) {
@@ -102,19 +103,20 @@ public class AcidRain extends StatelessGame {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = -radius; x <= radius; x++) { for(int x = -radius; x <= radius; x++) {
for(int z = -radius; z <= radius; z++) { for(int z = -radius; z <= radius; z++) {
batch.setBlock(x, roofHeight, z, Block.AIR); batch.setBlock(x, this.roofHeight, z, Block.AIR);
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue; if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue;
if(noise.getNoise(x + offset, z + offset) > 0.4) continue; if(this.noise.getNoise(x + offset, z + offset) > 0.4) continue;
batch.setBlock(x, roofHeight, z, Block.OAK_PLANKS); batch.setBlock(x, this.roofHeight, z, Block.OAK_PLANKS);
} }
} }
BatchUtil.loadAndApplyBatch(batch, this, () -> {}); BatchUtil.loadAndApplyBatch(batch, this, () -> {
});
} }
private void playerDeath(Player p) { private void playerDeath(Player p) {
p.setGameMode(GameMode.SPECTATOR); p.setGameMode(GameMode.SPECTATOR);
getScore().insertResult(p); this.getScore().insertResult(p);
} }
@Override @Override

View File

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

View File

@@ -0,0 +1,112 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.anvilRun;
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 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;
final int seconds;
final int anvilHeight = 200;
final List<Pos> anvilSpawnPositions = new ArrayList<>();
int anvilsPerSecond;
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));
this.eventNode().addListener(EntityTickEvent.class, this::onEntityTick);
}
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = -this.radius; x <= this.radius; x++) {
for(int z = -this.radius; z <= this.radius; z++) {
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > this.radius) continue;
this.anvilSpawnPositions.add(new Pos(x + 0.5, this.anvilHeight, z + 0.5));
batch.setBlock(x, this.spawnHeight - 1, z, Block.SNOW_BLOCK);
}
}
this.anvilsPerSecond = this.anvilSpawnPositions.size() / this.seconds;
Collections.shuffle(this.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(
() -> this.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(this.isBeforeBeginning && playerMoveEvent.getNewPosition().y() < this.spawnHeight - 2) {
playerMoveEvent.setCancelled(true);
playerMoveEvent.getPlayer().teleport(this.getSpawn());
return;
}
if(playerMoveEvent.getNewPosition().y() < this.spawnHeight - 2)
this.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() > this.spawnHeight + 0.5) return;
if(anvilPosition.y() < this.spawnHeight - 3) entityTickEvent.getEntity().remove();
if(this.getBlock(anvilPosition.withY(this.spawnHeight - 1)).isAir()) return;
this.setBlock(anvilPosition.withY(this.spawnHeight - 1), Block.AIR);
}
@Override
public Pos getSpawn() {
return new Pos(0, this.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.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 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.CLOCK, 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,9 +8,9 @@ import org.jetbrains.annotations.NotNull;
public class Backrooms extends StatelessGame { public class Backrooms extends StatelessGame {
public Backrooms() { public Backrooms() {
super(Dimension.NETHER.DIMENSION, "Backrooms", new NoScore()); super(Dimension.NETHER.key, "Backrooms", new NoScore());
BackroomsGenerator generator = new BackroomsGenerator(); BackroomsGenerator generator = new BackroomsGenerator();
setGenerator(unit -> generator.generateRoom(unit, 50)); this.setGenerator(unit -> generator.generateRoom(unit, 50));
} }
@Override @Override

View File

@@ -3,6 +3,7 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.backrooms;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.generator.GenerationUnit; import net.minestom.server.instance.generator.GenerationUnit;
import net.minestom.server.instance.generator.UnitModifier; import net.minestom.server.instance.generator.UnitModifier;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
public class BackroomsGenerator { public class BackroomsGenerator {
@@ -11,8 +12,8 @@ public class BackroomsGenerator {
var start = unit.absoluteStart(); var start = unit.absoluteStart();
var yPos = start.blockY() + y; var yPos = start.blockY() + y;
for (int x = 0; x < unit.size().blockX(); x++) { for(int x = 0; x < unit.size().blockX(); x++) {
for (int z = 0; z < unit.size().blockZ(); z++) { for(int z = 0; z < unit.size().blockZ(); z++) {
var xPos = start.blockX() + x; var xPos = start.blockX() + x;
var zPos = start.blockZ() + z; var zPos = start.blockZ() + z;
@@ -23,7 +24,7 @@ public class BackroomsGenerator {
modifier.setBlock(xPos, yPos + 4, zPos, Block.SMOOTH_STONE_SLAB); modifier.setBlock(xPos, yPos + 4, zPos, Block.SMOOTH_STONE_SLAB);
// idk man... dont ask about this // idk man... dont ask about this
if ( if(
(x - 2) % 4 == 0 && ( (x - 2) % 4 == 0 && (
((z - 2) % 8 == 0) || ((z - 2) % 8 == 0) ||
((z - 2) % 8 == 1) || ((z - 2) % 8 == 1) ||
@@ -36,14 +37,14 @@ public class BackroomsGenerator {
} }
} }
generateWalls(modifier, start.blockX() + 0, yPos + 1, start.blockZ() + 0); this.generateWalls(modifier, start.blockX(), yPos + 1, start.blockZ());
generateWalls(modifier, start.blockX() + 8, yPos + 1, start.blockZ() + 0); this.generateWalls(modifier, start.blockX() + 8, yPos + 1, start.blockZ());
generateWalls(modifier, start.blockX() + 0, yPos + 1, start.blockZ() + 8); this.generateWalls(modifier, start.blockX(), yPos + 1, start.blockZ() + 8);
generateWalls(modifier, start.blockX() + 8, yPos + 1, start.blockZ() + 8); this.generateWalls(modifier, start.blockX() + 8, yPos + 1, start.blockZ() + 8);
} }
private void generateWalls(UnitModifier modifier, int xPos, int yPos, int zPos) { private void generateWalls(UnitModifier modifier, int xPos, int yPos, int zPos) {
generatePillar(modifier, xPos, yPos, zPos, Block.CHISELED_SANDSTONE); this.generatePillar(modifier, xPos, yPos, zPos, Block.CHISELED_SANDSTONE);
var random = ThreadLocalRandom.current(); var random = ThreadLocalRandom.current();
@@ -55,31 +56,31 @@ public class BackroomsGenerator {
var door1pos = random.nextInt(2, 6); var door1pos = random.nextInt(2, 6);
var door2pos = random.nextInt(2, 6); var door2pos = random.nextInt(2, 6);
if (wall1) { if(wall1) {
for (int x = xPos; x < xPos + 8; x++) { for(int x = xPos; x < xPos + 8; x++) {
generatePillar(modifier, x, yPos, zPos, Block.SMOOTH_SANDSTONE); this.generatePillar(modifier, x, yPos, zPos, Block.SMOOTH_SANDSTONE);
} }
} }
if (wall2) { if(wall2) {
for (int z = zPos; z < zPos + 8; z++) { for(int z = zPos; z < zPos + 8; z++) {
generatePillar(modifier, xPos, yPos, z, Block.SMOOTH_SANDSTONE); this.generatePillar(modifier, xPos, yPos, z, Block.SMOOTH_SANDSTONE);
} }
} }
if (door1 && wall1) { if(door1 && wall1) {
generatePillar(modifier, xPos + door1pos, yPos, zPos, Block.AIR); this.generatePillar(modifier, xPos + door1pos, yPos, zPos, Block.AIR);
generatePillar(modifier, xPos + door1pos + 1, yPos, zPos, Block.AIR); this.generatePillar(modifier, xPos + door1pos + 1, yPos, zPos, Block.AIR);
} }
if (door2 && wall2) { if(door2 && wall2) {
generatePillar(modifier, xPos, yPos, zPos + door2pos, Block.AIR); this.generatePillar(modifier, xPos, yPos, zPos + door2pos, Block.AIR);
generatePillar(modifier, xPos, yPos, zPos + door2pos + 1, Block.AIR); this.generatePillar(modifier, xPos, yPos, zPos + door2pos + 1, Block.AIR);
} }
} }
private void generatePillar(UnitModifier modifier, int xPos, int yPos, int zPos, Block material) { private void generatePillar(UnitModifier modifier, int xPos, int yPos, int zPos, Block material) {
for (int y = yPos; y < yPos + 3; y++) { for(int y = yPos; y < yPos + 3; y++) {
modifier.setBlock(xPos, y, zPos, material); modifier.setBlock(xPos, y, zPos, material);
} }
} }

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.PlayerBlockBreakEvent;
import net.minestom.server.event.player.PlayerBlockPlaceEvent; import net.minestom.server.event.player.PlayerBlockPlaceEvent;
import net.minestom.server.event.player.PlayerMoveEvent; 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.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.timer.ExecutionType; import net.minestom.server.timer.ExecutionType;
@@ -29,7 +29,9 @@ import net.minestom.server.timer.TaskSchedule;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Bedwars extends StatelessGame { public class Bedwars extends StatelessGame {
@@ -38,14 +40,14 @@ public class Bedwars extends StatelessGame {
public Bedwars() throws IOException { 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"))); this.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()); Configuration config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(Resource.GAME_MAP.getPath().resolve("bedwars/test/config.yml").toFile());
List<String> teamNames = config.getStringList("setup.teams"); List<String> teamNames = config.getStringList("setup.teams");
teamNames.forEach(teamName -> { teamNames.forEach(teamName -> {
String path = "teams." + teamName; String path = "teams." + teamName;
teams.add(new BedwarsTeam( this.teams.add(new BedwarsTeam(
config.getString(path + ".name"), config.getString(path + ".name"),
Position.getPosFromCommaSeparated(config.getString(path + ".pos.spawn")), Position.getPosFromCommaSeparated(config.getString(path + ".pos.spawn")),
Position.getPosFromCommaSeparated(config.getString(path + ".pos.spawner")), Position.getPosFromCommaSeparated(config.getString(path + ".pos.spawner")),
@@ -54,7 +56,7 @@ public class Bedwars extends StatelessGame {
)); ));
}); });
eventNode().addListener(PickupItemEvent.class, pickupItemEvent -> { this.eventNode().addListener(PickupItemEvent.class, pickupItemEvent -> {
if(pickupItemEvent.getEntity() instanceof Player p) { if(pickupItemEvent.getEntity() instanceof Player p) {
p.getInventory().addItemStack(pickupItemEvent.getItemStack()); p.getInventory().addItemStack(pickupItemEvent.getItemStack());
} }
@@ -68,32 +70,33 @@ public class Bedwars extends StatelessGame {
@Override @Override
protected void onStart() { protected void onStart() {
scheduler().submitTask(() -> { this.scheduler().submitTask(() -> {
if(!isRunning) return TaskSchedule.stop(); if(!this.isRunning) return TaskSchedule.stop();
teams.forEach(bedwarsTeam -> { this.teams.forEach(bedwarsTeam -> {
ItemEntity item = new ItemEntity(ItemStack.of(bedwarsTeam.getBlock())); ItemEntity item = new ItemEntity(ItemStack.of(bedwarsTeam.getBlock()));
item.setNoGravity(true); item.setNoGravity(true);
item.setInstance(this, bedwarsTeam.getSpawner()); item.setInstance(this, bedwarsTeam.getSpawner());
}); });
return TaskSchedule.stop(); return TaskSchedule.stop();
}, ExecutionType.SYNC); }, ExecutionType.TICK_END);
} }
@Override @Override
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) { protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) {
placedBlocks.add(playerBlockPlaceEvent.getBlockPosition()); this.placedBlocks.add(playerBlockPlaceEvent.getBlockPosition());
} }
@Override @Override
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent playerBlockBreakEvent) { protected void onBlockBreak(@NotNull PlayerBlockBreakEvent playerBlockBreakEvent) {
if(!placedBlocks.contains(playerBlockBreakEvent.getBlockPosition())) playerBlockBreakEvent.setCancelled(true); if(!this.placedBlocks.contains(playerBlockBreakEvent.getBlockPosition()))
playerBlockBreakEvent.setCancelled(true);
teams.forEach(bedwarsTeam -> { this.teams.forEach(bedwarsTeam -> {
if(Arrays.stream(bedwarsTeam.getBed()).anyMatch(pos -> pos.sameBlock(playerBlockBreakEvent.getBlockPosition()))) if(Arrays.stream(bedwarsTeam.getBed()).anyMatch(pos -> pos.sameBlock(playerBlockBreakEvent.getBlockPosition())))
breakBed(bedwarsTeam); this.breakBed(bedwarsTeam);
}); });
if(playerBlockBreakEvent.isCancelled()) if(playerBlockBreakEvent.isCancelled())
@@ -102,13 +105,13 @@ public class Bedwars extends StatelessGame {
@Override @Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(playerMoveEvent.getNewPosition().y() < 0) death(playerMoveEvent.getPlayer()); if(playerMoveEvent.getNewPosition().y() < 0) this.death(playerMoveEvent.getPlayer());
} }
private void breakBed(BedwarsTeam team) { private void breakBed(BedwarsTeam team) {
team.removeBed(); team.removeBed();
for (Pos blockPos : team.getBed()) { for(Pos blockPos : team.getBed()) {
setBlock(blockPos, Material.AIR.block()); this.setBlock(blockPos, Material.AIR.block());
} }
} }

View File

@@ -8,16 +8,12 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class BedwarsTeam { public class BedwarsTeam {
private List<Player> members = new ArrayList<>();
private final String name; private final String name;
private final Pos spawn; private final Pos spawn;
private final Pos spawner; private final Pos spawner;
private final Pos[] bed; private final Pos[] bed;
private final Material block; private final Material block;
private List<Player> members = new ArrayList<>();
private boolean hasBed = true; private boolean hasBed = true;
public BedwarsTeam(String name, Pos spawn, Pos spawner, Pos[] bed, Material block) { public BedwarsTeam(String name, Pos spawn, Pos spawner, Pos[] bed, Material block) {
@@ -33,11 +29,11 @@ public class BedwarsTeam {
} }
public boolean isHasBed() { public boolean isHasBed() {
return hasBed; return this.hasBed;
} }
public List<Player> getMembers() { public List<Player> getMembers() {
return members; return this.members;
} }
public void setMembers(List<Player> members) { public void setMembers(List<Player> members) {
@@ -45,22 +41,22 @@ public class BedwarsTeam {
} }
public String getName() { public String getName() {
return name; return this.name;
} }
public Pos getSpawn() { public Pos getSpawn() {
return spawn; return this.spawn;
} }
public Pos getSpawner() { public Pos getSpawner() {
return spawner; return this.spawner;
} }
public Pos[] getBed() { public Pos[] getBed() {
return bed; return this.bed;
} }
public Material getBlock() { public Material getBlock() {
return block; return this.block;
} }
} }

View File

@@ -0,0 +1,79 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerBlockBreakEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class BlockBreakRace extends StatelessGame {
private final int height;
private int spawnCount = 0;
public BlockBreakRace(int height) {
super(Dimension.OVERWORLD.key, "blockBreakRace", new FirstWinsScore());
this.height = height;
this.setGenerator(new BlockBreakRaceGenerator(height));
}
@Override
protected boolean onPlayerJoin(Player p) {
PlayerInventory inv = p.getInventory();
inv.addItemStack(ItemStack.of(Material.DIAMOND_PICKAXE));
inv.addItemStack(ItemStack.of(Material.DIAMOND_AXE));
inv.addItemStack(ItemStack.of(Material.DIAMOND_SHOVEL));
return super.onPlayerJoin(p);
}
@Override
protected void onStart() {
this.getPlayers().forEach(player -> player.setGameMode(GameMode.SURVIVAL));
}
@Override
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) {
List<Material> allowedMaterials = List.of(Material.STONE, Material.OAK_PLANKS, Material.DIRT);
if(!allowedMaterials.contains(event.getBlock().registry().material())) event.setCancelled(true);
if(this.isBeforeBeginning) event.setCancelled(true);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(this.isBeforeBeginning) return;
if(playerMoveEvent.getNewPosition().y() < BlockBreakRaceGenerator.BOTTOM_Y) {
Player player = playerMoveEvent.getPlayer();
this.getScore().insertResult(player);
player.setGameMode(GameMode.SPECTATOR);
player.getInventory().clear();
}
}
@Override
public Pos getSpawn() {
int idx = this.spawnCount++;
int cols = BlockBreakRaceGenerator.ROW_OFFSETS_X.length;
int rows = BlockBreakRaceGenerator.ROW_OFFSETS_Z.length;
int perChunk = cols * rows;
int zChunk = idx / perChunk;
int gridIndex = idx % perChunk;
int xIndex = gridIndex % cols;
int zIndex = gridIndex / cols;
int localX = BlockBreakRaceGenerator.ROW_OFFSETS_X[xIndex];
int localZ = BlockBreakRaceGenerator.ROW_OFFSETS_Z[zIndex];
int absZ = (zChunk * 16) + localZ;
return new Pos(localX, BlockBreakRaceGenerator.BOTTOM_Y + this.height + 1, absZ).add(0.5);
}
}

View File

@@ -0,0 +1,40 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace;
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 BlockBreakRaceFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_BlockBreakRace#name");
}
@Override
public Material symbol() {
return Material.DIAMOND_PICKAXE;
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_BlockBreakRace#description");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("height", Material.SCAFFOLDING, TranslatedComponent.byId("optionCommon#height"), 20, 30, 40, 50));
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new BlockBreakRace(configuration.get("height").getAsInt()).setParent(parent);
}
}

View File

@@ -0,0 +1,65 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.blockBreakRace;
import eu.mhsl.minenet.minigames.world.generator.featureEnriched.ValeGenerator;
import eu.mhsl.minenet.minigames.world.generator.terrain.BaseGenerator;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.instance.block.Block;
import net.minestom.server.instance.generator.GenerationUnit;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class BlockBreakRaceGenerator extends BaseGenerator {
public static final int BOTTOM_Y = 50;
public static final int[] ROW_OFFSETS_X = {4, 8, 12};
public static final int[] ROW_OFFSETS_Z = {4, 8, 12};
private static final Block[] FILL_BLOCKS = {
Block.STONE,
Block.DIRT,
Block.OAK_PLANKS
};
public final int TOP_Y;
private final Random random = ThreadLocalRandom.current();
public BlockBreakRaceGenerator(int height) {
this.TOP_Y = BOTTOM_Y + height;
ValeGenerator vale = new ValeGenerator();
vale.setXShiftMultiplier(i -> 0.5d);
vale.setHeightNoiseMultiplier(i -> 2);
vale.setXShiftOffset(i -> 40d);
this.addMixIn(vale);
this.addMixIn(unit -> {
if(unit.absoluteStart().chunkX() != 0) return;
for(int localX : ROW_OFFSETS_X) {
for(int localZ : ROW_OFFSETS_Z) {
final int absZ = unit.absoluteStart().blockZ() + localZ;
this.placeTube(unit, localX, absZ);
}
}
});
}
private void placeTube(GenerationUnit unit, int x, int z) {
for(int y = BOTTOM_Y; y < this.TOP_Y; y++) {
Block fill = FILL_BLOCKS[this.random.nextInt(FILL_BLOCKS.length)];
unit.modifier().fill(
new Pos(x, y, z),
new Pos(x, y, z).add(1),
fill
);
}
for(int dx = -1; dx <= 1; dx++) {
for(int dz = -1; dz <= 1; dz++) {
if(dx == 0 && dz == 0) continue; // Zentrum überspringen
unit.modifier().fill(
new Pos(x + dx, BOTTOM_Y, z + dz),
new Pos(x + dx, this.TOP_Y + 3, z + dz).add(1),
Block.BARRIER
);
}
}
}
}

View File

@@ -6,31 +6,24 @@ import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import eu.mhsl.minenet.minigames.score.LastWinsScore; import eu.mhsl.minenet.minigames.score.LastWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil; import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.util.GeneratorUtils; 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.Point;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.*; import net.minestom.server.entity.Entity;
import net.minestom.server.entity.metadata.arrow.ArrowMeta; import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.metadata.other.PrimedTntMeta; import net.minestom.server.entity.metadata.other.PrimedTntMeta;
import net.minestom.server.event.EventListener; import net.minestom.server.event.EventListener;
import net.minestom.server.event.item.ItemUpdateStateEvent; import net.minestom.server.event.entity.projectile.ProjectileCollideWithBlockEvent;
import net.minestom.server.event.player.PlayerItemAnimationEvent; import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block; 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.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.tag.Tag; 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 org.jetbrains.annotations.NotNull;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class BowSpleef extends StatelessGame { public class BowSpleef extends StatelessGame {
@@ -38,49 +31,50 @@ public class BowSpleef extends StatelessGame {
private static final Tag<Boolean> ARROW_FIRST_HIT = Tag.Boolean("ARROW_ALREADY_LIT"); private static final Tag<Boolean> ARROW_FIRST_HIT = Tag.Boolean("ARROW_ALREADY_LIT");
private final int radius = 30; private final int radius = 30;
private final int totalElevation = 50; private final int totalElevation = 50;
public BowSpleef() { public BowSpleef() {
super(Dimension.OVERWORLD.DIMENSION, "bowSpleef", new LastWinsScore()); super(Dimension.OVERWORLD.key, "bowSpleef", new LastWinsScore());
eventNode().addListener( // 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()
// );
this.eventNode().addListener(
EventListener EventListener
.builder(PlayerItemAnimationEvent.class) .builder(ProjectileCollideWithBlockEvent.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)
.handler(projectileBlockHitEvent -> { .handler(projectileBlockHitEvent -> {
CustomEntityProjectile projectile = projectileBlockHitEvent.getEntity(); Entity projectile = projectileBlockHitEvent.getEntity();
if(!projectile.getTag(ARROW_FIRST_HIT)) { if(!projectile.getTag(ARROW_FIRST_HIT)) {
projectile.remove(); projectile.remove();
return; return;
@@ -89,9 +83,9 @@ public class BowSpleef extends StatelessGame {
float radius = 0.5F; float radius = 0.5F;
Point arrowPos = projectile.getPosition(); Point arrowPos = projectile.getPosition();
GeneratorUtils.foreachXZ(arrowPos.add(radius), arrowPos.sub(radius), point -> { GeneratorUtils.foreachXZ(arrowPos.add(radius), arrowPos.sub(radius), point -> {
Point location = point.add(projectile.getVelocity().mul(0.04)).withY(totalElevation); Point location = point.add(projectile.getVelocity().mul(0.04)).withY(this.totalElevation);
if(!getBlock(location).isAir()) { if(!this.getBlock(location).isAir()) {
setBlock(location, Block.AIR); this.setBlock(location, Block.AIR);
Entity fallingTnt = new Entity(EntityType.TNT); Entity fallingTnt = new Entity(EntityType.TNT);
PrimedTntMeta fallingTntMeta = (PrimedTntMeta) fallingTnt.getEntityMeta(); PrimedTntMeta fallingTntMeta = (PrimedTntMeta) fallingTnt.getEntityMeta();
@@ -106,9 +100,9 @@ public class BowSpleef extends StatelessGame {
.build() .build()
); );
eventNode().addListener( this.eventNode().addListener(
EventListener EventListener
.builder(ProjectileHitEvent.ProjectileEntityHitEvent.class) .builder(ProjectileCollideWithEntityEvent.class)
.handler(projectileEntityHitEvent -> projectileEntityHitEvent.setCancelled(true)) .handler(projectileEntityHitEvent -> projectileEntityHitEvent.setCancelled(true))
.build() .build()
); );
@@ -118,11 +112,11 @@ public class BowSpleef extends StatelessGame {
@Override @Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) { protected void onLoad(@NotNull CompletableFuture<Void> callback) {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = -radius; x <= radius; x++) { for(int x = -this.radius; x <= this.radius; x++) {
for(int z = -radius; z <= radius; z++) { for(int z = -this.radius; z <= this.radius; z++) {
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue; if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > this.radius) continue;
batch.setBlock(x, totalElevation, z, Block.TNT); batch.setBlock(x, this.totalElevation, z, Block.TNT);
} }
} }
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null)); BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
@@ -130,14 +124,13 @@ public class BowSpleef extends StatelessGame {
@Override @Override
protected void onStart() { protected void onStart() {
getPlayers().forEach(player -> { this.getPlayers().forEach(player -> {
player.getInventory().setItemStack( player.getInventory().setItemStack(
0, 0,
ItemStack ItemStack
.builder(Material.BOW) .builder(Material.BOW)
.displayName(TranslatedComponent.byId("bow").getAssembled(player)) .customName(TranslatedComponent.byId("bow").getAssembled(player))
.meta(builder -> builder.enchantment(Enchantment.FLAME, (short) 1).build()) .glowing(true)
.meta(builder -> builder.hideFlag(ItemHideFlag.HIDE_ENCHANTS))
.build() .build()
); );
}); });
@@ -145,14 +138,14 @@ public class BowSpleef extends StatelessGame {
@Override @Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(playerMoveEvent.getNewPosition().y() < totalElevation) { if(playerMoveEvent.getNewPosition().y() < this.totalElevation) {
getScore().insertResult(playerMoveEvent.getPlayer()); this.getScore().insertResult(playerMoveEvent.getPlayer());
playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR); playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
} }
} }
@Override @Override
public Pos getSpawn() { public Pos getSpawn() {
return new Pos(0, totalElevation + 1, 0); return new Pos(0, this.totalElevation + 1, 0);
} }
} }

View File

@@ -3,6 +3,8 @@ package eu.mhsl.minenet.minigames.instance.game.stateless.types.bowSpleef;
import eu.mhsl.minenet.minigames.instance.game.Game; 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.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option; import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.RestrictionHandler;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.common.MinimalPlayeramountGameRestriction;
import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
@@ -12,7 +14,12 @@ import java.util.Map;
public class BowSpleefFactory implements GameFactory { public class BowSpleefFactory implements GameFactory {
@Override @Override
public TranslatedComponent name() { public TranslatedComponent name() {
return TranslatedComponent.byId(""); return TranslatedComponent.byId("game_BowSpleef#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_BowSpleef#description");
} }
@Override @Override
@@ -24,4 +31,10 @@ public class BowSpleefFactory implements GameFactory {
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception { public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new BowSpleef().setParent(parent); return new BowSpleef().setParent(parent);
} }
@Override
public RestrictionHandler globalRestrictions() {
return new RestrictionHandler()
.addRestriction(new MinimalPlayeramountGameRestriction(2));
}
} }

View File

@@ -1,15 +1,14 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube; package eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore; import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil; 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.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import io.github.bloepiloepi.pvp.config.AttackConfig; import io.github.togar2.pvp.feature.CombatFeatures;
import io.github.bloepiloepi.pvp.config.DamageConfig;
import io.github.bloepiloepi.pvp.config.PvPConfig;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -23,16 +22,17 @@ class Deathcube extends StatelessGame {
final int percentage; final int percentage;
public Deathcube(int radius, int height, int percentage, int pvpEnabled) { 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.radius = radius;
this.height = height + 49; this.height = height + 49;
this.percentage = percentage; this.percentage = percentage;
this.setGenerator(new CircularPlateTerrainGenerator(radius+10).setPlateHeight(50)); this.setGenerator(new CircularPlateTerrainGenerator(radius + 10).setPlateHeight(50));
if(pvpEnabled == 1) eventNode().addChild( if(pvpEnabled == 1) this.eventNode().addChild(
PvPConfig.emptyBuilder() CombatFeatures.empty()
.damage(DamageConfig.legacyBuilder().fallDamage(false)) .add(CombatFeatures.VANILLA_ATTACK)
.attack(AttackConfig.legacyBuilder().attackCooldown(true)) .add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build().createNode() .build().createNode()
); );
System.out.println(radius); System.out.println(radius);
@@ -42,12 +42,12 @@ class Deathcube extends StatelessGame {
protected void onLoad(@NotNull CompletableFuture<Void> callback) { protected void onLoad(@NotNull CompletableFuture<Void> callback) {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = -radius; x <= radius; x++) { for(int x = -this.radius; x <= this.radius; x++) {
for (int z = -radius; z <= radius; z++) { for(int z = -this.radius; z <= this.radius; z++) {
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue; if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > this.radius) continue;
for (int y = 49; y < height; y++) { for(int y = 49; y < this.height; y++) {
if(super.rnd.nextInt(1, 100) <= percentage) { if(super.rnd.nextInt(1, 100) <= this.percentage) {
batch.setBlock(x, y, z, BlockPallet.WOOD.rnd()); batch.setBlock(x, y, z, BlockPallet.WOOD.rnd());
} }
} }
@@ -60,12 +60,22 @@ class Deathcube extends StatelessGame {
@Override @Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
super.onPlayerMove(playerMoveEvent); super.onPlayerMove(playerMoveEvent);
if(isBeforeBeginning) if(playerMoveEvent.getNewPosition().y() > 51.5) playerMoveEvent.setCancelled(true); if(playerMoveEvent.getNewPosition().y() < 48) {
if(playerMoveEvent.getNewPosition().y() > height) getScore().insertResult(playerMoveEvent.getPlayer()); playerMoveEvent.setCancelled(true);
playerMoveEvent.getPlayer().teleport(this.getSpawn());
return;
}
if(this.isBeforeBeginning && playerMoveEvent.getNewPosition().y() > 51.5) {
playerMoveEvent.setCancelled(true);
return;
}
if(playerMoveEvent.getNewPosition().y() <= this.height) return;
this.getScore().insertResult(playerMoveEvent.getPlayer());
playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
} }
@Override @Override
public Pos getSpawn() { public Pos getSpawn() {
return new Pos(0, 50, 30); return new Pos(0, 50, -(this.radius + 5));
} }
} }

View File

@@ -1,9 +1,9 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube; package eu.mhsl.minenet.minigames.instance.game.stateless.types.deathcube;
import eu.mhsl.minenet.minigames.instance.game.Game; 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.GameFactory;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.Option; 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.game.stateless.config.common.NumericOption;
import eu.mhsl.minenet.minigames.instance.room.Room; import eu.mhsl.minenet.minigames.instance.room.Room;
import eu.mhsl.minenet.minigames.message.component.TranslatedComponent; import eu.mhsl.minenet.minigames.message.component.TranslatedComponent;
@@ -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("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("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("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,22 +17,26 @@ import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.coordinate.Point; import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec; import net.minestom.server.coordinate.Vec;
import net.minestom.server.entity.EquipmentSlot;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.player.*; import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerStartFlyingWithElytraEvent;
import net.minestom.server.event.player.PlayerStopFlyingWithElytraEvent;
import net.minestom.server.event.player.PlayerUseItemEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.item.ItemStack; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material; import net.minestom.server.item.Material;
import net.minestom.server.network.packet.server.play.ParticlePacket; import net.minestom.server.network.packet.server.play.ParticlePacket;
import net.minestom.server.particle.Particle; import net.minestom.server.particle.Particle;
import net.minestom.server.particle.ParticleCreator;
import net.minestom.server.sound.SoundEvent; import net.minestom.server.sound.SoundEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Random;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -40,6 +44,7 @@ public class ElytraRace extends StatelessGame {
private final ValeGenerator vale = new ValeGenerator(); private final ValeGenerator vale = new ValeGenerator();
private final int gameHeight = 0; private final int gameHeight = 0;
private final int seaLevel = -55;
private final int ringSpacing = 100; private final int ringSpacing = 100;
private final int ringCount; private final int ringCount;
@@ -47,82 +52,74 @@ public class ElytraRace extends StatelessGame {
private final Material resetMaterial = Material.RED_DYE; private final Material resetMaterial = Material.RED_DYE;
private final int boostMultiplier = 50; private final int boostMultiplier = 50;
private final Material ringMaterial = Material.GOLD_BLOCK; private final Material ringMaterial = Material.GOLD_BLOCK;
private final Map<Player, CheckPointData> playerCheckpoints = new HashMap<>();
private int generatedUntil = 0; private int generatedUntil = 0;
private record CheckPointData(int currentCheckpoint, int nextCheckpoint) {
public CheckPointData next(int spacing) {
return new CheckPointData(nextCheckpoint, nextCheckpoint + spacing);
}
}
private final Map<Player, CheckPointData> playerCheckpoints = new HashMap<>();
public ElytraRace(int ringCount) { public ElytraRace(int ringCount) {
super(Dimension.OVERWORLD.DIMENSION, "ElytraRace", new FirstWinsScore()); super(Dimension.OVERWORLD.key, "ElytraRace", new FirstWinsScore());
this.ringCount = ringCount; this.ringCount = ringCount;
setGenerator(vale); this.setGenerator(this.vale);
vale.setCalculateSeaLevel(point -> -55); this.vale.setCalculateSeaLevel(point -> this.seaLevel);
vale.setXShiftMultiplier(integer -> NumberUtil.map(integer, 50, 500, 0, 1)); this.vale.setXShiftMultiplier(integer -> NumberUtil.map(integer, 50, 500, 0, 1));
vale.addMixIn(new PlaneTerrainGenerator(gameHeight, Block.BARRIER)); this.vale.addMixIn(new PlaneTerrainGenerator(this.gameHeight, Block.BARRIER));
eventNode().addListener(PlayerUseItemEvent.class, playerUseItemEvent -> { this.eventNode().addListener(PlayerUseItemEvent.class, playerUseItemEvent -> {
Player player = playerUseItemEvent.getPlayer(); Player player = playerUseItemEvent.getPlayer();
Material usedMaterial = playerUseItemEvent.getItemStack().material(); Material usedMaterial = playerUseItemEvent.getItemStack().material();
if(usedMaterial.equals(boostMaterial)) { if(usedMaterial.equals(this.boostMaterial)) {
if(!player.isFlyingWithElytra()) return; if(!player.isFlyingWithElytra()) return;
boost(player); this.boost(player);
InventoryUtil.removeItemFromPlayer(player, boostMaterial, 1); InventoryUtil.removeItemFromPlayer(player, this.boostMaterial, 1);
} else if(usedMaterial.equals(resetMaterial)) { } else if(usedMaterial.equals(this.resetMaterial)) {
toCheckpoint(player); this.toCheckpoint(player);
InventoryUtil.removeItemFromPlayer(player, resetMaterial, 1); InventoryUtil.removeItemFromPlayer(player, this.resetMaterial, 1);
} }
}); });
eventNode().addListener(PlayerStopFlyingWithElytraEvent.class, playerStopFlyingWithElytraEvent -> { this.eventNode().addListener(PlayerStopFlyingWithElytraEvent.class, playerStopFlyingWithElytraEvent -> {
Player player = playerStopFlyingWithElytraEvent.getPlayer(); Player player = playerStopFlyingWithElytraEvent.getPlayer();
if(Position.blocksBelowPlayer(this, player).contains(ringMaterial.block())) { if(Position.blocksBelowPlayer(this, player).contains(this.ringMaterial.block())) {
player.setFlyingWithElytra(true); player.setFlyingWithElytra(true);
boost(player); this.boost(player);
} else { } else {
toCheckpoint(player); this.toCheckpoint(player);
// getScore().insertResult(playerStopFlyingWithElytraEvent.getPlayer()); // getScore().insertResult(playerStopFlyingWithElytraEvent.getPlayer());
// playerStopFlyingWithElytraEvent.getPlayer().setGameMode(GameMode.SPECTATOR); // playerStopFlyingWithElytraEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
} }
}); });
eventNode().addListener(PlayerStartFlyingWithElytraEvent.class, playerStartFlyingWithElytraEvent -> { this.eventNode().addListener(PlayerStartFlyingWithElytraEvent.class, playerStartFlyingWithElytraEvent -> {
if(!isRunning) { if(!this.isRunning) {
playerStartFlyingWithElytraEvent.getPlayer().setFlyingWithElytra(false); playerStartFlyingWithElytraEvent.getPlayer().setFlyingWithElytra(false);
return; return;
} }
boost(playerStartFlyingWithElytraEvent.getPlayer()); this.boost(playerStartFlyingWithElytraEvent.getPlayer());
}); });
} }
@Override @Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) { protected void onLoad(@NotNull CompletableFuture<Void> callback) {
Point spawnpoint = new Pos(vale.getXShiftAtZ(0), -46, 0); Point spawnpoint = new Pos(this.vale.getXShiftAtZ(0), -46, 0);
GeneratorUtils.iterateArea(spawnpoint.sub(2, 0, 2), spawnpoint.add(2, 0, 2), point -> { GeneratorUtils.iterateArea(spawnpoint.sub(5, 0, 5), spawnpoint.add(5, 0, 5), point -> this.setBlock(point, BlockPallet.STREET.rnd()));
setBlock(point, BlockPallet.STREET.rnd());
});
generateRing(ringSpacing); this.generateRing(this.ringSpacing);
generateRing(ringSpacing * 2); this.generateRing(this.ringSpacing * 2);
callback.complete(null); callback.complete(null);
} }
@Override @Override
protected void onStart() { protected void onStart() {
getPlayers().forEach(player -> { this.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++) { 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(this.boostMaterial).customName(TranslatedComponent.byId("boost").getAssembled(player)).build());
} }
addResetItemToPlayer(player); this.addResetItemToPlayer(player);
}); });
} }
@@ -131,72 +128,80 @@ public class ElytraRace extends StatelessGame {
Player player = playerMoveEvent.getPlayer(); Player player = playerMoveEvent.getPlayer();
Point newPos = playerMoveEvent.getNewPosition(); Point newPos = playerMoveEvent.getNewPosition();
playerCheckpoints.putIfAbsent(player, new CheckPointData(ringSpacing, ringSpacing * 2)); if(this.isBeforeBeginning && playerMoveEvent.getNewPosition().y() < this.getSpawn().y()) {
player.teleport(this.getSpawn());
if(newPos.z() > generatedUntil - ringSpacing) { return;
generateRing(generatedUntil + ringSpacing);
} }
if(newPos.z() > playerCheckpoints.get(player).nextCheckpoint) { this.playerCheckpoints.putIfAbsent(player, new CheckPointData(this.ringSpacing, this.ringSpacing * 2));
playerCheckpoints.put(player, playerCheckpoints.get(player).next(ringSpacing));
boost(player); if(newPos.z() > this.generatedUntil - this.ringSpacing) {
this.generateRing(this.generatedUntil + this.ringSpacing);
} }
if(newPos.y() > gameHeight - 5) { if(newPos.z() > this.playerCheckpoints.get(player).nextCheckpoint) {
Point particlePoint = newPos.withY(gameHeight); this.playerCheckpoints.put(player, this.playerCheckpoints.get(player).next(this.ringSpacing));
ParticlePacket particle = ParticleCreator.createParticlePacket( this.boost(player);
}
if(newPos.y() > this.gameHeight - 5) {
Point particlePoint = newPos.withY(this.gameHeight);
ParticlePacket particle = new ParticlePacket(
Particle.WAX_ON, Particle.WAX_ON,
particlePoint.blockX(), particlePoint.blockX(),
particlePoint.blockY(), particlePoint.blockY(),
particlePoint.withZ(z -> z+10).blockZ(), particlePoint.withZ(z -> z + 10).blockZ(),
20, 20,
0, 0,
30, 30,
Math.toIntExact((long) NumberUtil.map(newPos.y(), gameHeight - 5, gameHeight, 50, 500)) 1f,
Math.toIntExact((long) NumberUtil.map(newPos.y(), this.gameHeight - 5, this.gameHeight, 50, 500))
); );
player.sendPacket(particle); player.sendPacket(particle);
} }
if(getBlock(player.getPosition()).equals(Block.WATER)) { if(this.getBlock(player.getPosition()).equals(Block.WATER)) {
toCheckpoint(player); this.toCheckpoint(player);
} }
if(newPos.z() > ringCount * ringSpacing) { if(newPos.z() > this.ringCount * this.ringSpacing) {
getScore().insertResult(player); this.getScore().insertResult(player);
player.setGameMode(GameMode.SPECTATOR); player.setGameMode(GameMode.SPECTATOR);
player.setFlyingWithElytra(false);
} }
} }
@Override @Override
public Pos getSpawn() { public Pos getSpawn() {
return new Pos(vale.getXShiftAtZ(0), -45, 0); return new Pos(this.vale.getXShiftAtZ(0), -45, 0);
} }
private void addResetItemToPlayer(Player p) { 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(this.resetMaterial).customName(TranslatedComponent.byId("reset").getAssembled(p)).build());
} }
private Point getRingPositionAtZ(int z) { private Point getRingPositionAtZ(int z) {
return new Pos(vale.getXShiftAtZ(z), -45, z); Random random = new Random(this.hashCode() + z);
return new Pos(this.vale.getXShiftAtZ(z), -45 + random.nextInt(-5, 15), z);
} }
private CompletableFuture<Void> generateRing(int zPos) { private void generateRing(int zPos) {
if(zPos > ringCount * ringSpacing) return null; if(zPos > this.ringCount * this.ringSpacing) return;
boolean isLast = (zPos == ringCount * ringSpacing); boolean isLast = (zPos == this.ringCount * this.ringSpacing);
generatedUntil = zPos; this.generatedUntil = zPos;
AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
Point ringPos = getRingPositionAtZ(zPos); Point ringPos = this.getRingPositionAtZ(zPos);
GeneratorUtils.iterateArea( GeneratorUtils.iterateArea(
ringPos.sub(100, 0, 0).withY(getDimensionType().getMinY()), ringPos.sub(100, 0, 0).withY(0),
ringPos.add(100, 0, 0).withY(gameHeight), ringPos.add(100, 0, 0).withY(this.seaLevel),
point -> batch.setBlock(point, Block.BARRIER) point -> batch.setBlock(point, Block.BARRIER)
); );
GeneratorUtils.iterateArea( GeneratorUtils.iterateArea(
ringPos.sub(3, 3, 0), ringPos.sub(3, 3, 0),
ringPos.add(3, 3, 0), ringPos.add(3, 3, 0),
point -> batch.setBlock(point, isLast ? Block.DIAMOND_BLOCK : ringMaterial.block()) point -> batch.setBlock(point, isLast ? Block.DIAMOND_BLOCK : this.ringMaterial.block())
); );
GeneratorUtils.iterateArea( GeneratorUtils.iterateArea(
ringPos.sub(2, 2, 0), ringPos.sub(2, 2, 0),
@@ -204,8 +209,8 @@ public class ElytraRace extends StatelessGame {
point -> batch.setBlock(point, Block.AIR) point -> batch.setBlock(point, Block.AIR)
); );
BatchUtil.loadAndApplyBatch(batch, this, () -> {}); BatchUtil.loadAndApplyBatch(batch, this, () -> {
return null; });
} }
private void boost(Player player) { private void boost(Player player) {
@@ -213,13 +218,13 @@ public class ElytraRace extends StatelessGame {
Vec playerVelocity = player.getPosition().direction(); Vec playerVelocity = player.getPosition().direction();
player.setVelocity( player.setVelocity(
player.getVelocity().add(playerVelocity.mul(boostMultiplier)) player.getVelocity().add(playerVelocity.mul(this.boostMultiplier))
.withY(playerVelocity.withY(v -> v * boostMultiplier).y()) .withY(playerVelocity.withY(v -> v * this.boostMultiplier).y())
); );
} }
private void toCheckpoint(Player p) { private void toCheckpoint(Player p) {
Point checkpointPos = getRingPositionAtZ(playerCheckpoints.get(p).currentCheckpoint); Point checkpointPos = this.getRingPositionAtZ(this.playerCheckpoints.get(p).currentCheckpoint);
p.setVelocity(Vec.ZERO); p.setVelocity(Vec.ZERO);
p.setFlyingWithElytra(false); p.setFlyingWithElytra(false);
p.teleport(Pos.fromPoint(checkpointPos).add(0.5, 0, 0.5)); p.teleport(Pos.fromPoint(checkpointPos).add(0.5, 0, 0.5));
@@ -227,7 +232,7 @@ public class ElytraRace extends StatelessGame {
p.setFlying(true); p.setFlying(true);
p.setFlyingSpeed(0); p.setFlyingSpeed(0);
new Countdown(TitleMessage.class) new Countdown()
.countdown( .countdown(
Audience.audience(p), Audience.audience(p),
3, 3,
@@ -239,16 +244,24 @@ public class ElytraRace extends StatelessGame {
.subtitle( .subtitle(
subtitleMessage -> subtitleMessage ->
subtitleMessage subtitleMessage
.appendStatic(Component.text("Launch in ", NamedTextColor.DARK_GREEN)) .appendTranslated("game_ElytraRace#launchIn")
.appendSpace()
.appendStatic(Component.text(countdownModifier.timeLeft, NamedTextColor.GREEN)) .appendStatic(Component.text(countdownModifier.timeLeft, NamedTextColor.GREEN))
.appendStatic(Component.text(" seconds", NamedTextColor.DARK_GREEN)) .appendSpace()
.appendTranslated(countdownModifier.timeLeft == 1 ? "common#second" : "common#seconds")
) )
).thenRun(() -> { ).thenRun(() -> {
p.setFlying(false); p.setFlying(false);
p.setFlyingSpeed(1); p.setFlyingSpeed(1);
p.setFlyingWithElytra(true); p.setFlyingWithElytra(true);
boost(p); this.boost(p);
addResetItemToPlayer(p); this.addResetItemToPlayer(p);
}); });
} }
private record CheckPointData(int currentCheckpoint, int nextCheckpoint) {
public CheckPointData next(int spacing) {
return new CheckPointData(this.nextCheckpoint, this.nextCheckpoint + spacing);
}
}
} }

View File

@@ -14,7 +14,12 @@ import java.util.Map;
public class ElytraRaceFactory implements GameFactory { public class ElytraRaceFactory implements GameFactory {
@Override @Override
public TranslatedComponent name() { public TranslatedComponent name() {
return TranslatedComponent.byId(""); return TranslatedComponent.byId("game_ElytraRace#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_ElytraRace#description");
} }
@Override @Override
@@ -25,7 +30,7 @@ public class ElytraRaceFactory implements GameFactory {
@Override @Override
public ConfigManager configuration() { public ConfigManager configuration() {
return new ConfigManager() 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 @Override

View File

@@ -0,0 +1,64 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.fastbridge;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.Chunk;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull;
public class Fastbridge extends StatelessGame {
private int currentSpawn = 0;
public Fastbridge() {
super(Dimension.OVERWORLD.key, "Fastbridge", new FirstWinsScore());
this.setGenerator(new FastbridgeChunkgenerator());
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
Player player = playerMoveEvent.getPlayer();
Pos newPos = playerMoveEvent.getNewPosition();
if(this.getScore().hasResult(player)) return;
if(newPos.y() < 0) {
player.teleport(this.getSpawn());
if(!this.isBeforeBeginning) this.resetPlayer(player);
}
if(newPos.x() > 53) {
this.getScore().insertResult(player);
player.setGameMode(GameMode.SPECTATOR);
}
}
@Override
protected void onStart() {
this.getPlayers().forEach(player -> {
player.setGameMode(GameMode.SURVIVAL);
this.resetPlayer(player);
});
}
@Override
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) {
if(this.isBeforeBeginning) playerBlockPlaceEvent.setCancelled(true);
}
private void resetPlayer(Player player) {
if(this.isBeforeBeginning) return;
PlayerInventory inventory = player.getInventory();
inventory.clear();
inventory.addItemStack(ItemStack.of(Material.WHITE_WOOL, 64));
}
@Override
public synchronized Pos getSpawn() {
return new Pos(24, 1, this.currentSpawn++ * Chunk.CHUNK_SIZE_Z * 2 - 8, -90, 0);
}
}

View File

@@ -0,0 +1,29 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.fastbridge;
import eu.mhsl.minenet.minigames.world.generator.featureEnriched.ValeGenerator;
import eu.mhsl.minenet.minigames.world.generator.terrain.BaseGenerator;
import net.minestom.server.instance.block.Block;
public class FastbridgeChunkgenerator extends BaseGenerator {
public FastbridgeChunkgenerator() {
this.addMixIn(unit -> {
if(unit.absoluteStart().chunkZ() % 2 == 0) {
unit.modifier().fill(Block.BARRIER);
return;
}
if(unit.absoluteStart().chunkX() != 1 && unit.absoluteStart().chunkX() != 3) return;
for(int x = 5; x <= 10; x++) {
for(int z = 5; z <= 10; z++) {
unit.modifier().setRelative(x, 64, z, unit.absoluteStart().chunkX() == 3 ? Block.GOLD_BLOCK : Block.GRASS_BLOCK);
}
}
});
ValeGenerator vale = new ValeGenerator();
vale.setXShiftMultiplier(integer -> 0.5d);
vale.setHeightNoiseMultiplier(integer -> 2);
vale.setXShiftOffset(integer -> 40d);
this.addMixIn(vale);
}
}

View File

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

View File

@@ -0,0 +1,126 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.highGround;
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.world.BlockPallet;
import io.github.togar2.pvp.events.EntityKnockbackEvent;
import io.github.togar2.pvp.events.FinalAttackEvent;
import io.github.togar2.pvp.events.PrepareAttackEvent;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Player;
import net.minestom.server.event.instance.InstanceTickEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.block.Block;
import org.jetbrains.annotations.NotNull;
import java.util.WeakHashMap;
import java.util.concurrent.CompletableFuture;
class HighGround extends StatelessGame {
private final int radius;
private final int seconds;
private final WeakHashMap<Player, Integer> scoreMap = new WeakHashMap<>();
HighGround(int radius, int seconds) {
super(Dimension.THE_END.key, "highground", new PointsWinScore());
this.radius = radius;
this.seconds = seconds;
this.eventNode().addChild(
CombatFeatures.empty()
.add(CombatFeatures.VANILLA_ATTACK)
.add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build()
.createNode()
);
this.eventNode().addListener(
FinalAttackEvent.class,
finalAttackEvent -> finalAttackEvent.setBaseDamage(0)
);
this.eventNode().addListener(PrepareAttackEvent.class, prepareAttackEvent -> {
if(this.isBeforeBeginning) {
prepareAttackEvent.setCancelled(true);
}
});
this.eventNode().addListener(
EntityKnockbackEvent.class,
entityKnockbackEvent -> entityKnockbackEvent.setStrength(1.1f)
);
this.eventNode().addListener(InstanceTickEvent.class, instanceTickEvent -> {
if(this.isBeforeBeginning || !this.isRunning) return;
this.getPlayers().forEach(player -> {
if((player.isOnGround() && player.getPosition().y() >= 1) || (!player.isOnGround() && player.getPosition().y() >= 1.5)) {
this.scoreMap.put(player, this.scoreMap.get(player) + 1);
player.setLevel(this.scoreMap.get(player) / 20);
player.setExp((this.scoreMap.get(player) % 20) / 20.0f);
}
});
});
}
@Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) {
for(int y = 0; y >= -3; y--) {
int radius = (Math.abs(y) * 5) + this.radius;
for(int x = -radius; x <= radius; x++) {
for(int z = -radius; z <= radius; z++) {
double distance = new Pos(x, 0, z).distance(0, 0, 0);
if(distance <= radius) {
this.setBlock(x, y, z, y == 0 ? Block.DIAMOND_BLOCK : Block.GRASS_BLOCK);
Pos featurePosition = new Pos(x, y + 1, z);
if(y >= 0 || this.getBlock(featurePosition).isSolid()) continue;
if(this.rnd.nextDouble() < 0.1) {
this.setBlock(featurePosition, Block.SHORT_GRASS);
}
if(this.rnd.nextDouble() < 0.01) {
this.setBlock(featurePosition, BlockPallet.FLOWER.rnd());
}
}
}
}
}
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
Player player = playerMoveEvent.getPlayer();
if(playerMoveEvent.getNewPosition().y() < -10) {
player.teleport(this.getSpawn());
}
}
@Override
protected void start() {
this.getPlayers().forEach(player -> this.scoreMap.put(player, 0));
super.start();
}
@Override
protected void onStart() {
this.setTimeLimit(this.seconds);
}
@Override
protected void onStop() {
this.getPlayers().forEach(player -> this.getScore().insertResult(player, this.scoreMap.get(player)));
}
@Override
public Pos getSpawn() {
double theta = this.rnd.nextDouble() * 2 * Math.PI;
double spawnRadius = this.radius + 5;
double x = spawnRadius * Math.cos(theta);
double z = spawnRadius * Math.sin(theta);
return new Pos(x, 0, z).withLookAt(new Pos(0, 0, 0));
}
}

View File

@@ -0,0 +1,49 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.highGround;
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.game.stateless.config.restriction.RestrictionHandler;
import eu.mhsl.minenet.minigames.instance.game.stateless.config.restriction.common.MinimalPlayeramountGameRestriction;
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 HighGroundFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_Highground#name");
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_Highground#description");
}
@Override
public Material symbol() {
return Material.GOLDEN_HELMET;
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("radius", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#radius"), 3, 5, 7, 10))
.addOption(new NumericOption("seconds", Material.CLOCK, TranslatedComponent.byId("optionCommon#seconds"), 30, 60, 90, 120));
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new HighGround(configuration.get("radius").getAsInt(), configuration.get("seconds").getAsInt()).setParent(parent);
}
@Override
public RestrictionHandler globalRestrictions() {
return new RestrictionHandler()
.addRestriction(new MinimalPlayeramountGameRestriction(2));
}
}

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 = -this.radius * 2; x <= this.radius * 2; x++) {
for(int z = -this.radius * 2; z <= this.radius * 2; z++) {
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > this.radius) {
batch.setBlock(x, this.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() {
this.setTimeLimit(this.timeLimit);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
Player p = playerMoveEvent.getPlayer();
if(
p.isOnGround() && playerMoveEvent.getNewPosition().y() < this.height
|| playerMoveEvent.getNewPosition().y() < 0
|| this.isBeforeBeginning && playerMoveEvent.getNewPosition().y() < this.height
) {
p.teleport(this.getSpawn());
playerMoveEvent.setCancelled(true);
}
if(
playerMoveEvent.getNewPosition().y() <= 1
&& playerMoveEvent.getNewPosition().distance(0, 1, 0) < this.radius + 0.5
&& !(!this.isBeforeBeginning && !this.isRunning)
) {
this.setBlock(playerMoveEvent.getNewPosition().withY(1), Block.REDSTONE_BLOCK);
this.scores.merge(p, 1, Integer::sum);
p.teleport(this.getSpawn());
playerMoveEvent.setCancelled(true);
p.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 2f, 2f));
}
}
@Override
protected void onStop() {
this.getPlayers().forEach(player -> this.getScore().insertResult(player, this.scores.getOrDefault(player, 0)));
}
@Override
public Pos getSpawn() {
double theta = this.rnd.nextDouble() * 2 * Math.PI;
double spawnRadius = this.radius + 2;
double x = spawnRadius * Math.cos(theta);
double z = spawnRadius * Math.sin(theta);
return new Pos(x, this.height + 2, z).withLookAt(new Pos(0, this.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

@@ -1,16 +1,15 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.minerun; package eu.mhsl.minenet.minigames.instance.game.stateless.types.minerun;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame; import eu.mhsl.minenet.minigames.instance.game.stateless.StatelessGame;
import eu.mhsl.minenet.minigames.score.FirstWinsScore; import eu.mhsl.minenet.minigames.score.FirstWinsScore;
import eu.mhsl.minenet.minigames.util.BatchUtil; import eu.mhsl.minenet.minigames.util.BatchUtil;
import eu.mhsl.minenet.minigames.util.CommonProperties; import eu.mhsl.minenet.minigames.util.CommonProperties;
import eu.mhsl.minenet.minigames.util.Intersect; import eu.mhsl.minenet.minigames.util.Intersect;
import eu.mhsl.minenet.minigames.instance.Dimension;
import eu.mhsl.minenet.minigames.world.BlockPallet; import eu.mhsl.minenet.minigames.world.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.SquarePlateTerrainGenerator; import eu.mhsl.minenet.minigames.world.generator.terrain.SquarePlateTerrainGenerator;
import net.kyori.adventure.sound.Sound; import net.kyori.adventure.sound.Sound;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player; import net.minestom.server.entity.Player;
import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.event.player.PlayerMoveEvent;
@@ -19,7 +18,7 @@ import net.minestom.server.instance.block.Block;
import net.minestom.server.sound.SoundEvent; import net.minestom.server.sound.SoundEvent;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.*; import java.util.Random;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
class Minerun extends StatelessGame { class Minerun extends StatelessGame {
@@ -33,8 +32,8 @@ class Minerun extends StatelessGame {
private final int afterFinishLine = 10; private final int afterFinishLine = 10;
public Minerun(int width, int length, int minePercentage) { 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.setGenerator(new SquarePlateTerrainGenerator(width, length + this.preRun + this.afterFinishLine).setPlateHeight(50).setGenerateBorders(true));
this.width = width; this.width = width;
this.length = length; this.length = length;
@@ -43,24 +42,24 @@ class Minerun extends StatelessGame {
@Override @Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) { protected void onLoad(@NotNull CompletableFuture<Void> callback) {
int spawnToFinishLine = preRun + length + afterMines; int spawnToFinishLine = this.preRun + this.length + this.afterMines;
Random random = new Random(); Random random = new Random();
AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = 0; x <= width; x++) { for(int x = 0; x <= this.width; x++) {
for(int z = preRun; z <= length + preRun; z++) { for(int z = this.preRun; z <= this.length + this.preRun; z++) {
if (random.nextInt(0, 100) < minePercentage) { if(random.nextInt(0, 100) < this.minePercentage) {
batch.setBlock(x, 50, z, BlockPallet.PRESSURE_PLATES.rnd()); batch.setBlock(x, 50, z, BlockPallet.PRESSURE_PLATES.rnd());
} }
} }
} }
for(int x = 0; x <= width; x++) { for(int x = 0; x <= this.width; x++) {
batch.setBlock(x, 49, spawnToFinishLine, Block.GOLD_BLOCK); batch.setBlock(x, 49, spawnToFinishLine, Block.GOLD_BLOCK);
batch.setBlock(x, 49, preRun, Block.GOLD_BLOCK); batch.setBlock(x, 49, this.preRun, Block.GOLD_BLOCK);
batch.setBlock(x, 50, preRun, Block.OAK_FENCE.withProperties(CommonProperties.fenceEastWest)); batch.setBlock(x, 50, this.preRun, Block.OAK_FENCE.withProperties(CommonProperties.fenceEastWest));
} }
BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null)); BatchUtil.loadAndApplyBatch(batch, this, () -> callback.complete(null));
} }
@@ -68,11 +67,11 @@ class Minerun extends StatelessGame {
@Override @Override
protected void onStart() { protected void onStart() {
AbsoluteBlockBatch batch = new AbsoluteBlockBatch(); AbsoluteBlockBatch batch = new AbsoluteBlockBatch();
for(int x = 0; x <= width; x++) { for(int x = 0; x <= this.width; x++) {
batch.setBlock(x, 50, preRun, Block.AIR); batch.setBlock(x, 50, this.preRun, Block.AIR);
} }
BatchUtil.loadAndApplyBatch(batch, this, () -> playSound(Sound.sound(SoundEvent.BLOCK_WOOD_BREAK, Sound.Source.BLOCK, 1f, 1f))); BatchUtil.loadAndApplyBatch(batch, this, () -> this.playSound(Sound.sound(SoundEvent.BLOCK_WOOD_BREAK, Sound.Source.BLOCK, 1f, 1f)));
} }
@Override @Override
@@ -81,24 +80,23 @@ class Minerun extends StatelessGame {
Player p = playerMoveEvent.getPlayer(); Player p = playerMoveEvent.getPlayer();
Pos middle = playerMoveEvent.getNewPosition(); Pos middle = playerMoveEvent.getNewPosition();
if(isBeforeBeginning && middle.z() > preRun+0.5) { //player cannot go forward before the game start if(this.isBeforeBeginning && middle.z() > this.preRun + 0.5) { //player cannot go forward before the game start
playerMoveEvent.setCancelled(true); playerMoveEvent.setCancelled(true);
} }
if(Intersect.withPressurePlate(this, BlockPallet.PRESSURE_PLATES, middle)) { //Player died if(Intersect.withPressurePlate(this, BlockPallet.PRESSURE_PLATES, middle)) { //Player died
p.playSound(Sound.sound(SoundEvent.ENTITY_GENERIC_EXPLODE, Sound.Source.PLAYER, 1f, 1f)); 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(), this.getSpawn().y(), this.getSpawn().z()));
p.teleport(new Pos(p.getPosition().x(), getSpawn().y(), getSpawn().z()));
} }
if(middle.z() > preRun + length + afterMines) { // Player finished if(middle.z() > this.preRun + this.length + this.afterMines) { // Player finished
getScore().insertResult(p); this.getScore().insertResult(p);
p.setGameMode(GameMode.SPECTATOR); p.setGameMode(GameMode.SPECTATOR);
} }
} }
@Override @Override
public Pos getSpawn() { public Pos getSpawn() {
return new Pos((double) width /2, 50, 3); return new Pos((double) this.width / 2, 50, 3);
} }
} }

View File

@@ -22,7 +22,7 @@ public class MinerunFactory implements GameFactory {
return new ConfigManager() return new ConfigManager()
.addOption(new NumericOption("width", Material.OAK_FENCE, TranslatedComponent.byId("optionCommon#width"), 10, 30, 50, 100)) .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("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 @Override

View File

@@ -0,0 +1,185 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.spaceSnake;
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.MaterialUtil;
import io.github.togar2.pvp.events.FinalAttackEvent;
import io.github.togar2.pvp.events.PrepareAttackEvent;
import io.github.togar2.pvp.feature.CombatFeatures;
import net.kyori.adventure.sound.Sound;
import net.minestom.server.MinecraftServer;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.Entity;
import net.minestom.server.entity.EntityType;
import net.minestom.server.entity.GameMode;
import net.minestom.server.entity.Player;
import net.minestom.server.entity.metadata.other.FallingBlockMeta;
import net.minestom.server.event.entity.EntityTickEvent;
import net.minestom.server.event.player.PlayerBlockPlaceEvent;
import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.instance.WorldBorder;
import net.minestom.server.instance.block.Block;
import net.minestom.server.inventory.PlayerInventory;
import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import net.minestom.server.sound.SoundEvent;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class SpaceSnake extends StatelessGame {
private final Map<Player, PlayState> playerStates = new WeakHashMap<>();
private final Supplier<Integer> posInBoundsH = () -> this.rnd.nextInt(-60, 300);
private int mapSize;
private final Supplier<Integer> posInBoundsW = () -> this.rnd.nextInt(-this.mapSize / 2, this.mapSize / 2);
public SpaceSnake(int mapSize, int powerUpCount) {
super(Dimension.THE_END.key, "spaceSnake", new PointsWinScore());
this.mapSize = mapSize;
this.setWorldBorder(new WorldBorder(this.mapSize, 0, 0, 0, 0));
for(int i = 0; i < powerUpCount; i++) {
this.spawnPowerUp();
}
this.eventNode().addChild(
CombatFeatures.empty()
.add(CombatFeatures.VANILLA_ATTACK)
.add(CombatFeatures.VANILLA_DAMAGE)
.add(CombatFeatures.VANILLA_KNOCKBACK)
.build()
.createNode()
);
this.eventNode().addListener(PrepareAttackEvent.class, prepareAttackEvent -> {
if(this.isBeforeBeginning) prepareAttackEvent.setCancelled(true);
});
this.eventNode().addListener(FinalAttackEvent.class, finalAttackEvent -> {
finalAttackEvent.setBaseDamage(0);
((Player) finalAttackEvent.getTarget()).setHealth(20);
});
}
@Override
protected void onStart() {
this.getPlayers().forEach(player -> {
player.setGameMode(GameMode.SURVIVAL);
this.updateInv(player);
player.setHeldItemSlot((byte) 1);
});
}
@Override
protected void onStop() {
this.getPlayers().forEach(player -> this.getScore().insertResult(player, this.playerStates.get(player).length.get()));
}
@Override
protected boolean onPlayerJoin(Player p) {
Pos spawn = new Pos(this.posInBoundsW.get(), -60, this.posInBoundsW.get());
PlayState state = new PlayState(
new AtomicInteger(3),
new ArrayDeque<>(List.of(spawn)),
MaterialUtil.getRandomFullBlock(material -> !material.equals(Material.DIAMOND_BLOCK)),
spawn
);
this.playerStates.put(p, state);
this.setBlock(spawn, state.blockType.block());
MinecraftServer.getSchedulerManager().scheduleNextTick(
() -> p.teleport(this.getSaveSpawn(spawn))
);
return super.onPlayerJoin(p);
}
@Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
PlayState state = this.playerStates.get(playerMoveEvent.getPlayer());
if(this.isBeforeBeginning) {
boolean falling = state.blocks.stream().anyMatch(pos -> pos.y() > playerMoveEvent.getNewPosition().y());
if(falling) playerMoveEvent.getPlayer().teleport(this.getSaveSpawn(state.spawn));
return;
}
if(playerMoveEvent.getNewPosition().y() < -64) {
this.getScore().insertResult(playerMoveEvent.getPlayer(), state.length.get());
playerMoveEvent.getPlayer().teleport(this.getSpawn());
playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
long livingPlayers = this.getPlayers().stream()
.filter(p -> this.getScore().hasResult(p))
.count();
if(livingPlayers == 1) this.setTimeLimit(10);
if(livingPlayers == 0) this.stop();
}
}
@Override
protected void onBlockPlace(@NotNull PlayerBlockPlaceEvent playerBlockPlaceEvent) {
if(this.isBeforeBeginning) {
playerBlockPlaceEvent.setCancelled(true);
return;
}
PlayState state = this.playerStates.get(playerBlockPlaceEvent.getPlayer());
state.blocks.add(playerBlockPlaceEvent.getBlockPosition().asVec().asPosition());
state.cutToLength(pos -> this.setBlock(pos, Block.AIR));
MinecraftServer.getSchedulerManager().scheduleNextTick(() -> this.updateInv(playerBlockPlaceEvent.getPlayer()));
playerBlockPlaceEvent.getPlayer().setLevel(state.length.get());
}
private Pos getSaveSpawn(Pos blockPos) {
return blockPos.add(0.5).withY((y) -> y + 2);
}
private void updateInv(Player player) {
PlayerInventory inventory = player.getInventory();
inventory.clear();
inventory.addItemStack(ItemStack.of(Material.STICK, 1).with(builder -> builder.glowing(true)));
inventory.addItemStack(ItemStack.of(this.playerStates.get(player).blockType, 64));
}
private void spawnPowerUp() {
Pos spawnPos = new Pos(this.posInBoundsW.get(), this.posInBoundsH.get(), this.posInBoundsW.get());
Entity display = new Entity(EntityType.FALLING_BLOCK);
((FallingBlockMeta) display.getEntityMeta()).setBlock(Block.DIAMOND_BLOCK);
display.setGlowing(true);
display.setNoGravity(true);
display.setInstance(this, spawnPos);
display.eventNode().addListener(EntityTickEvent.class, onTick -> {
Player player = this.getPlayers().stream()
.filter(p -> !this.getScore().hasResult(p))
.filter(p -> p.getBoundingBox()
.grow(1, 1, 1)
.intersectBox(display.getPosition().sub(p.getPosition()), display.getBoundingBox())
)
.findAny()
.orElse(null);
if(player == null) return;
this.spawnPowerUp();
display.remove();
this.onPowerup(player);
});
}
private void onPowerup(Player player) {
PlayState state = this.playerStates.get(player);
state.length.incrementAndGet();
player.setLevel(player.getLevel() + 1);
player.playSound(Sound.sound(SoundEvent.ENTITY_EXPERIENCE_ORB_PICKUP, Sound.Source.PLAYER, 1f, 1f));
}
record PlayState(AtomicInteger length, Queue<Pos> blocks, Material blockType, Pos spawn) {
public void cutToLength(Consumer<Pos> removed) {
while(this.blocks.size() > this.length.get()) {
removed.accept(this.blocks.poll());
}
}
}
}

View File

@@ -0,0 +1,41 @@
package eu.mhsl.minenet.minigames.instance.game.stateless.types.spaceSnake;
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 SpaceSnakeFactory implements GameFactory {
@Override
public TranslatedComponent name() {
return TranslatedComponent.byId("game_SpaceSnake#name");
}
@Override
public ConfigManager configuration() {
return new ConfigManager()
.addOption(new NumericOption("width", Material.HEART_OF_THE_SEA, TranslatedComponent.byId("optionCommon#width"), 20, 30, 40, 50, 60, 70, 80))
.addOption(new NumericOption("powerUpCount", Material.DIAMOND, TranslatedComponent.byId("game_SpaceSnake#powerUpCount"), 50, 100, 200, 300));
}
@Override
public Material symbol() {
return Material.GREEN_CONCRETE_POWDER;
}
@Override
public TranslatedComponent description() {
return TranslatedComponent.byId("game_SpaceSnake#description");
}
@Override
public Game manufacture(Room parent, Map<String, Option<?>> configuration) throws Exception {
return new SpaceSnake(configuration.get("width").getAsInt(), configuration.get("powerUpCount").getAsInt()).setParent(parent);
}
}

View File

@@ -9,44 +9,45 @@ import eu.mhsl.minenet.minigames.world.BlockPallet;
import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator; import eu.mhsl.minenet.minigames.world.generator.terrain.CircularPlateTerrainGenerator;
import net.minestom.server.coordinate.Pos; import net.minestom.server.coordinate.Pos;
import net.minestom.server.entity.GameMode; import net.minestom.server.entity.GameMode;
import net.minestom.server.event.player.PlayerBlockBreakEvent;
import net.minestom.server.event.player.PlayerMoveEvent; import net.minestom.server.event.player.PlayerMoveEvent;
import net.minestom.server.event.player.PlayerStartDiggingEvent; import net.minestom.server.event.player.PlayerStartDiggingEvent;
import net.minestom.server.instance.batch.AbsoluteBlockBatch; import net.minestom.server.instance.batch.AbsoluteBlockBatch;
import net.minestom.server.instance.block.Block; import net.minestom.server.instance.block.Block;
import net.minestom.server.item.*; import net.minestom.server.item.ItemStack;
import net.minestom.server.item.Material;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
public class Spleef extends StatelessGame { public class Spleef extends StatelessGame {
final int heightPerLevel = 20;
final int totalElevation = 50;
int radius; int radius;
int stackCount; int stackCount;
final int heightPerLevel = 20;
final int totalElevation = 50;
public Spleef(int radius, int stackCount) { public Spleef(int radius, int stackCount) {
super(Dimension.OVERWORLD.DIMENSION, "Spleef", new LastWinsScore()); super(Dimension.OVERWORLD.key, "Spleef", new LastWinsScore());
getScore().setIgnoreLastPlayers(1); this.getScore().setIgnoreLastPlayers(1);
this.radius = radius; this.radius = radius;
this.stackCount = stackCount; this.stackCount = stackCount;
setGenerator(new CircularPlateTerrainGenerator(50)); this.setGenerator(new CircularPlateTerrainGenerator(50));
eventNode().addListener(PlayerStartDiggingEvent.class, this::destroyBlock); this.eventNode().addListener(PlayerStartDiggingEvent.class, this::destroyBlock);
} }
@Override @Override
protected void onLoad(@NotNull CompletableFuture<Void> callback) { protected void onLoad(@NotNull CompletableFuture<Void> callback) {
AbsoluteBlockBatch circle = new AbsoluteBlockBatch(); AbsoluteBlockBatch circle = new AbsoluteBlockBatch();
for (int level = 0; level < stackCount; level++) { for(int level = 0; level < this.stackCount; level++) {
for(int x = -radius; x <= radius; x++) { for(int x = -this.radius; x <= this.radius; x++) {
for(int z = -radius; z <= radius; z++) { for(int z = -this.radius; z <= this.radius; z++) {
if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > radius) continue; if(new Pos(x, 0, z).distance(new Pos(0, 0, 0)) > this.radius) continue;
circle.setBlock(x, totalElevation + (level * heightPerLevel), z, BlockPallet.WINTER.rnd()); circle.setBlock(x, this.totalElevation + (level * this.heightPerLevel), z, BlockPallet.WINTER.rnd());
} }
} }
} }
@@ -56,18 +57,12 @@ public class Spleef extends StatelessGame {
@Override @Override
protected void onStart() { protected void onStart() {
getPlayers().forEach(player -> { this.getPlayers().forEach(player -> {
player.setGameMode(GameMode.SURVIVAL); player.setGameMode(GameMode.SURVIVAL);
player.getInventory().addItemStack( player.getInventory().addItemStack(
ItemStack ItemStack
.builder(Material.DIAMOND_SHOVEL) .builder(Material.DIAMOND_SHOVEL)
.displayName(TranslatedComponent.byId("game_Spleef#shovelName").getAssembled(player)) .customName(TranslatedComponent.byId("game_Spleef#shovelName").getAssembled(player))
.meta(
builder -> builder
.enchantment(Enchantment.EFFICIENCY, (short) 99)
.hideFlag(ItemHideFlag.HIDE_ENCHANTS)
.build()
)
.build() .build()
); );
player.setHeldItemSlot((byte) 0); player.setHeldItemSlot((byte) 0);
@@ -76,19 +71,29 @@ public class Spleef extends StatelessGame {
@Override @Override
protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) { protected void onPlayerMove(@NotNull PlayerMoveEvent playerMoveEvent) {
if(playerMoveEvent.getNewPosition().y() < totalElevation) { if(playerMoveEvent.getNewPosition().y() < this.totalElevation) {
playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR); playerMoveEvent.getPlayer().setGameMode(GameMode.SPECTATOR);
playerMoveEvent.getPlayer().getInventory().clear(); playerMoveEvent.getPlayer().getInventory().clear();
getScore().insertResult(playerMoveEvent.getPlayer()); this.getScore().insertResult(playerMoveEvent.getPlayer());
} }
} }
@Override
protected void onBlockBreak(@NotNull PlayerBlockBreakEvent event) {
if(!this.isRunning) {
event.setCancelled(true);
return;
}
this.setBlock(event.getBlockPosition(), Block.AIR);
}
private void destroyBlock(PlayerStartDiggingEvent event) { private void destroyBlock(PlayerStartDiggingEvent event) {
setBlock(event.getBlockPosition(), Block.AIR); if(!this.isRunning) return;
this.setBlock(event.getBlockPosition(), Block.AIR);
} }
@Override @Override
public Pos getSpawn() { public Pos getSpawn() {
return new Pos(0, totalElevation + heightPerLevel * (stackCount-1) + 1, 0); return new Pos(0, this.totalElevation + this.heightPerLevel * (this.stackCount - 1) + 1, 0);
} }
} }

View File

@@ -33,7 +33,7 @@ public class SpleefFactory implements GameFactory {
@Override @Override
public ConfigManager configuration() { public ConfigManager configuration() {
return new ConfigManager() 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)); .addOption(new NumericOption("stackCount", Material.SCAFFOLDING, TranslatedComponent.byId("game_Spleef#stackCount"), 1, 2, 3, 4, 5));
} }

View File

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

View File

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

Some files were not shown because too many files have changed in this diff Show More