diff --git a/.gitignore b/.gitignore index 9b222ae..36dfa2c 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,9 @@ build/ out/ classes/ +.gradlew +.gradle-wrapper.properties + # eclipse *.launch diff --git a/README.md b/README.md index 0473767..72a2ef8 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,9 @@ für den ReentsEntertainment Minecraft Server Ändert folgendes: -- nichts +- fügt multi-sleep hinzu: du kannst beim schlafen dein bett in einem von fünf slots speichern. Nach dem Tod kannst du auswählen bei welchem du respawnen willst; TODO: -- Betten auswählen zum spawnen +- Gird-Blöcke diff --git a/gradle.properties b/gradle.properties index 388008f..f5228ad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,9 +9,9 @@ yarn_mappings=1.19.2+build.28 loader_version=0.14.23 # Mod Properties -mod_version=1.0.0 +mod_version=1.0.3 maven_group=modchest archives_base_name=reservermod # Dependencies -fabric_version=0.76.1+1.19.2 \ No newline at end of file +fabric_version=0.76.1+1.19.2 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index ac72c34..0000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew deleted file mode 100644 index 0adc8e1..0000000 --- a/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index 93e3f59..0000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/src/client/java/modchest/REServerModClient.java b/src/client/java/modchest/REServerModClient.java index 7c7f9b6..2ae7013 100644 --- a/src/client/java/modchest/REServerModClient.java +++ b/src/client/java/modchest/REServerModClient.java @@ -1,16 +1,19 @@ package modchest; + +import modchest.networking.modNetworkingClient; import net.fabricmc.api.ClientModInitializer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class REServerModClient implements ClientModInitializer{ - - @Override +public class REServerModClient implements ClientModInitializer { + public static final Logger LOGGER = LoggerFactory.getLogger("modchest"); // Erster Error Logger + @Override public void onInitializeClient() { - // This entrypoint is suitable for setting up client-specific logic, such as rendering. + // This entrypoint is suitable for setting up client-specific logic, such as rendering. + modNetworkingClient.registerC2SPackets(); //Identifier unter denen der Client zuhoert werden registriert + + LOGGER.info("Modchest-Client successfully loaded!"); } - - - } - - +} diff --git a/src/client/java/modchest/mixin/client/DeathScreen.java b/src/client/java/modchest/mixin/client/DeathScreen.java new file mode 100644 index 0000000..bb96ec9 --- /dev/null +++ b/src/client/java/modchest/mixin/client/DeathScreen.java @@ -0,0 +1,77 @@ +package modchest.mixin.client; + +import modchest.REServerModClient; +import modchest.networking.modNetworkingClient; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(net.minecraft.client.gui.screen.DeathScreen.class) +public class DeathScreen extends Screen { + protected DeathScreen(Text title) { + super(Text.of("useless")); + } //Da wir einen bereits bestehenden Screen erweitern, wird dieser Text nie angezeigt + + @Inject(method = "init", at = @At("TAIL")) //Dieser Code wird in den eigentlich bereits bestehenden Code der Klasse DeathScreen hinzugefügt + private void addMultiSleepButtons(CallbackInfo info) {; + int widthButton = 40; //Die generelle Breite der knoepfe wird definiert + int heightButton = 20; // " hoehe " + int yOffset = 5; //Wie gross der Abstand zwischen der oberen Kante un dem knop sein soll (der Nullpunkt (0|0) ist soswohl im Fenster als auch beim Knopf oben links die Ecke) + int xOffset = this.width / 2 - widthButton / 2; //Die Mitte wird ausgerechnet (Mitte vom fenster minus halbe Breite des knopfes um tatsächlich die Mitte zu haben, weil koordinaten und so + this.addDrawableChild( + new ButtonWidget(xOffset - 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#1"), button -> { //Knopf wird erzeugt + REServerModClient.LOGGER.info("First Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); //Neuer Buffer wird erstellt + buffer.writeInt(1); //Beschrieben, damit der Server weiss, welcher knopf gedrueckt wurde + sendPacket(buffer); //Und an den Server gesendet zum Speichern; Die gesamte logik passiert auf dem server, damit man keien fake koordinaten oder so eingeben kann + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset - (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#2"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Second Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(2); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset, yOffset, widthButton, heightButton, Text.translatable("#3"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Third Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(3); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#4"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Fourth Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(4); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#5"), button -> { //Kommentare siehe knopf #1 + REServerModClient.LOGGER.info("Fifth Button for using spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(5); + sendPacket(buffer); + }) + ); + } + + @Unique + private synchronized void sendPacket(PacketByteBuf buffer) { + try { + ClientPlayNetworking.send(modNetworkingClient.death_multi_respawn_buttons, buffer); + } catch (Exception e) {} + } +} diff --git a/src/client/java/modchest/mixin/client/ExampleClientMixin.java b/src/client/java/modchest/mixin/client/ExampleClientMixin.java deleted file mode 100644 index 0a7c93d..0000000 --- a/src/client/java/modchest/mixin/client/ExampleClientMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package modchest.mixin.client; - -import net.minecraft.client.MinecraftClient; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MinecraftClient.class) -public class ExampleClientMixin { - @Inject(at = @At("HEAD"), method = "run") - private void run(CallbackInfo info) { - // This code is injected into the start of MinecraftClient.run()V - } -} \ No newline at end of file diff --git a/src/client/java/modchest/mixin/client/SleepingChatScreen.java b/src/client/java/modchest/mixin/client/SleepingChatScreen.java new file mode 100644 index 0000000..1d68f8b --- /dev/null +++ b/src/client/java/modchest/mixin/client/SleepingChatScreen.java @@ -0,0 +1,77 @@ +package modchest.mixin.client; + +import modchest.REServerModClient; +import modchest.networking.modNetworkingClient; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(net.minecraft.client.gui.screen.SleepingChatScreen.class) +public class SleepingChatScreen extends Screen { //Sehr identisch zu Death Screen, siehe dort fuer Kommentare!! + protected SleepingChatScreen(Text title) { + super(Text.of("useless")); + } + + @Inject(method = "init", at = @At("TAIL")) + private void addMultiSleepButtons(CallbackInfo info) { + int widthButton = 40; + int heightButton = 20; + int yOffset = 5; + int xOffset = this.width / 2 - widthButton / 2; + this.addDrawableChild( + new ButtonWidget(xOffset - 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#1"), button -> { + REServerModClient.LOGGER.info("First Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(1); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset - (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#2"), button -> { + REServerModClient.LOGGER.info("Second Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(2); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset, yOffset, widthButton, heightButton, Text.translatable("#3"), button -> { + REServerModClient.LOGGER.info("Third Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(3); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#4"), button -> { + REServerModClient.LOGGER.info("Fourth Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(4); + sendPacket(buffer); + }) + ); + this.addDrawableChild( + new ButtonWidget(xOffset + 2 * (widthButton + 5), yOffset, widthButton, heightButton, Text.translatable("#5"), button -> { + REServerModClient.LOGGER.info("Fifth Button for saving spawn pressed!"); + PacketByteBuf buffer = PacketByteBufs.create(); + buffer.writeInt(5); + sendPacket(buffer); + }) + ); + } + + @Unique + private synchronized void sendPacket(PacketByteBuf buffer) { + try { + ClientPlayNetworking.send(modNetworkingClient.start_sleeping_call_buttons, buffer); + } catch (Exception e) {} + } +} \ No newline at end of file diff --git a/src/client/java/modchest/networking/modNetworkingClient.java b/src/client/java/modchest/networking/modNetworkingClient.java new file mode 100644 index 0000000..b30a978 --- /dev/null +++ b/src/client/java/modchest/networking/modNetworkingClient.java @@ -0,0 +1,15 @@ +package modchest.networking; + +import modchest.REServerMod; +import modchest.networking.packet.respawnRequestS2CPacket; +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.minecraft.util.Identifier; + +public class modNetworkingClient { //Identifier werden eingeführt + public static final Identifier request_respawn = new Identifier(REServerMod.MOD_ID, "request_respawn"); //alle Identifier muessen leider IMMER auf Client und Server (doppelt) eingefuehrt werden + public static final Identifier start_sleeping_call_buttons = new Identifier(REServerMod.MOD_ID, "start_sleeping_call_buttons"); + public static final Identifier death_multi_respawn_buttons = new Identifier(REServerMod.MOD_ID, "death_call_respawn_buttons"); + public static void registerC2SPackets() { //Identifier fuer packets werden registriert (Identifier die der Server aufruft um beim CLient was auszufuehren) + ClientPlayNetworking.registerGlobalReceiver(request_respawn, respawnRequestS2CPacket::receive); //was der Client dann machen soll steht in der receive Methode + } +} diff --git a/src/client/java/modchest/networking/packet/respawnRequestS2CPacket.java b/src/client/java/modchest/networking/packet/respawnRequestS2CPacket.java new file mode 100644 index 0000000..d2e9aa9 --- /dev/null +++ b/src/client/java/modchest/networking/packet/respawnRequestS2CPacket.java @@ -0,0 +1,15 @@ +package modchest.networking.packet; + +import modchest.REServerModClient; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayNetworkHandler; +import net.minecraft.network.PacketByteBuf; + +public class respawnRequestS2CPacket { + + public static void receive(MinecraftClient minecraftClient, ClientPlayNetworkHandler clientPlayNetworkHandler, PacketByteBuf packetByteBuf, PacketSender packetSender) { + //REServerModClient.LOGGER.info("Server asked for respawn after pressing a saved respawn button!"); + minecraftClient.player.requestRespawn(); + } +} diff --git a/src/client/resources/reservermod.client.mixins.json b/src/client/resources/reservermod.client.mixins.json index ee8b04c..583fc92 100644 --- a/src/client/resources/reservermod.client.mixins.json +++ b/src/client/resources/reservermod.client.mixins.json @@ -1,11 +1,14 @@ { - "required": true, - "package": "modchest.mixin.client", - "compatibilityLevel": "JAVA_17", - "client": [ - "ExampleClientMixin" - ], - "injectors": { - "defaultRequire": 1 - } + "required": true, + "package": "modchest.mixin.client", + "compatibilityLevel": "JAVA_17", + "client": [ + "DeathScreen", + "SleepingChatScreen" + ], + "injectors": { + "defaultRequire": 1 + }, + "mixins": [ + ] } \ No newline at end of file diff --git a/src/documentation/Development b/src/documentation/Development index 32dc014..21e0921 100644 --- a/src/documentation/Development +++ b/src/documentation/Development @@ -8,6 +8,10 @@ Archimedes ship mod code (Mod die Schiffe hinzufügt): (1.7.10, alt aber leich Valkyrien Skies Mod (Fügt Schiffe + Flugzeuge hinzu): (1.19.2 + Fabric, aber etwas komplexer) https://github.com/ValkyrienSkies +In Arbeit: +- (Paula) Grid-Block: Blöcke in diversen Formen. Wenn man mit einem Block rechtsklick macht, nimmt der Grid-Block die entsprechende Textur an. Mit einem neuen Werkzeug + dem Hammer kann man mit rechtsklick die Textur wieder entfernen, mit linksklick den ganzen Block abbauen. Sinn: Mehr baumöglichkeiten, und wenn man z.B. + Deko-Blätter platziert baut man die nicht mehr ausversehen ab. Ideen für Features: diff --git a/src/documentation/Features b/src/documentation/Features index d9d174e..6c18cd0 100644 --- a/src/documentation/Features +++ b/src/documentation/Features @@ -1,2 +1,2 @@ Bereits vorhandene Features: -- keins.... \ No newline at end of file +- multi-sleep (man hat 5 spawnpunkte zu auswahl) \ No newline at end of file diff --git a/src/main/java/modchest/REServerMod.java b/src/main/java/modchest/REServerMod.java index 278ff1f..50fb423 100644 --- a/src/main/java/modchest/REServerMod.java +++ b/src/main/java/modchest/REServerMod.java @@ -6,9 +6,11 @@ import modchest.event.useBlockCallback; import modchest.block.modBlocks; import modchest.item.modItemGroup; import modchest.item.modItems; + import net.fabricmc.api.ModInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import modchest.util.initializer; //Main file; Hier wird alles aufgesetzt public class REServerMod implements ModInitializer { @@ -16,17 +18,13 @@ public class REServerMod implements ModInitializer { public static final Logger LOGGER = LoggerFactory.getLogger("modchest"); // Erster Error Logger - @Override - public void onInitialize() { - modItemGroup.modchest(); // Item Gruppe fürs Creative-Inventar wird erstellt; In dieser Gruppe sollen - // dann alle Items und Blöcke dieser Mod angezeigt werden - modItems.setItems(); // die Items werden erstellt - modBlocks.setBlocks(); // Hier werden die Blöcke erstellt - modBlockEntities.registerBlockEntities(); // Die Interaktionsmenüs für die Blöcke werden erstellt - useBlockCallback.EVENT.register(new useBlockCallback()); - - - LOGGER.info("Modchest erfolgreich geladen!"); + public void onInitialize() { //Der uebersicht halber sind jetzt alle initializer in Klassen in util in initializer + initializer.itemGroups(); + initializer.itemsAndBlocks(); + initializer.events(); + initializer.networking(); + + LOGGER.info("Modchest successfully loaded!"); } diff --git a/src/main/java/modchest/event/playerAfterRespawnEvent.java b/src/main/java/modchest/event/playerAfterRespawnEvent.java new file mode 100644 index 0000000..f6941fb --- /dev/null +++ b/src/main/java/modchest/event/playerAfterRespawnEvent.java @@ -0,0 +1,36 @@ +package modchest.event; + +import modchest.REServerMod; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; + +public class playerAfterRespawnEvent implements ServerPlayerEvents.AfterRespawn { //Wenn die Multi-Spawn mod verwendet wurde, muss der Vanillaspawn wieder gesetzt werden + @Override + public void afterRespawn(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer, boolean alive) { + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); //Damit die Methoden benutzt werden koennen, muss ein Objekt erstellt werden; ist aber egal, weil eh keine Daten in dieser Klasse gespeichert werden + NbtCompound nbt = setAndGet.getMultiSpawnVanilla(newPlayer); //holt sich den nbt-tag + if (nbt != null) { + try { + int[] location = nbt.getIntArray("location"); //holt sich den gespeicherten Ort + BlockPos blockPos = new BlockPos(location[0], location[1], location[2]); + + String[] parts = nbt.getString("dimension").split(":"); //holt sich die gespeicherte Dimension; trennt den String entspreichend; damit sollte es auch funktionieren, sollte eine Mod weitere Dimensionen hinzufuegen + parts = parts[2].split("]"); + RegistryKey dim = RegistryKey.of(Registry.WORLD_KEY, new Identifier(parts[0])); + + float angle = nbt.getFloat("angle"); //Und den blickwinkel + + newPlayer.setSpawnPoint(dim, blockPos, angle, true, false); + } catch (Exception e) { + REServerMod.LOGGER.info("Following error when trying set " + newPlayer.getDisplayName() + "'s Vanilla Spawn: " + e); + } + } + } +} diff --git a/src/main/java/modchest/mixin/ExampleMixin.java b/src/main/java/modchest/mixin/ExampleMixin.java deleted file mode 100644 index 4c11efa..0000000 --- a/src/main/java/modchest/mixin/ExampleMixin.java +++ /dev/null @@ -1,15 +0,0 @@ -package modchest.mixin; - -import net.minecraft.server.MinecraftServer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(MinecraftServer.class) -public class ExampleMixin { - @Inject(at = @At("HEAD"), method = "loadWorld") - private void init(CallbackInfo info) { - // This code is injected into the start of MinecraftServer.loadWorld()V - } -} \ No newline at end of file diff --git a/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java b/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java new file mode 100644 index 0000000..635dbb7 --- /dev/null +++ b/src/main/java/modchest/mixin/ServerPlayerEntityMixin.java @@ -0,0 +1,61 @@ +package modchest.mixin; + +import modchest.REServerMod; +import modchest.util.ServerPlayerEntityInterface; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Arrays; + +@Mixin(ServerPlayerEntity.class) +public abstract class ServerPlayerEntityMixin implements ServerPlayerEntityInterface { + @Unique + private NbtCompound dataSaver = new NbtCompound(); //Weil die nbt daten beim tod geloescht werden, muessen sie rueber kopiert werden; der neue nbtTag existiert aber noch nciht, daher muessen sie hier zwischengespeichert werden + + @Override + public NbtCompound getDataSaver() { //Um errors zu vermeiden, sorgt er dafuer, dass es immer ein persistentData gibt + if (this.dataSaver == null) { + this.dataSaver = new NbtCompound(); + } + return this.dataSaver; + } + + @Override + public void setDataSaver(NbtCompound data) { //Um errors zu vermeiden, sorgt er dafuer, dass es immer ein persistentData gibt + this.dataSaver = data; + } + + @Inject(method = "writeCustomDataToNbt", at = @At("TAIL")) + public void writeCustomDataToNbt(NbtCompound nbt, CallbackInfo ci) { //Immer wenn eine andere Methode aufruft, dass Daten abgespeichert werden sollen, tun wir das jetzt auch + if (dataSaver != null) { //wenn der dataSaver null ist, wuerde sonst ein Error kommen, weil Minecraft keine leeren NBTs absepeicheern kann :( + try { + nbt.put("REServerMod", this.dataSaver); + } catch (Exception e) { + REServerMod.LOGGER.info("Error while saving custom NBt-Data: " + e); + } + } else { + REServerMod.LOGGER.info("write failed! This probably means, that the player hasn't set a custom spanpoint yet"); + } + } + + @Inject(method = "readCustomDataFromNbt", at = @At("TAIL")) + public void readCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) { //gleiches beim einlesen. Werden NBT-Daten eingelesen, tun wird das auch + try { + dataSaver = (NbtCompound) nbt.get("REServerMod"); + } catch (Exception e) { + REServerMod.LOGGER.info("Error while saving custom NBt-Data: " + e); + } + //REServerMod.LOGGER.info("readCustomDataFromNbt called with following Data: " + Arrays.toString(nbt.getIntArray("REServerMod.sleep_data"))); + } + + @Inject(method = "copyFrom", at = @At("TAIL")) + public void copyFrom(ServerPlayerEntity oldPlayer, boolean alive, CallbackInfo ci) { //Beim Tod des Spielers werden die NBT-Daten kopiert, damit die Spawnpunkte nicht verloren gehen, kopieren wir sie auch mit rueber + dataSaver = ((ServerPlayerEntityInterface) oldPlayer).getDataSaver(); + //REServerMod.LOGGER.info("copyFrom called"); + } +} diff --git a/src/main/java/modchest/mixin/bedBlock.java b/src/main/java/modchest/mixin/bedBlock.java new file mode 100644 index 0000000..a995ba4 --- /dev/null +++ b/src/main/java/modchest/mixin/bedBlock.java @@ -0,0 +1,88 @@ +package modchest.mixin; + +import modchest.REServerMod; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import net.minecraft.block.BedBlock; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +@Mixin(BedBlock.class) +public class bedBlock { + + @Inject(method = "onBreak", at = @At("HEAD")) + public void onBreak(World world, BlockPos pos, BlockState state, PlayerEntity player, CallbackInfo ci) { //Ueberprueft, wenn ein Bett zerstoert wird, ob jemand dieses Bett als Spawnpunkt hat + if (!world.isClient) { //Stellt sicher, dass das ganze nicht auf dem Client gerechnet wird, weil der Code sonst abstuertzt + + int posBedX = pos.getX(); + int posBedY = pos.getY(); + int posBedZ = pos.getZ(); + + String bedData = state.toString(); + if (Objects.equals(bedData.split("part=")[1], "foot]")) { //das fussende wurde zerstoert, damit der Code also geht, muss in richtung kopfende eins gegangen werden + switch (bedData.split("facing=")[1].split(",")[0]) { + case "east": + posBedX++; + break; + case "west": + posBedX--; + break; + case "south": + posBedZ++; + break; + case "north": + posBedZ--; + break; + default: + break; + } + } + + if (posBedX < 0) { //Es gibt leider einen rundungsfehler. Wenn Das Bett negative koordinaten hat, rundet es weg von der Null wahrend der Spieler richtung Null aufrundet + posBedX++; + } + if (posBedY < 0) { + posBedY++; + } + if (posBedZ < 0) { + posBedZ++; + } + + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); //Damit die Methoden benutzt werden koennen, muss ein Objekt erstellt werden; ist aber egal, weil eh keine Daten in dieser Klasse gespeichert werden + List playerArray = null; + try { //Sollte der Code doch ausversehen auf dem Client ausgefuehrt werden, wuerde die folgende Zeile einen Error schmeissen + playerArray = world.getPlayers(); //holt sich die liste aller Spieler auf dem server + } catch (Exception e) { + REServerMod.LOGGER.info("Error when trying to get players Array after Bed was destroyed: " + e); + } + for (int i = 0; i < playerArray.size(); i++) { //geht fuer jeden Spieler durch + for (int j = 1; j <= 5; j++) { //und fuer alle Speicherslots dieser + int[] posXYZ = new int[0]; + try { //Sollte der Code doch ausversehen auf dem Client ausgefuehrt werden, wuerde die folgende Zeile einen Error schmeissen + posXYZ = setAndGet.getMultiSpawn((ServerPlayerEntity) playerArray.get(i), j); + } catch (Exception e) { + REServerMod.LOGGER.info("Error casting playerArray to ServerPlayerEntity: " + e); + } + if (posBedX == posXYZ[0] && posBedY == posXYZ[1] && posBedZ == posXYZ[2]) { //Gleicht ab, ob die Koordinaten uebereinstimmen + try { //Sollte der Code doch ausversehen auf dem Client ausgefuehrt werden, wuerde die folgende Zeile einen Error schmeissen + setAndGet.setMultiSpawnBlank((ServerPlayerEntity) playerArray.get(i), j); //Wird ein bett zerstoert, wird der Spawnpunkt geblanked + } catch (Exception e) { + REServerMod.LOGGER.info("Error when trying to get players Array after Bed was destroyed: " + e); + } + } + } + } + } + } +} diff --git a/src/main/java/modchest/networking/modNetworkingServer.java b/src/main/java/modchest/networking/modNetworkingServer.java new file mode 100644 index 0000000..64f771d --- /dev/null +++ b/src/main/java/modchest/networking/modNetworkingServer.java @@ -0,0 +1,19 @@ +package modchest.networking; + +import modchest.REServerMod; +import modchest.networking.packet.deathScreenMultiButtonsC2SPacket; +import modchest.networking.packet.setNewRespawnsC2SPacket; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.util.Identifier; + +public class modNetworkingServer { //Identifier werden eingeführt + public static final Identifier request_respawn = new Identifier(REServerMod.MOD_ID, "request_respawn"); //alle Identifier muessen leider IMMER auf Client und Server (doppelt) eingefuehrt werden + public static final Identifier start_sleeping_call_buttons = new Identifier(REServerMod.MOD_ID, "start_sleeping_call_buttons"); + public static final Identifier death_multi_respawn_buttons = new Identifier(REServerMod.MOD_ID, "death_call_respawn_buttons"); + + public static void registerS2CPackets() { //Identifier fuer packets werden registriert (Identifier die der Client aufruft um beim Server was auszufuehren) + ServerPlayNetworking.registerGlobalReceiver(start_sleeping_call_buttons, setNewRespawnsC2SPacket::receive); //was der Server dann machen soll steht in der receive Methode + + ServerPlayNetworking.registerGlobalReceiver(death_multi_respawn_buttons, deathScreenMultiButtonsC2SPacket::receive); + } +} diff --git a/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java b/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java new file mode 100644 index 0000000..63440ce --- /dev/null +++ b/src/main/java/modchest/networking/packet/deathScreenMultiButtonsC2SPacket.java @@ -0,0 +1,54 @@ +package modchest.networking.packet; + +import modchest.REServerMod; +import modchest.networking.modNetworkingServer; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.awt.*; +import java.util.Arrays; + +public class deathScreenMultiButtonsC2SPacket { + public static void receive(MinecraftServer server, ServerPlayerEntity player, //Passiert auf dem Server!!! + ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); //um die nicht-statischen Methoden aufzurufen, erzeugen wir ein Objekt. Wir speichern aber keine Daten in der Klasse, daher ist das OK + int num; //num steht fuer Number, und sagt, welcher der 5 Knoepfe gedrueckt wurde, da das Spiel abstuertzt wenn man buf.readInt() mehr als einmal ausfuehrt + try { + num = buf.readInt(); //Um Spielabstuertze definitiv zu verhindern in einem try block, hat aber nie Probleme gemacht, also eine reine absicherung + } catch (Exception e) { + REServerMod.LOGGER.info("Following Error when trying to get the number of pressed Button: " + e + "continuing bwith Button 1"); + num = 1; + } + setAndGet.setMultiSpawnVanilla(player); + + int[] posXYZ = setAndGet.getMultiSpawn(player, num); //neue Koordinaten werden vom Server geholt + + if (posXYZ.length == 3 && posXYZ[0] < 77889900) { //Stellt sicher, dass die 3 spawnkoordinaten nicht null sind; Koordinaten 77889900 sind ausserhalb der Welt und werden daher von mir in setAndGetMultiSpawnButtonsSpawn als Errorcodes verwendet + try { + //REServerMod.LOGGER.info("try Respawning from Multi-Sapwn"); + player.setSpawnPoint(World.OVERWORLD, new BlockPos(posXYZ[0], posXYZ[1], posXYZ[2]), 0, true, true); //neuer Spawn wird gesetzt + ServerPlayNetworking.send(player, modNetworkingServer.request_respawn, PacketByteBufs.create()); //Anfrage an den Client zum respawnen wird gesendet + player.sendMessage((Text.translatable("chat.modchest.multispawn.respawned", num))); + REServerMod.LOGGER.info("Respawned Player " + player.getEntityName() + " at " + Arrays.toString(setAndGet.getMultiSpawn(player, num))); + setAndGet.setMultiSpawn(player, 6); + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Following error, trying to respawn player " + player.getDisplayName() + ": " + e); + } + } else { + if (posXYZ[0] == 77889944) { //Dieser Errorcode bedeutet, dass das Bett zerstoert wurde + player.sendMessage(Text.translatable("chat.modchest.multispawn.beddestroyed")); + } else { + player.sendMessage(Text.translatable("chat.modchest.multispawn.spawnnotset")); + } + } + } +} diff --git a/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java b/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java new file mode 100644 index 0000000..92419bf --- /dev/null +++ b/src/main/java/modchest/networking/packet/setNewRespawnsC2SPacket.java @@ -0,0 +1,46 @@ +package modchest.networking.packet; + +import modchest.REServerMod; +import modchest.util.setAndGetMultiButtonsSpawn; +import net.fabricmc.fabric.api.networking.v1.PacketSender; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +import java.util.Arrays; + +public class setNewRespawnsC2SPacket { + public static void receive(MinecraftServer server, ServerPlayerEntity player, //Passiert auf dem Server!!! + ServerPlayNetworkHandler handler, PacketByteBuf buf, PacketSender responseSender) { + setAndGetMultiButtonsSpawn setAndGet = new setAndGetMultiButtonsSpawn(); + try { + switch (buf.readInt()) { //Wird nur einmal angefragt, daher muss buf.readInt() nicht als variable gesetzt werden + case 1: + setAndGet.setMultiSpawn(player, 1); //Spawnpunkt wird gespeichert + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "1")); + break; + case 2: + setAndGet.setMultiSpawn(player, 2); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "2")); + break; + case 3: + setAndGet.setMultiSpawn(player, 3); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "3")); + break; + case 4: + setAndGet.setMultiSpawn(player, 4); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "4")); + break; + case 5: + setAndGet.setMultiSpawn(player, 5); + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawn", "5")); + break; + } + } catch (Exception e) { + player.sendMessage(Text.translatable("chat.modchest.multispawn.setspawnerror")); + REServerMod.LOGGER.info("Following Error, when trying to save " + player.getDisplayName() + "'s Spawnpoint: " + e); + } + } +} diff --git a/src/main/java/modchest/util/ServerPlayerEntityInterface.java b/src/main/java/modchest/util/ServerPlayerEntityInterface.java new file mode 100644 index 0000000..2f43ab9 --- /dev/null +++ b/src/main/java/modchest/util/ServerPlayerEntityInterface.java @@ -0,0 +1,10 @@ +package modchest.util; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Unique; + +public interface ServerPlayerEntityInterface { + NbtCompound getDataSaver(); + void setDataSaver(NbtCompound data); +} diff --git a/src/main/java/modchest/util/initializer.java b/src/main/java/modchest/util/initializer.java new file mode 100644 index 0000000..6308369 --- /dev/null +++ b/src/main/java/modchest/util/initializer.java @@ -0,0 +1,30 @@ +package modchest.util; + +import modchest.block.entity.modBlockEntities; +import modchest.block.modBlocks; +import modchest.event.playerAfterRespawnEvent; +import modchest.item.modItemGroup; +import modchest.item.modItems; +import modchest.networking.modNetworkingServer; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; + +public class initializer { + public static void itemGroups() { + modItemGroup.modchest(); // Item Gruppe fürs Creative-Inventar wird erstellt; In dieser Gruppe sollen + // dann alle Items und Blöcke dieser Mod angezeigt werden + } + + public static void itemsAndBlocks() { + modItems.setItems(); // die Items werden erstellt + modBlocks.setBlocks(); // Hier werden die Blöcke erstellt + modBlockEntities.registerBlockEntities(); // Die Interaktionsmenüs für die Blöcke werden erstellt + } + + public static void events() { //Events, bei denen custom Code ausgefuehrt wird, werden eingefuehrt + ServerPlayerEvents.AFTER_RESPAWN.register(new playerAfterRespawnEvent()); + } + + public static void networking() { //Identifier unter denen der Server zuhoert werden registriert + modNetworkingServer.registerS2CPackets(); + } +} diff --git a/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java b/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java new file mode 100644 index 0000000..7ee7e51 --- /dev/null +++ b/src/main/java/modchest/util/setAndGetMultiButtonsSpawn.java @@ -0,0 +1,168 @@ +package modchest.util; + +import modchest.REServerMod; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; + +public class setAndGetMultiButtonsSpawn { + + public synchronized void setMultiSpawn(ServerPlayerEntity player, int spawn) { + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); //alle daten der mod werden in diesem NBT Gespeichert + if (topNbt.get("multi_sleep") == null) { //die daten fuer multi-sleep werden in dem nbt-tag "multi_sleep" gespeichert, der wiederum um anderen nbt gespeichert wird + topNbt.put("multi_sleep", new NbtCompound()); //sollte dieser nbt-tag nicht existieren, wird ein neuer erstellt + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //nbt tag mit allen daten fuer multi-sleep wird geladen + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + int[] fullArray = new int[3]; //ein kleiner zwischenspeicher + + fullArray[0] = (int) player.getX(); + fullArray[1] = (int) player.getY(); + fullArray[2] = (int) player.getZ(); + + try { + if (subNbt != null) { + subNbt.putIntArray(String.valueOf(spawn), fullArray); //speichert unseren array an der entsprechenden nummer ab + topNbt.put("multi_sleep", subNbt); //speichert den tag unter multi_sleep im top-tag ab + castedPlayer.setDataSaver(topNbt); //speichert den top-tag wieder im spieler ab + } else { + REServerMod.LOGGER.info("Error when trying to write spawn to file!"); + player.sendMessage(Text.translatable("chat.modchest.multispawn.spawnnotsaved")); + } + } catch (Exception e) { + REServerMod.LOGGER.info("Error when saving Spawnpoint! Exception: " + e); + player.sendMessage(Text.translatable("chat.modchest.multispawn.spawnnotsaved")); + } + } + + public synchronized int[] getMultiSpawn(ServerPlayerEntity player, int spawn) { + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //wie bei setMultiSpawn() + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + int[] fullArray = new int[0]; + if (subNbt != null) { + fullArray = subNbt.getIntArray(String.valueOf(spawn)); //holt sich den ganzen Array, mit allen gespeicherten Spawnpunkten; struktur wird etwas weiter unten erklaert + } + + if (fullArray.length != 3) { //sollte der Array leer oder anderweitig ungueltig sein wird er neu erstellt + int[] tempArray = new int[3]; + for (int i = 0; i < 3; i++) { + tempArray[i] = 77889922; //Lueckenfueller; wird in deathScreenMultiButtonsC2SPacket uebrprueft und rausgefiltert + } + + try { //wenn wir gerade den Array erstellt haben, weil er ungueltig war, wird er hier in den nbt-tag abgespseichert + subNbt.putIntArray(String.valueOf(spawn), fullArray); + topNbt.put("multi_sleep", subNbt); + castedPlayer.setDataSaver(topNbt); + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when loading Spawnpoint! Exception: " + e); + player.sendMessage(Text.translatable("chat.modchest.multispawn.getable")); + } + } + + fullArray = subNbt.getIntArray(String.valueOf(spawn)); //wir laden ihn uns wieder, nur um sicher zu gehen + int[] posXYZ = new int[3]; //zwischenspeicher + try { //schaut, ob wir die daten laden koennen + posXYZ[0] = fullArray[0]; + posXYZ[1] = fullArray[1]; + posXYZ[2] = fullArray[2]; + } catch (Exception e) { //sonst geben wir folgenden Errorcode zurueck + posXYZ[0] = 77889933; + posXYZ[1] = 77889933; + posXYZ[2] = 77889933; + } + return posXYZ; + } + + public synchronized void setMultiSpawnVanilla(ServerPlayerEntity player) { //bevor der Spieler respawnt, speichern wir einmal seinen Vanillaspawn ab, um ihn spaeter wieder darauf zu setzen + BlockPos posAlt = player.getSpawnPointPosition(); //Spawnpunkt der Vanilla-respawn-funktion wird gespeichert + RegistryKey dimAlt = player.getSpawnPointDimension();//Dimension " + float angleAlt = player.getSpawnAngle(); //Blickrichtung " + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //alles in der set-Methode ganz oben erklaert + + try { //sicheerheit, weil hier mal wieder viel zwischen datentypen gewechselt wird + NbtCompound vanillaSpawnData = new NbtCompound(); + int[] location = new int[3]; //spawnpunkt wird in einen Array komprimiert + location[0] = posAlt.getX(); + location[1] = posAlt.getY(); + location[2] = posAlt.getZ(); + vanillaSpawnData.putIntArray("location", location); //und abgespeichert + vanillaSpawnData.putString("dimension", dimAlt.toString()); //dimension wird abgespeichert + vanillaSpawnData.putFloat("angle", angleAlt); //auch die Blickrichtung + vanillaSpawnData.putBoolean("used", false); //wird auf true gesetzt, sobald der Spawnpunkt wieder zurueck gesetzt wurde + + subNbt.put("vanillaSpawnData", vanillaSpawnData); //spawnpunkt wird im sub-nbt gespeichert + topNbt.put("multi_sleep", subNbt); //und im top-nbt + castedPlayer.setDataSaver(topNbt); //um dann im player gespeichert zu werden + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when saving Spawnpoint! Exception: " + e); + } + } + + public synchronized NbtCompound getMultiSpawnVanilla(ServerPlayerEntity player) { + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //steht alles wieder in der ersten methode + + if (subNbt != null) { + NbtCompound nbt = (NbtCompound) subNbt.get("vanillaSpawnData"); //hollt sich die daten + if (nbt != null) { + if (!nbt.getBoolean("used")) { + nbt.putBoolean("used", true); //setzt den verwendet boolean auf true; nicht ganz perfekt, sollte ein fehler beim speichern auftreten wird es nicht nochmal versucht, speichert aber massiv an coding und leistung + subNbt.put("vanillaSpawnData", nbt); + topNbt.put("multi_sleep", subNbt); //muss den bearbeiteten nbt wieder abgespeichert (nur der boolean wurde ueberschrieben) + castedPlayer.setDataSaver(topNbt); + return nbt; //gibt den nbt-tag an die aufrufende Methode + } else { + return null; + } + } + } else { + return null; + } + return null; + } + + public synchronized void setMultiSpawnBlank(ServerPlayerEntity player, int spawn) { //wird aufgerufen wenn das Bett dieses Spielers zerstoert wurde + ServerPlayerEntityInterface castedPlayer = (ServerPlayerEntityInterface) player; + NbtCompound topNbt = ((ServerPlayerEntityInterface) player).getDataSaver(); + if (topNbt.get("multi_sleep") == null) { + topNbt.put("multi_sleep", new NbtCompound()); + } + NbtCompound subNbt = (NbtCompound) topNbt.get("multi_sleep"); //alles wieder wie in der ersten Methode; + spawn--; //weil der Array mit Slot 0 beginnt, rutscht alles eins auf + int[] fullArray = new int[0]; + if (subNbt != null) { + fullArray = subNbt.getIntArray(String.valueOf(spawn)); //holt sich den ganzen Array, mit allen gespeicherten Spawnpunkten; struktur wird etwas weiter unten erklaert + } + + fullArray[0] = 77889944; //Errorcode der in deathScreenMultiButtonsC2SPacket als zerstoertes Bett rausgefiltert wird + fullArray[1] = 77889944; + fullArray[2] = 77889944; + + try { + subNbt.putIntArray(String.valueOf(spawn), fullArray); //wird abgespeichert + topNbt.put("multi_sleep", subNbt); + castedPlayer.setDataSaver(topNbt); + } catch (Exception e) { + REServerMod.LOGGER.info("Sorry! Error when saving Spawnpoint! Exception: " + e); + } + } +} diff --git a/src/main/resources/assets/modchest/icon.png b/src/main/resources/assets/modchest/icon.png index 047b91f..f2da261 100644 Binary files a/src/main/resources/assets/modchest/icon.png and b/src/main/resources/assets/modchest/icon.png differ diff --git a/src/main/resources/assets/modchest/icon.png.old b/src/main/resources/assets/modchest/icon.png.old new file mode 100644 index 0000000..047b91f Binary files /dev/null and b/src/main/resources/assets/modchest/icon.png.old differ diff --git a/src/main/resources/assets/modchest/lang/de_de.json b/src/main/resources/assets/modchest/lang/de_de.json index 5faed22..52767ab 100644 --- a/src/main/resources/assets/modchest/lang/de_de.json +++ b/src/main/resources/assets/modchest/lang/de_de.json @@ -3,6 +3,12 @@ "item.modchest.pirates_coin": "OP Piraten ding zum Testen", "block.modchest.steering_wheel": "Lenkrad", "itemGroup.modchest.itemlist1": "Malte's Mod", - "block.modchest.grid_block": "Grid Block" - + "block.modchest.grid_block": "Grid Block", + "chat.modchest.multispawn.beddestroyed": "Scheint so, als wäre das Bett zerstört worden!", + "chat.modchest.multispawn.respawned": "Respawne bei #%s", + "chat.modchest.multispawn.setspawn": "Nutze spawn #%s", + "chat.modchest.multispawn.setspawnerror": "Fehler beim speichern!", + "chat.modchest.multispawn.spawnnotset": "Es scheint so, als wäre dieser Spawn nicht gesetzt!", + "chat.modchest.multispawn.spawnnotsaved": "Fehler beim Versuch, diesen Spawn zu speichern!", + "chat.modchest.multispawn.getable": "Diese spawn location konnte nicht geladen werden!" } \ No newline at end of file diff --git a/src/main/resources/assets/modchest/lang/en_pt.json b/src/main/resources/assets/modchest/lang/en_pt.json index 1c6d01e..778ddd5 100644 --- a/src/main/resources/assets/modchest/lang/en_pt.json +++ b/src/main/resources/assets/modchest/lang/en_pt.json @@ -3,5 +3,12 @@ "item.modchest.pirates_coin": "Ya coin for tha pirrrrrates!", "block.modchest.steering_wheel": "Ne, du kriegst keine hilfreichen Angaben mit der Sprache!", "itemGroup.modchest.itemlist1": "Änder doch endlich die Sprache...", - "block.modchest.grid_block": "Grid Block" + "block.modchest.grid_block": "Grid Block", + "chat.modchest.multispawn.beddestroyed": "Sorry, mate! Looks like that cap'n doesn't like you", + "chat.modchest.multispawn.respawned": "Prepare to board some ship, lads!", + "chat.modchest.multispawn.setspawn": "Boarded random ship!", + "chat.modchest.multispawn.setspawnerror": "oh, that hammock is full!", + "chat.modchest.multispawn.spawnnotset": "No hammocks a'board!", + "chat.modchest.multispawn.spawnnotsaved": "Couldn't remember that ship...", + "chat.modchest.multispawn.getable": "Na ship could be found!" } diff --git a/src/main/resources/assets/modchest/lang/en_us.json b/src/main/resources/assets/modchest/lang/en_us.json index beb2031..0030f89 100644 --- a/src/main/resources/assets/modchest/lang/en_us.json +++ b/src/main/resources/assets/modchest/lang/en_us.json @@ -3,5 +3,13 @@ "item.modchest.pirates_coin": "Pirate's Coin", "block.modchest.steering_wheel": "Steering Wheel", "itemGroup.modchest.itemlist1": "Theo macht unfug", - "block.modchest.grid_block": "Grid Block" + "block.modchest.grid_block": "Grid Block", + "itemGroup.modchest.itemlist1": "new blocks", + "chat.modchest.multispawn.beddestroyed": "Oh shit! Looks like that bed got destroyed!", + "chat.modchest.multispawn.respawned": "Respawn #%s used", + "chat.modchest.multispawn.setspawn": "Set spawn #%s", + "chat.modchest.multispawn.setspawnerror": "Sorry! Error when setting that spawn!", + "chat.modchest.multispawn.spawnnotset": "Sorry! Looks like that Spawnpoint isn't set yet!", + "chat.modchest.multispawn.spawnnotsaved": "Sorry! Error when trying to save your spawn!", + "chat.modchest.multispawn.getable": "Sorry! Couldn't get your spawnlocation!" } \ No newline at end of file diff --git a/src/main/resources/data/icon.png b/src/main/resources/data/icon.png new file mode 100644 index 0000000..f2da261 Binary files /dev/null and b/src/main/resources/data/icon.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index ad0d2aa..20a6044 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -16,7 +16,7 @@ "sources": "https://github.com/FabricMC/fabric-example-mod" }, "license": "CC0-1.0", - "icon": "assets/reservermod/icon.png", + "icon": "assets/modchest/icon.png", "environment": "*", "entrypoints": { "main": [ diff --git a/src/main/resources/reservermod.mixins.json b/src/main/resources/reservermod.mixins.json index 62e600b..62856ee 100644 --- a/src/main/resources/reservermod.mixins.json +++ b/src/main/resources/reservermod.mixins.json @@ -1,11 +1,12 @@ { - "required": true, - "package": "modchest.mixin", - "compatibilityLevel": "JAVA_17", - "mixins": [ - "ExampleMixin" - ], - "injectors": { - "defaultRequire": 1 + "required": true, + "package": "modchest.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "ServerPlayerEntityMixin", + "bedBlock" + ], + "injectors": { + "defaultRequire": 1 } } \ No newline at end of file