commit 014f65bc8654c03359dcfa0cca94f1e858a1a870 Author: Flemmli97 Date: Sun Aug 23 14:52:36 2020 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..550b373 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# fabric + +run/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..fd96346 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Fabric Example Mod + +## Setup + +For setup instructions please see the [fabric wiki page](https://fabricmc.net/wiki/tutorial:setup) that relates to the IDE that you are using. + +## License + +This template is available under the CC0 license. Feel free to learn from it and incorporate it in your own projects. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..7edb9ff --- /dev/null +++ b/build.gradle @@ -0,0 +1,84 @@ +plugins { + id 'fabric-loom' version '0.4-SNAPSHOT' + id 'maven-publish' +} + +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 + +archivesBaseName = project.archives_base_name +version = project.mod_version +group = project.maven_group + +repositories { + mavenCentral() +} + +dependencies { + //to change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + compile group: 'org.yaml', name: 'snakeyaml', version: '1.25' + include group: 'org.yaml', name: 'snakeyaml', version: '1.25' + + // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. + // You may need to force-disable transitiveness on them. +} + +processResources { + inputs.property "version", project.version + + from(sourceSets.main.resources.srcDirs) { + include "fabric.mod.json" + expand "version": project.version + } + + from(sourceSets.main.resources.srcDirs) { + exclude "fabric.mod.json" + } +} + +// ensure that the encoding is set to UTF-8, no matter what the system default is +// this fixes some edge cases with special characters not displaying correctly +// see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html +tasks.withType(JavaCompile) { + options.encoding = "UTF-8" +} + +// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task +// if it is present. +// If you remove this task, sources will not be generated. +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = "sources" + from sourceSets.main.allSource +} + +jar { + from "LICENSE" +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + // add all the jars that should be included when publishing to maven + artifact(remapJar) { + builtBy remapJar + } + artifact(sourcesJar) { + builtBy remapSourcesJar + } + } + } + + // select the repositories you want to publish to + repositories { + // uncomment to publish to the local maven + // mavenLocal() + } +} diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..14cc199 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,18 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G + +# Fabric Properties + # check these on https://fabricmc.net/use + minecraft_version=1.16.2 + yarn_mappings=1.16.2+build.1 + loader_version=0.9.1+build.205 + +# Mod Properties + mod_version = 1.0.0 + maven_group = com.flemmli97 + archives_base_name = thisismyland + +# Dependencies + # currently not on the main fabric site, check on the maven: https://maven.fabricmc.net/net/fabricmc/fabric-api/fabric-api + fabric_version=0.17.2+build.396-1.16 + cca_version=2.5.0-nightly.1.16.2-rc2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..490fda8 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..622ab64 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..2fe81a7 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or 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 UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# 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 + ;; + 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" + which java >/dev/null 2>&1 || 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 + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..62bd9b9 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@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=. +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%" == "0" goto init + +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 init + +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 + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +: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 %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..5b60df3 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + jcenter() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + gradlePluginPortal() + } +} diff --git a/src/main/java/com/flemmli97/flan/Flan.java b/src/main/java/com/flemmli97/flan/Flan.java new file mode 100644 index 0000000..2ea1210 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/Flan.java @@ -0,0 +1,37 @@ +package com.flemmli97.flan; + +import com.flemmli97.flan.claim.ObjectToPermissionMap; +import com.flemmli97.flan.commands.CommandClaim; +import com.flemmli97.flan.config.ConfigHandler; +import com.flemmli97.flan.event.BlockInteractEvents; +import com.flemmli97.flan.event.EntityInteractEvents; +import com.flemmli97.flan.event.ItemInteractEvents; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.player.AttackBlockCallback; +import net.fabricmc.fabric.api.event.player.AttackEntityCallback; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.fabricmc.fabric.api.event.player.UseEntityCallback; +import net.fabricmc.fabric.api.event.player.UseItemCallback; + +public class Flan implements ModInitializer { + + @Override + public void onInitialize() { + + //Events + AttackBlockCallback.EVENT.register(BlockInteractEvents::breakBlocks); + UseBlockCallback.EVENT.register(BlockInteractEvents::useBlocks); + UseEntityCallback.EVENT.register(EntityInteractEvents::useAtEntity); + AttackEntityCallback.EVENT.register(EntityInteractEvents::attackEntity); + UseItemCallback.EVENT.register(ItemInteractEvents::useItem); + ServerLifecycleEvents.SERVER_STARTING.register(ConfigHandler::serverLoad); + ServerLifecycleEvents.SERVER_STARTING.register(ObjectToPermissionMap::reload); + //Explosion + //XP + //TARGETBLOCK + //Commands + CommandRegistrationCallback.EVENT.register(CommandClaim::register); + } +} diff --git a/src/main/java/com/flemmli97/flan/IClaimData.java b/src/main/java/com/flemmli97/flan/IClaimData.java new file mode 100644 index 0000000..156f07a --- /dev/null +++ b/src/main/java/com/flemmli97/flan/IClaimData.java @@ -0,0 +1,6 @@ +package com.flemmli97.flan; + +public interface IClaimData { + + Object getClaimData(); +} diff --git a/src/main/java/com/flemmli97/flan/claim/Claim.java b/src/main/java/com/flemmli97/flan/claim/Claim.java new file mode 100644 index 0000000..106547c --- /dev/null +++ b/src/main/java/com/flemmli97/flan/claim/Claim.java @@ -0,0 +1,417 @@ +package com.flemmli97.flan.claim; + +import com.flemmli97.flan.player.PlayerClaimData; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.math.BlockPos; + +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class Claim { + + private boolean dirty; + private int minX, minZ, maxX, maxZ, minY; + + private UUID owner; + private UUID claimID; + private final EnumSet globalPerm = EnumSet.noneOf(EnumPermission.class); + private final Map> permissions = Maps.newHashMap(); + + private final Map playersGroups = Maps.newHashMap(); + + private final List subClaims = Lists.newArrayList(); + + /** + * Flag for players tracking this claim + */ + private boolean removed; + + private Claim() { + } + + public Claim(BlockPos pos1, BlockPos pos2, UUID creator) { + this(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ(), Math.min(pos1.getY(), pos2.getY()), creator); + } + + public Claim(int x1, int x2, int z1, int z2, int minY, UUID creator) { + this.minX = Math.min(x1, x2); + this.minZ = Math.min(z1, z2); + this.maxX = Math.max(x1, x2); + this.maxZ = Math.max(z1, z2); + this.minY = Math.max(0, minY); + this.owner = creator; + } + + public static Claim fromTag(CompoundTag tag) { + Claim claim = new Claim(); + claim.read(tag); + return claim; + } + + public static Claim fromJson(JsonObject obj, UUID owner) { + Claim claim = new Claim(); + claim.readJson(obj, owner); + return claim; + } + + public void setClaimID(UUID uuid) { + this.claimID = uuid; + this.setDirty(); + } + + public UUID getClaimID() { + return this.claimID; + } + + public UUID getOwner() { + return this.owner; + } + + public int getPlane() { + return (this.maxX - this.minX) * (this.maxZ - this.minZ); + } + + /** + * @return The claims dimension in order: x, X, z, Z, y + */ + public int[] getDimensions() { + return new int[]{this.minX, this.maxX, this.minZ, this.maxZ, this.minY}; + } + + public boolean insideClaim(BlockPos pos) { + return this.minX <= pos.getX() && this.maxX >= pos.getX() && this.minZ <= pos.getZ() && this.maxZ >= pos.getZ() && this.minY <= pos.getY(); + } + + public boolean intersects(Claim other) { + return this.minX < other.maxX && this.maxX > other.minX && this.minZ < other.maxZ && this.maxZ > other.minZ; + } + + public boolean isCorner(BlockPos pos) { + return (pos.getX() == this.minX && pos.getZ() == this.minZ) || (pos.getX() == this.minX && pos.getZ() == this.maxZ) + || (pos.getX() == this.maxX && pos.getZ() == this.minZ) || (pos.getX() == this.maxX && pos.getZ() == this.maxZ); + } + + public void remove() { + this.removed = true; + } + + public boolean isRemoved() { + return this.removed; + } + + public boolean canInteract(PlayerEntity player, EnumPermission perm, BlockPos pos) { + if (perm == EnumPermission.EXPLOSIONS || perm == EnumPermission.WITHER) { + for (Claim claim : this.subClaims) { + if (claim.insideClaim(pos)) { + if (claim.canInteract(player, perm, pos)) + return true; + break; + } + } + return this.permEnabled(perm); + } + if (player.getUuid().equals(this.owner)) + return true; + PlayerClaimData data = PlayerClaimData.get(player); + if (player.hasPermissionLevel(2) && data.isAdminIgnoreClaim()) + return true; + for (Claim claim : this.subClaims) { + if (claim.insideClaim(pos)) { + if (claim.canInteract(player, perm, pos)) + return true; + break; + } + } + if (this.playersGroups.containsKey(player.getUuid())) { + EnumMap map = this.permissions.get(this.playersGroups.get(player.getUuid())); + if (map != null && map.containsKey(perm)) + return map.get(perm); + } + return this.permEnabled(perm); + } + + public boolean permEnabled(EnumPermission perm) { + return this.globalPerm.contains(perm); + } + + public boolean tryCreateSubClaim(BlockPos pos1, BlockPos pos2) { + return false; + } + + public Claim getSubClaim(BlockPos pos) { + for (Claim claim : this.subClaims) + if (claim.insideClaim(pos)) + return claim; + return null; + } + + public boolean setPlayerGroup(UUID player, String group, boolean force) { + if (group == null) { + this.playersGroups.remove(player); + this.setDirty(); + return true; + } + if (!this.playersGroups.containsKey(player) || force) { + this.playersGroups.put(player, group); + this.setDirty(); + return true; + } + return false; + } + + public List playersFromGroup(MinecraftServer server, String group) { + List l = Lists.newArrayList(); + this.playersGroups.forEach((uuid, g) -> { + if (g.equals(group)) + l.add(uuid); + }); + List names = Lists.newArrayList(); + l.forEach(uuid -> { + GameProfile prof = server.getUserCache().getByUuid(uuid); + if (prof != null) + names.add(prof.getName()); + }); + names.sort(null); + return names; + } + + public void editGlobalPerms(EnumPermission toggle) { + if (this.globalPerm.contains(toggle)) + this.globalPerm.remove(toggle); + else + this.globalPerm.add(toggle); + this.setDirty(); + } + + /** + * Edit the permissions for a group. If not defined for the group creates a new default permission map for that group + * + * @param mode -1 = makes it resort to the global perm, 0 = deny perm, 1 = allow perm + * @return If editing was successful or not + */ + public boolean editPerms(PlayerEntity player, String group, EnumPermission perm, int mode) { + if (player.getUuid().equals(this.owner) || this.canInteract(player, EnumPermission.EDITPERMS, player.getBlockPos())) { + if (mode > 1) + mode = -1; + boolean has = this.permissions.containsKey(perm); + EnumMap perms = has ? this.permissions.get(group) : new EnumMap(EnumPermission.class); + if (mode == -1) + perms.remove(perm); + else + perms.put(perm, mode == 1); + if (!has) + this.permissions.put(group, perms); + this.setDirty(); + return true; + } + return false; + } + + public boolean removePermGroup(PlayerEntity player, String group) { + if (player.getUuid().equals(this.owner) || this.canInteract(player, EnumPermission.EDITPERMS, player.getBlockPos())) { + this.permissions.remove(group); + List toRemove = Lists.newArrayList(); + this.playersGroups.forEach((uuid, g) -> { + if (g.equals(group)) + toRemove.add(uuid); + }); + toRemove.forEach(uuid -> this.playersGroups.remove(uuid)); + this.setDirty(); + return true; + } + return false; + } + + public int groupHasPerm(String rank, EnumPermission perm) { + if (!this.permissions.containsKey(rank) || !this.permissions.get(rank).containsKey(perm)) + return -1; + return this.permissions.get(rank).get(perm) ? 1 : 0; + } + + public List groups() { + List l = Lists.newArrayList(this.permissions.keySet()); + l.sort(null); + return l; + } + + public boolean addSubClaims(Claim claim) { + return false; + } + + public void setDirty() { + this.dirty = true; + } + + public boolean isDirty() { + return this.dirty; + } + + public void readJson(JsonObject obj, UUID uuid) { + JsonArray pos = obj.getAsJsonArray("PosxXzZY"); + this.minX = pos.get(0).getAsInt(); + this.maxX = pos.get(1).getAsInt(); + this.minZ = pos.get(2).getAsInt(); + this.maxZ = pos.get(3).getAsInt(); + this.minY = pos.get(4).getAsInt(); + this.owner = uuid; + this.claimID = UUID.fromString(obj.get("ID").getAsString()); + this.globalPerm.clear(); + this.permissions.clear(); + this.subClaims.clear(); + if (obj.has("GlobalPerms")) { + obj.getAsJsonArray("GlobalPerms").forEach(perm -> this.globalPerm.add(EnumPermission.valueOf(perm.getAsString()))); + } + if (obj.has("PermGroup")) { + JsonObject perms = obj.getAsJsonObject("PermGroup"); + perms.entrySet().forEach(key -> { + EnumMap map = new EnumMap(EnumPermission.class); + JsonObject group = key.getValue().getAsJsonObject(); + group.entrySet().forEach(gkey -> map.put(EnumPermission.valueOf(gkey.getKey()), gkey.getValue().getAsBoolean())); + this.permissions.put(key.getKey(), map); + }); + } + if (obj.has("PlayerPerms")) { + JsonObject pl = obj.getAsJsonObject("PlayerPerms"); + pl.entrySet().forEach(key -> this.playersGroups.put(UUID.fromString(key.getKey()), key.getValue().getAsString())); + } + if (obj.has("SubClaims")) { + obj.getAsJsonArray("SubClaims").forEach(sub -> this.subClaims.add(Claim.fromJson(sub.getAsJsonObject(), this.owner))); + } + } + + public JsonObject toJson(JsonObject obj) { + JsonArray pos = new JsonArray(); + pos.add(this.minX); + pos.add(this.maxX); + pos.add(this.minZ); + pos.add(this.maxZ); + pos.add(this.minY); + obj.add("PosxXzZY", pos); + + obj.addProperty("ID", this.claimID.toString()); + if (!this.globalPerm.isEmpty()) { + JsonArray gPerm = new JsonArray(); + this.globalPerm.forEach(p -> gPerm.add(p.toString())); + obj.add("GlobalPerms", gPerm); + } + if (!this.permissions.isEmpty()) { + JsonObject perms = new JsonObject(); + this.permissions.forEach((s, pmap) -> { + JsonObject group = new JsonObject(); + pmap.forEach((perm, bool) -> group.addProperty(perm.toString(), bool)); + perms.add(s, group); + }); + obj.add("PermGroup", perms); + } + if (!this.playersGroups.isEmpty()) { + JsonObject pl = new JsonObject(); + this.playersGroups.forEach((uuid, s) -> pl.addProperty(uuid.toString(), s)); + obj.add("PlayerPerms", pl); + } + if (!this.subClaims.isEmpty()) { + JsonArray list = new JsonArray(); + this.subClaims.forEach(p -> list.add(p.toJson(new JsonObject()))); + obj.add("SubClaims", list); + } + return obj; + } + + public CompoundTag save(CompoundTag tag) { + tag.putIntArray("PosxXzZY", new int[]{this.minX, this.maxX, this.minZ, this.maxZ, this.minY}); + tag.putUuid("Owner", this.owner); + tag.putUuid("ID", this.claimID); + if (!this.globalPerm.isEmpty()) { + ListTag list = new ListTag(); + this.globalPerm.forEach(p -> list.add(StringTag.of(p.toString()))); + tag.put("GlobalPerms", list); + } + if (!this.permissions.isEmpty()) { + CompoundTag perms = new CompoundTag(); + this.permissions.forEach((s, pmap) -> { + CompoundTag group = new CompoundTag(); + pmap.forEach((perm, bool) -> group.putBoolean(perm.toString(), bool)); + perms.put(s, group); + }); + tag.put("PermGroup", perms); + } + if (!this.playersGroups.isEmpty()) { + CompoundTag pl = new CompoundTag(); + this.playersGroups.forEach((uuid, s) -> pl.putString(uuid.toString(), s)); + tag.put("PlayerPerms", pl); + } + if (!this.subClaims.isEmpty()) { + ListTag list = new ListTag(); + this.subClaims.forEach(p -> list.add(p.save(new CompoundTag()))); + tag.put("SubClaims", list); + } + return tag; + } + + public void read(CompoundTag tag) { + int[] pos = tag.getIntArray("PosxXzZY"); + this.minY = pos[0]; + this.maxX = pos[1]; + this.minZ = pos[2]; + this.maxZ = pos[3]; + this.minY = pos[4]; + this.owner = tag.getUuid("Owner"); + this.claimID = tag.getUuid("ID"); + this.globalPerm.clear(); + this.permissions.clear(); + this.subClaims.clear(); + if (tag.contains("GlobalPerms")) { + tag.getList("GlobalPerms", 8).forEach(perm -> this.globalPerm.add(EnumPermission.valueOf(perm.asString()))); + } + if (tag.contains("PermGroup")) { + CompoundTag perms = tag.getCompound("PermGroup"); + perms.getKeys().forEach(key -> { + EnumMap map = new EnumMap(EnumPermission.class); + CompoundTag group = perms.getCompound(key); + group.getKeys().forEach(gkey -> map.put(EnumPermission.valueOf(gkey), group.getBoolean(gkey))); + this.permissions.put(key, map); + }); + } + if (tag.contains("PlayerPerms")) { + CompoundTag pl = tag.getCompound("PlayerPerms"); + pl.getKeys().forEach(key -> this.playersGroups.put(UUID.fromString(key), pl.getString(key))); + } + if (tag.contains("SubClaims")) { + tag.getList("SubClaims", 10).forEach(sub -> this.subClaims.add(Claim.fromTag((CompoundTag) sub))); + } + } + + @Override + public int hashCode() { + return this.claimID.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj instanceof Claim) + return this.claimID.equals(((Claim) obj).claimID); + return false; + } + + @Override + public String toString() { + return String.format("Claim:[Owner:%s, from: x=%d; z=%d, to: x=%d, z=%d", this.owner.toString(), this.minX, this.minZ, this.maxX, this.maxZ); + } + + public String formattedClaim() { + return String.format("[x=%d,z=%d] to: [x=%d,z=%d]", this.minX, this.minZ, this.maxX, this.maxZ); + } +} diff --git a/src/main/java/com/flemmli97/flan/claim/ClaimStorage.java b/src/main/java/com/flemmli97/flan/claim/ClaimStorage.java new file mode 100644 index 0000000..0cd0666 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/claim/ClaimStorage.java @@ -0,0 +1,299 @@ +package com.flemmli97.flan.claim; + +import com.flemmli97.flan.IClaimData; +import com.flemmli97.flan.player.PlayerClaimData; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.ibm.icu.impl.Pair; +import it.unimi.dsi.fastutil.longs.Long2ObjectArrayMap; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.util.WorldSavePath; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +public class ClaimStorage { + + public static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + + public final Long2ObjectArrayMap> claims = new Long2ObjectArrayMap(); + public final Map claimUUIDMap = Maps.newHashMap(); + public final Map> playerClaimMap = Maps.newHashMap(); + + public static ClaimStorage get(ServerWorld world) { + return (ClaimStorage) ((IClaimData) world).getClaimData(); + } + + public ClaimStorage(MinecraftServer server, RegistryKey key) { + this.read(server, key); + } + + public UUID generateUUID() { + UUID uuid = UUID.randomUUID(); + if (this.claimUUIDMap.containsKey(uuid)) + return generateUUID(); + return uuid; + } + + public boolean createClaim(BlockPos pos1, BlockPos pos2, PlayerEntity player) { + Claim claim = new Claim(pos1.down(5), pos2.down(5), player.getUuid()); + boolean conflicts = conflicts(claim, null); + if (!conflicts) { + PlayerClaimData data = PlayerClaimData.get(player); + if (!data.useClaimBlocks(claim.getPlane())) + return false; + claim.setClaimID(this.generateUUID()); + this.addClaim(claim); + data.addDisplayClaim(claim); + return true; + } + player.sendMessage(Text.of("Error creating claim"), false); + return false; + } + + private boolean conflicts(Claim claim, Claim except) { + int[] chunks = getChunkPos(claim); + for (int x = chunks[0]; x <= chunks[1]; x++) + for (int z = chunks[2]; z <= chunks[3]; z++) { + List claims = this.claims.get(new ChunkPos(x, z).toLong()); + if (claims != null) + for (Claim other : claims) { + if (claim.intersects(other) && !claim.equals(except)) { + return true; + } + } + } + return false; + } + + public boolean deleteClaim(Claim claim) { + System.out.println("claim " + claim); + System.out.println("claimmap " + this.claims); + + claim.remove(); + int[] pos = getChunkPos(claim); + System.out.println("" + Arrays.toString(pos)); + for (int x = pos[0]; x <= pos[1]; x++) + for (int z = pos[2]; z <= pos[3]; z++) { + ChunkPos chunkPos = new ChunkPos(x, z); + this.claims.compute(chunkPos.toLong(), (key, val) -> { + if (val == null) + return null; + val.remove(claim); + return val.isEmpty() ? null : val; + }); + } + System.out.println(this.claims); + this.playerClaimMap.getOrDefault(claim.getOwner(), Sets.newHashSet()).remove(claim); + return this.claimUUIDMap.remove(claim.getClaimID()) != null; + } + + public boolean resizeClaim(Claim claim, BlockPos pos) { + return false; + } + + public Claim getClaimAt(BlockPos pos) { + long chunk = new ChunkPos(pos).toLong(); + if (this.claims.containsKey(chunk)) + for (Claim claim : this.claims.get(chunk)) { + if (claim.insideClaim(pos)) + return claim; + } + return null; + } + + private void addClaim(Claim claim) { + System.out.println("adding claim " + claim); + int[] pos = getChunkPos(claim); + System.out.println("" + Arrays.toString(pos)); + for (int x = pos[0]; x <= pos[1]; x++) + for (int z = pos[2]; z <= pos[3]; z++) { + ChunkPos chunkPos = new ChunkPos(x, z); + this.claims.merge(chunkPos.toLong(), Lists.newArrayList(claim), (key, val) -> { + val.add(claim); + return val; + }); + } + System.out.println("claimmap " + this.claims); + this.claimUUIDMap.put(claim.getClaimID(), claim); + this.playerClaimMap.merge(claim.getOwner(), Sets.newHashSet(claim), (key, val) -> { + val.add(claim); + return val; + }); + } + + public Collection allClaimsFromPlayer(UUID player) { + return this.playerClaimMap.containsKey(player) ? ImmutableSet.copyOf(this.playerClaimMap.get(player)) : ImmutableSet.of(); + } + + public static int[] getChunkPos(Claim claim) { + int[] dim = claim.getDimensions(); + int[] pos = new int[4]; + pos[0] = dim[0] >> 4; + pos[1] = dim[1] >> 4; + pos[2] = dim[2] >> 4; + pos[3] = dim[3] >> 4; + return pos; + } + + public void fromTag(CompoundTag compoundTag) { + ListTag list = compoundTag.getList("Claims", 10); + list.forEach(tag -> { + Claim claim = Claim.fromTag((CompoundTag) tag); + this.addClaim(claim); + }); + } + + public CompoundTag toTag(CompoundTag compoundTag) { + ListTag list = new ListTag(); + this.claims.forEach((l, cList) -> + cList.forEach(claim -> list.add(claim.save(new CompoundTag())))); + compoundTag.put("Claims", list); + return compoundTag; + } + + public void read(MinecraftServer server, RegistryKey reg) { + File dir = new File(DimensionType.getSaveDirectory(reg, server.getSavePath(WorldSavePath.ROOT).toFile()), "/data/claims/"); + if (dir.exists()) { + try { + for (File file : dir.listFiles()) { + if (!file.getName().endsWith(".json")) + continue; + UUID uuid = UUID.fromString(file.getName().replace(".json", "")); + FileReader reader = new FileReader(file); + JsonArray arr = GSON.fromJson(reader, JsonArray.class); + if (arr == null) + continue; + arr.forEach(el -> { + if (el.isJsonObject()) { + this.addClaim(Claim.fromJson((JsonObject) el, uuid)); + } + }); + reader.close(); + } + } catch (IOException e) { + + } + } + } + + public void save(MinecraftServer server, RegistryKey reg) { + File dir = new File(DimensionType.getSaveDirectory(reg, server.getSavePath(WorldSavePath.ROOT).toFile()), "/data/claims/"); + if (!dir.exists()) + dir.mkdir(); + try { + for (Map.Entry> e : this.playerClaimMap.entrySet()) { + + File file = new File(dir, e.getKey().toString() + ".json"); + if (!file.exists()) { + if (e.getValue().isEmpty()) + continue; + file.createNewFile(); + } + FileWriter writer = new FileWriter(file); + JsonArray arr = new JsonArray(); + e.getValue().forEach(claim -> arr.add(claim.toJson(new JsonObject()))); + GSON.toJson(arr, writer); + writer.close(); + } + } catch (IOException e) { + + } + } + + public static void readGriefPreventionData(MinecraftServer server) { + Yaml yml = new Yaml(); + File griefPrevention = server.getSavePath(WorldSavePath.ROOT).resolve("GriefPreventionData/ClaimData").toFile(); + if (!griefPrevention.exists()) + return; + Map> subClaimMap = Maps.newHashMap(); + Map intFileMap = Maps.newHashMap(); + + try { + //Get all parent claims + for (File f : griefPrevention.listFiles()) { + if (f.getName().endsWith(".yml")) { + FileReader reader = new FileReader(f); + Map values = yml.load(reader); + if (values.get("Parent Claim ID").equals(Integer.valueOf(-1))) { + intFileMap.put(Integer.valueOf(values.get("Parent Claim ID").toString()), f); + } + } + } + //Map child to parent claims + for (File f : griefPrevention.listFiles()) { + if (f.getName().endsWith(".yml")) { + FileReader reader = new FileReader(f); + Map values = yml.load(reader); + if (!values.get("Parent Claim ID").equals(Integer.valueOf(-1))) { + subClaimMap.merge(intFileMap.get(Integer.valueOf(values.get("Parent Claim ID").toString())) + , Lists.newArrayList(f), (key, val) -> { + val.add(f); + return val; + }); + } + } + } + + for (File parent : intFileMap.values()) { + Pair parentClaim = parseFromYaml(parent, yml); + List childs = subClaimMap.get(parent); + if (childs != null && !childs.isEmpty()) { + for (File childF : childs) + parentClaim.second.addSubClaims(parseFromYaml(childF, yml).second); + } + ClaimStorage.get(server.getWorld(worldRegFromString(parentClaim.first))).addClaim(parentClaim.second); + } + } catch (IOException e) { + + } + } + + private static Pair parseFromYaml(File file, Yaml yml) throws IOException { + FileReader reader = new FileReader(file); + Map values = yml.load(reader); + reader.close(); + UUID owner = UUID.fromString(values.get("Owner").toString()); + String[] lesserCorner = values.get("Lesser Boundary Corner").toString().split(";"); + String[] greaterCorner = values.get("Greater Boundary Corner").toString().split(";"); + Claim claim = new Claim(Integer.parseInt(lesserCorner[1]), Integer.parseInt(greaterCorner[1]), + Integer.parseInt(lesserCorner[3]), Integer.parseInt(greaterCorner[3]), + Integer.parseInt(lesserCorner[2]), owner); + + + return Pair.of(lesserCorner[0], claim); + } + + public static RegistryKey worldRegFromString(String spigot) { + if (spigot.equals("world_the_end")) + return World.END; + if (spigot.equals("world_nether")) + return World.NETHER; + return World.OVERWORLD; + } +} diff --git a/src/main/java/com/flemmli97/flan/claim/EnumClaimRank.java b/src/main/java/com/flemmli97/flan/claim/EnumClaimRank.java new file mode 100644 index 0000000..a09475e --- /dev/null +++ b/src/main/java/com/flemmli97/flan/claim/EnumClaimRank.java @@ -0,0 +1,8 @@ +package com.flemmli97.flan.claim; + +public enum EnumClaimRank { + + COOWNER, + BUILDER, + MANAGER +} diff --git a/src/main/java/com/flemmli97/flan/claim/EnumPermission.java b/src/main/java/com/flemmli97/flan/claim/EnumPermission.java new file mode 100644 index 0000000..396a63d --- /dev/null +++ b/src/main/java/com/flemmli97/flan/claim/EnumPermission.java @@ -0,0 +1,53 @@ +package com.flemmli97.flan.claim; + +import com.flemmli97.flan.config.ConfigHandler; +import net.minecraft.item.Item; +import net.minecraft.item.Items; + +public enum EnumPermission { + + EDITPERMS(Items.COMMAND_BLOCK), //--- + EDITCLAIM(ConfigHandler.config.claimingItem), //--- + BREAK(Items.DIAMOND_PICKAXE), + PLACE(Items.GRASS_BLOCK), + OPENCONTAINER(Items.CHEST), //--- + ANVIL(Items.ANVIL), + BED(Items.RED_BED), + BEACON(Items.BEACON), + DOOR(Items.OAK_DOOR), + FENCEGATE(Items.OAK_FENCE_GATE), + TRAPDOOR(Items.OAK_TRAPDOOR), + BUTTONLEVER(Items.LEVER), + PRESSUREPLATE(Items.STONE_PRESSURE_PLATE), + NOTEBLOCK(Items.NOTE_BLOCK), + REDSTONE(Items.REDSTONE), + JUKEBOX(Items.JUKEBOX), + ITEMFRAMEROTATE(Items.ITEM_FRAME), + TARGETBLOCK(Items.TARGET), + PROJECTILES(Items.ARROW), + TRAMPLE(Items.FARMLAND), + PORTAL(Items.OBSIDIAN), + BOAT(Items.OAK_BOAT), + MINECART(Items.MINECART), + BUCKET(Items.BUCKET), + ENDERPEARL(Items.ENDER_PEARL), + ANIMALINTERACT(Items.CHICKEN_SPAWN_EGG), + HURTANIMAL(Items.BEEF), + HURTPLAYER(Items.DIAMOND_SWORD), + XP(Items.EXPERIENCE_BOTTLE), + TRADING(Items.EMERALD), + EXPLOSIONS(Items.TNT), + WITHER(Items.WITHER_SKELETON_SKULL), + ARMORSTAND(Items.ARMOR_STAND), + BREAKNONLIVING(Items.COMMAND_BLOCK_MINECART); + + private Item item; + + EnumPermission(Item item) { + this.item = item; + } + + public Item getItem() { + return this.item; + } +} diff --git a/src/main/java/com/flemmli97/flan/claim/ObjectToPermissionMap.java b/src/main/java/com/flemmli97/flan/claim/ObjectToPermissionMap.java new file mode 100644 index 0000000..b4ed178 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/claim/ObjectToPermissionMap.java @@ -0,0 +1,76 @@ +package com.flemmli97.flan.claim; + +import com.google.common.collect.Maps; +import net.minecraft.block.AbstractButtonBlock; +import net.minecraft.block.AbstractPressurePlateBlock; +import net.minecraft.block.AbstractRedstoneGateBlock; +import net.minecraft.block.AnvilBlock; +import net.minecraft.block.BeaconBlock; +import net.minecraft.block.BedBlock; +import net.minecraft.block.BellBlock; +import net.minecraft.block.Block; +import net.minecraft.block.CampfireBlock; +import net.minecraft.block.ChorusFlowerBlock; +import net.minecraft.block.DaylightDetectorBlock; +import net.minecraft.block.DoorBlock; +import net.minecraft.block.FarmlandBlock; +import net.minecraft.block.FenceGateBlock; +import net.minecraft.block.JukeboxBlock; +import net.minecraft.block.LeverBlock; +import net.minecraft.block.NetherPortalBlock; +import net.minecraft.block.NoteBlock; +import net.minecraft.block.RedstoneWireBlock; +import net.minecraft.block.TargetBlock; +import net.minecraft.block.TntBlock; +import net.minecraft.block.TrapdoorBlock; +import net.minecraft.block.TurtleEggBlock; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.registry.Registry; + +import java.util.Map; + +public class ObjectToPermissionMap { + + private static Map blockToPermission = Maps.newHashMap(); + + public static void reload(MinecraftServer server) { + blockToPermission.clear(); + for (Block block : Registry.BLOCK) { + if (block instanceof AnvilBlock) + blockToPermission.put(block, EnumPermission.ANVIL); + if (block instanceof BedBlock) + blockToPermission.put(block, EnumPermission.BED); + if (block instanceof BeaconBlock) + blockToPermission.put(block, EnumPermission.BEACON); + if (block instanceof DoorBlock) + blockToPermission.put(block, EnumPermission.DOOR); + if (block instanceof FenceGateBlock) + blockToPermission.put(block, EnumPermission.FENCEGATE); + if (block instanceof TrapdoorBlock) + blockToPermission.put(block, EnumPermission.TRAPDOOR); + if (block instanceof LeverBlock || block instanceof AbstractButtonBlock) + blockToPermission.put(block, EnumPermission.BUTTONLEVER); + if (block instanceof NoteBlock) + blockToPermission.put(block, EnumPermission.NOTEBLOCK); + if (block instanceof AbstractRedstoneGateBlock || block instanceof RedstoneWireBlock || block instanceof DaylightDetectorBlock) + blockToPermission.put(block, EnumPermission.REDSTONE); + if (block instanceof JukeboxBlock) + blockToPermission.put(block, EnumPermission.JUKEBOX); + if (block instanceof AbstractPressurePlateBlock) + blockToPermission.put(block, EnumPermission.PRESSUREPLATE); + if (block instanceof NetherPortalBlock) + blockToPermission.put(block, EnumPermission.PORTAL); + if (block instanceof TurtleEggBlock || block instanceof FarmlandBlock) + blockToPermission.put(block, EnumPermission.TRAMPLE); + if (block instanceof TargetBlock) + blockToPermission.put(block, EnumPermission.TARGETBLOCK); + if (block instanceof BellBlock || block instanceof CampfireBlock + || block instanceof TntBlock || block instanceof ChorusFlowerBlock) + blockToPermission.put(block, EnumPermission.PROJECTILES); + } + } + + public static EnumPermission getFromBlock(Block block) { + return blockToPermission.get(block); + } +} diff --git a/src/main/java/com/flemmli97/flan/claim/ParticleIndicators.java b/src/main/java/com/flemmli97/flan/claim/ParticleIndicators.java new file mode 100644 index 0000000..caf0163 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/claim/ParticleIndicators.java @@ -0,0 +1,16 @@ +package com.flemmli97.flan.claim; + +import net.minecraft.particle.DustParticleEffect; + +public class ParticleIndicators { + + public static final DustParticleEffect CLAIMCORNER = new DustParticleEffect(0.0F, 1.0F, 0.0F, 1.0F); + public static final DustParticleEffect CLAIMMIDDLE = new DustParticleEffect(0.0F, 1.0F, 1.0F, 1.0F); + + public static final DustParticleEffect SUBCLAIMCORNER = DustParticleEffect.RED; + public static final DustParticleEffect SUBCLAIMMIDDLE = DustParticleEffect.RED; + + public static final DustParticleEffect SETCORNER = new DustParticleEffect(0.0F, 0.9F, 1.0F, 1.0F); + + public static final DustParticleEffect OVERLAPCLAIM = DustParticleEffect.RED; +} diff --git a/src/main/java/com/flemmli97/flan/commands/CommandClaim.java b/src/main/java/com/flemmli97/flan/commands/CommandClaim.java new file mode 100644 index 0000000..d1c249f --- /dev/null +++ b/src/main/java/com/flemmli97/flan/commands/CommandClaim.java @@ -0,0 +1,224 @@ +package com.flemmli97.flan.commands; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.claim.EnumPermission; +import com.flemmli97.flan.config.ConfigHandler; +import com.flemmli97.flan.gui.ClaimMenuScreenHandler; +import com.flemmli97.flan.player.EnumEditMode; +import com.flemmli97.flan.player.PlayerClaimData; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.mojang.authlib.GameProfile; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.IntegerArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.builder.ArgumentBuilder; +import com.mojang.brigadier.builder.LiteralArgumentBuilder; +import net.minecraft.command.argument.GameProfileArgumentType; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.CommandSource; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class CommandClaim { + + public static void register(CommandDispatcher dispatcher, boolean dedicated) { + + LiteralArgumentBuilder main = CommandManager.literal("claim"); + dispatcher.register(addToMainCommand(CommandManager.literal("claim"), + CommandManager.literal("menu").executes(context -> { + ServerCommandSource src = context.getSource(); + if (src.getPlayer() == null) + return 0; + ClaimStorage storage = ClaimStorage.get(context.getSource().getWorld()); + Claim claim = storage.getClaimAt(src.getPlayer().getBlockPos()); + if (claim == null || !claim.canInteract(src.getPlayer(), EnumPermission.EDITCLAIM, src.getPlayer().getBlockPos())) + return 0; + ClaimMenuScreenHandler.openClaimMenu(src.getPlayer(), claim); + return Command.SINGLE_SUCCESS; + }), + CommandManager.literal("delete").executes(context -> { + ServerCommandSource src = context.getSource(); + if (src.getPlayer() == null) + return 0; + ClaimStorage storage = ClaimStorage.get(src.getWorld()); + Claim claim = storage.getClaimAt(src.getPlayer().getBlockPos()); + if (claim == null || !claim.canInteract(src.getPlayer(), EnumPermission.EDITCLAIM, src.getPlayer().getBlockPos())) { + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteClaimError), false); + return 0; + } + storage.deleteClaim(claim); + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteClaim), false); + + return Command.SINGLE_SUCCESS; + }), + CommandManager.literal("deleteAll").executes(context -> { + ServerCommandSource src = context.getSource(); + if (src.getPlayer() == null) + return 0; + PlayerClaimData data = PlayerClaimData.get(src.getPlayer()); + if (data.confirmedDeleteAll()) { + for (ServerWorld world : src.getWorld().getServer().getWorlds()) { + ClaimStorage storage = ClaimStorage.get(world); + storage.allClaimsFromPlayer(src.getPlayer().getUuid()).forEach(claim -> storage.deleteClaim(claim)); + } + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteAllClaim), false); + data.setConfirmDeleteAll(false); + } else { + data.setConfirmDeleteAll(true); + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteAllClaimConfirm), false); + } + return Command.SINGLE_SUCCESS; + }), + CommandManager.literal("list").executes(context -> { + ServerCommandSource src = context.getSource(); + if (src.getPlayer() == null) + return 0; + Map> claims = Maps.newHashMap(); + for (ServerWorld world : src.getWorld().getServer().getWorlds()) { + ClaimStorage storage = ClaimStorage.get(world); + claims.put(world, storage.allClaimsFromPlayer(src.getPlayer().getUuid())); + } + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.listClaims), false); + for (Map.Entry> entry : claims.entrySet()) + for (Claim claim : entry.getValue()) + src.getPlayer().sendMessage(Text.of(entry.getKey().getRegistryKey().getValue().toString() + " - " + claim.formattedClaim()), false); + return Command.SINGLE_SUCCESS; + }), + CommandManager.literal("switchMode").executes(context -> { + ServerCommandSource src = context.getSource(); + if (src.getPlayer() == null) + return 0; + PlayerClaimData data = PlayerClaimData.get(src.getPlayer()); + data.setEditMode(data.getEditMode() == EnumEditMode.DEFAULT ? EnumEditMode.SUBCLAIM : EnumEditMode.DEFAULT); + src.getPlayer().sendMessage(Text.of(String.format(ConfigHandler.lang.editMode, data.getEditMode())), false); + return Command.SINGLE_SUCCESS; + }), + CommandManager.literal("adminMode").requires(src -> src.hasPermissionLevel(2)).executes(context -> { + ServerCommandSource src = context.getSource(); + if (src.getPlayer() == null) + return 0; + PlayerClaimData data = PlayerClaimData.get(src.getPlayer()); + data.setAdminIgnoreClaim(!data.isAdminIgnoreClaim()); + src.getPlayer().sendMessage(Text.of(String.format(ConfigHandler.lang.adminMode, data.isAdminIgnoreClaim())), false); + return Command.SINGLE_SUCCESS; + }), + CommandManager.literal("adminRemove").requires(src -> src.hasPermissionLevel(2)).executes(context -> { + ServerCommandSource src = context.getSource(); + ClaimStorage storage = ClaimStorage.get(src.getWorld()); + Claim claim = storage.getClaimAt(new BlockPos(src.getPosition())); + if (claim == null) { + src.sendFeedback(Text.of(ConfigHandler.lang.deleteClaimError), false); + return 0; + } + storage.deleteClaim(claim); + src.sendFeedback(Text.of(ConfigHandler.lang.deleteClaim), true); + return Command.SINGLE_SUCCESS; + }).then(CommandManager.literal("all").then(CommandManager.argument("player", GameProfileArgumentType.gameProfile())).executes(context -> { + ServerCommandSource src = context.getSource(); + Iterator it = GameProfileArgumentType.getProfileArgument(context, "player").iterator(); + List players = Lists.newArrayList(); + while (it.hasNext()) { + GameProfile prof = it.next(); + for (ServerWorld world : src.getWorld().getServer().getWorlds()) { + ClaimStorage storage = ClaimStorage.get(world); + storage.allClaimsFromPlayer(prof.getId()).forEach(claim -> storage.deleteClaim(claim)); + } + players.add(prof.getName()); + } + src.sendFeedback(Text.of(String.format(ConfigHandler.lang.adminDeleteAll, players.toString())), true); + return Command.SINGLE_SUCCESS; + })), + CommandManager.literal("giveClaimBlocks").requires(src -> src.hasPermissionLevel(2)).then(CommandManager.argument("player", GameProfileArgumentType.gameProfile()) + .then(CommandManager.argument("amount", IntegerArgumentType.integer()).executes(context -> { + ServerCommandSource src = context.getSource(); + Iterator it = GameProfileArgumentType.getProfileArgument(context, "player").iterator(); + List players = Lists.newArrayList(); + int amount = IntegerArgumentType.getInteger(context, "amount"); + while (it.hasNext()) { + GameProfile prof = it.next(); + ServerPlayerEntity player = src.getMinecraftServer().getPlayerManager().getPlayer(prof.getId()); + if (player != null) { + PlayerClaimData data = PlayerClaimData.get(player); + data.setAdditionalClaims(data.getAdditionalClaims() + amount); + } else + PlayerClaimData.editForOfflinePlayer(src.getMinecraftServer(), prof.getId(), amount); + players.add(prof.getName()); + } + src.sendFeedback(Text.of(String.format(ConfigHandler.lang.giveClaimBlocks, players.toString(), amount)), true); + return Command.SINGLE_SUCCESS; + }))), + addToMainCommand(CommandManager.literal("group"), + CommandManager.literal("add").then(CommandManager.argument("name", StringArgumentType.word()).executes(context -> { + ServerCommandSource src = context.getSource(); + String group = StringArgumentType.getString(context, "name"); + if (src.getPlayer() == null) + return 0; + ClaimStorage storage = ClaimStorage.get(src.getWorld()); + Claim claim = storage.getClaimAt(src.getPlayer().getBlockPos()); + if (claim == null || !claim.canInteract(src.getPlayer(), EnumPermission.EDITCLAIM, src.getPlayer().getBlockPos())) { + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteClaimError), false); + return 0; + } + claim.editPerms(src.getPlayer(), group, EnumPermission.EDITCLAIM, -1); + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteClaim), false); + return Command.SINGLE_SUCCESS; + })), + CommandManager.literal("remove").then(CommandManager.argument("name", StringArgumentType.word()).suggests((context, build) -> { + List list = Lists.newArrayList(); + ServerCommandSource src = context.getSource(); + String group = StringArgumentType.getString(context, "name"); + if (src.getPlayer() != null) { + ClaimStorage storage = ClaimStorage.get(src.getWorld()); + Claim claim = storage.getClaimAt(src.getPlayer().getBlockPos()); + if (claim != null && claim.canInteract(src.getPlayer(), EnumPermission.EDITCLAIM, src.getPlayer().getBlockPos())) { + list = claim.groups(); + } + } + return CommandSource.suggestMatching(list, build); + }).executes(context -> { + ServerCommandSource src = context.getSource(); + String group = StringArgumentType.getString(context, "name"); + if (src.getPlayer() == null) + return 0; + ClaimStorage storage = ClaimStorage.get(src.getWorld()); + Claim claim = storage.getClaimAt(src.getPlayer().getBlockPos()); + if (claim == null || !claim.canInteract(src.getPlayer(), EnumPermission.EDITCLAIM, src.getPlayer().getBlockPos())) { + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteClaimError), false); + return 0; + } + claim.removePermGroup(src.getPlayer(), group); + src.getPlayer().sendMessage(Text.of(ConfigHandler.lang.deleteClaim), false); + return Command.SINGLE_SUCCESS; + })), + CommandManager.literal("player").then(CommandManager.argument("player", GameProfileArgumentType.gameProfile())).executes(context -> { + ServerCommandSource src = context.getSource(); + GameProfileArgumentType.getProfileArgument(context, "player"); + if (src.getPlayer() == null) + return 0; + + //print + return 0; + }) + ))); + } + + private static LiteralArgumentBuilder addToMainCommand(LiteralArgumentBuilder main, ArgumentBuilder... other) { + if (other != null) + for (ArgumentBuilder o : other) + main.then(o); + return main; + } + +} diff --git a/src/main/java/com/flemmli97/flan/config/Config.java b/src/main/java/com/flemmli97/flan/config/Config.java new file mode 100644 index 0000000..7f3c3c2 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/config/Config.java @@ -0,0 +1,38 @@ +package com.flemmli97.flan.config; + +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.WorldSavePath; + +import java.io.File; + +public class Config { + + private File configDir; + + public int startingBlocks = 500; + public int maxClaimBlocks = 5000; + public int ticksForNextBlock = 1200; + + public String[] blacklistedWorlds; + public boolean worldWhitelist; + + public Item claimingItem = Items.GOLDEN_HOE; + public Item inspectionItem = Items.STICK; + + public int claimDisplayTime = 1000; + + public Config(MinecraftServer server) { + this.configDir = server.getSavePath(WorldSavePath.ROOT).resolve("config/claimConfigs").toFile(); + } + + + public void load() { + + } + + public void save() { + + } +} diff --git a/src/main/java/com/flemmli97/flan/config/ConfigHandler.java b/src/main/java/com/flemmli97/flan/config/ConfigHandler.java new file mode 100644 index 0000000..117ef21 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/config/ConfigHandler.java @@ -0,0 +1,16 @@ +package com.flemmli97.flan.config; + +import net.minecraft.server.MinecraftServer; + +public class ConfigHandler { + + public static Config config; + public static LangConfig lang; + + public static void serverLoad(MinecraftServer server) { + config = new Config(server); + config.load(); + lang = new LangConfig(server); + lang.load(); + } +} diff --git a/src/main/java/com/flemmli97/flan/config/LangConfig.java b/src/main/java/com/flemmli97/flan/config/LangConfig.java new file mode 100644 index 0000000..86a0575 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/config/LangConfig.java @@ -0,0 +1,39 @@ +package com.flemmli97.flan.config; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.WorldSavePath; + +import java.io.File; + +public class LangConfig { + + private File configDir; + + public String inspectBlockOwner = "This is %1$s's claim"; + public String inspectNoClaim = "Nobody owns this block"; + public String cantClaimHere = "Sorry you cant claim here"; + public String listClaims = "Listing all claims:"; + + public String deleteClaim = "Claim deleted"; + public String deleteAllClaimConfirm = "Are you sure you want to delete all claims? Type it again to confirm"; + public String deleteAllClaim = "All claims deleted"; + public String deleteClaimError = "No claim for you to delete here"; + public String adminDeleteAll = "Deleted all claims for following players: %s"; + + public String giveClaimBlocks = "Gave following players %2$d claimblocks: %1$s"; + public String adminMode = "Adminmode set to: "; + public String editMode = "Editing mode set to %s"; + + public String stringScreenReturn = "Click on paper to go back"; + + public String playerGroupAddFail = "Couldn't add that player to the group either cause the player " + + "is already in a group or no player matching the name was found"; + + public LangConfig(MinecraftServer server) { + this.configDir = server.getSavePath(WorldSavePath.ROOT).resolve("config/claimConfigs").toFile(); + } + + public void load() { + + } +} diff --git a/src/main/java/com/flemmli97/flan/event/BlockInteractEvents.java b/src/main/java/com/flemmli97/flan/event/BlockInteractEvents.java new file mode 100644 index 0000000..b862136 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/event/BlockInteractEvents.java @@ -0,0 +1,140 @@ +package com.flemmli97.flan.event; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.claim.EnumPermission; +import com.flemmli97.flan.claim.ObjectToPermissionMap; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.LockableContainerBlockEntity; +import net.minecraft.entity.Entity; +import net.minecraft.entity.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ToolItem; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; + +public class BlockInteractEvents { + + public static ActionResult breakBlocks(PlayerEntity player, World world, Hand hand, BlockPos pos, Direction dir) { + if (world.isClient) + return ActionResult.PASS; + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + Claim claim = storage.getClaimAt(pos); + if (claim != null) { + if (!claim.canInteract(player, EnumPermission.BREAK, pos)) + return ActionResult.SUCCESS; + } + return ActionResult.PASS; + } + + //Right click block + public static ActionResult useBlocks(PlayerEntity player, World world, Hand hand, BlockHitResult hitResult) { + if (world.isClient) + return ActionResult.PASS; + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + Claim claim = storage.getClaimAt(hitResult.getBlockPos()); + if (claim != null) { + boolean emptyHand = !player.getMainHandStack().isEmpty() || !player.getOffHandStack().isEmpty(); + boolean cancelBlockInteract = player.shouldCancelInteraction() && emptyHand; + if (!cancelBlockInteract) { + BlockState state = world.getBlockState(hitResult.getBlockPos()); + BlockEntity blockEntity = world.getBlockEntity(hitResult.getBlockPos()); + if (blockEntity != null) { + if (blockEntity instanceof LockableContainerBlockEntity) + return claim.canInteract(player, EnumPermission.OPENCONTAINER, hitResult.getBlockPos()) ? ActionResult.PASS : ActionResult.FAIL; + } + EnumPermission perm = ObjectToPermissionMap.getFromBlock(state.getBlock()); + if (perm != null) + return claim.canInteract(player, perm, hitResult.getBlockPos()) ? ActionResult.PASS : ActionResult.FAIL; + } + ItemStack stack = player.getStackInHand(hand); + if (stack.getItem() instanceof BlockItem || stack.getItem() instanceof ToolItem) + return claim.canInteract(player, EnumPermission.PLACE, hitResult.getBlockPos()) ? ActionResult.PASS : ActionResult.FAIL; + } + return ActionResult.PASS; + } + + public static boolean blockCollisionEntity(BlockState state, World world, BlockPos pos, Entity entity) { + if (entity.world.isClient) + return false; + if (entity instanceof PlayerEntity) { + EnumPermission perm = ObjectToPermissionMap.getFromBlock(state.getBlock()); + if (perm == null || (perm != EnumPermission.PRESSUREPLATE && perm != EnumPermission.PORTAL)) + return false; + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + Claim claim = storage.getClaimAt(pos); + if (claim != null) + return !claim.canInteract((PlayerEntity) entity, perm, pos); + } else if (entity instanceof ProjectileEntity) { + EnumPermission perm = ObjectToPermissionMap.getFromBlock(state.getBlock()); + if (perm == null || (perm != EnumPermission.PRESSUREPLATE && perm != EnumPermission.BUTTONLEVER)) + return false; + Entity owner = ((ProjectileEntity) entity).getOwner(); + if (owner instanceof PlayerEntity) { + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + Claim claim = storage.getClaimAt(pos); + if (claim != null) + return !claim.canInteract((PlayerEntity) owner, perm, pos); + } + } + return false; + } + + public static boolean entityFall(Entity entity, double heightDifference, boolean onGround, BlockState landedState, BlockPos landedPosition) { + if (entity.world.isClient) + return false; + if (entity instanceof ServerPlayerEntity) { + ClaimStorage storage = ClaimStorage.get((ServerWorld) entity.world); + Claim claim = storage.getClaimAt(landedPosition); + EnumPermission perm = ObjectToPermissionMap.getFromBlock(landedState.getBlock()); + if (perm != null && perm == EnumPermission.TRAMPLE) + return !claim.canInteract((PlayerEntity) entity, perm, landedPosition); + } else if (entity instanceof ProjectileEntity) { + Entity owner = ((ProjectileEntity) entity).getOwner(); + if (owner instanceof PlayerEntity) { + ClaimStorage storage = ClaimStorage.get((ServerWorld) entity.world); + Claim claim = storage.getClaimAt(landedPosition); + EnumPermission perm = ObjectToPermissionMap.getFromBlock(landedState.getBlock()); + if (perm != null && perm == EnumPermission.TRAMPLE) + return !claim.canInteract((PlayerEntity) owner, perm, landedPosition); + } + } + return false; + } + + public static boolean turtleEggHandle(World world, BlockPos pos, Entity entity) { + if (world.isClient) + return false; + ServerWorld serverWorld = (ServerWorld) world; + if (entity instanceof ServerPlayerEntity) { + ClaimStorage storage = ClaimStorage.get(serverWorld); + Claim claim = storage.getClaimAt(pos); + return !claim.canInteract((PlayerEntity) entity, EnumPermission.TRAMPLE, pos); + } else if (entity instanceof ProjectileEntity) { + Entity owner = ((ProjectileEntity) entity).getOwner(); + if (owner instanceof PlayerEntity) { + ClaimStorage storage = ClaimStorage.get(serverWorld); + Claim claim = storage.getClaimAt(pos); + return !claim.canInteract((PlayerEntity) owner, EnumPermission.TRAMPLE, pos); + } + } else if (entity instanceof ItemEntity) { + Entity owner = serverWorld.getEntity(((ItemEntity) entity).getThrower()); + if (owner instanceof PlayerEntity) { + ClaimStorage storage = ClaimStorage.get(serverWorld); + Claim claim = storage.getClaimAt(pos); + return !claim.canInteract((PlayerEntity) owner, EnumPermission.TRAMPLE, pos); + } + } + return false; + } +} diff --git a/src/main/java/com/flemmli97/flan/event/EntityInteractEvents.java b/src/main/java/com/flemmli97/flan/event/EntityInteractEvents.java new file mode 100644 index 0000000..f59e58a --- /dev/null +++ b/src/main/java/com/flemmli97/flan/event/EntityInteractEvents.java @@ -0,0 +1,162 @@ +package com.flemmli97.flan.event; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.claim.EnumPermission; +import com.flemmli97.flan.claim.ObjectToPermissionMap; +import com.flemmli97.flan.mixin.IPersistentProjectileVars; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.boss.WitherEntity; +import net.minecraft.entity.decoration.ArmorStandEntity; +import net.minecraft.entity.decoration.ItemFrameEntity; +import net.minecraft.entity.mob.Monster; +import net.minecraft.entity.passive.VillagerEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.projectile.PersistentProjectileEntity; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.entity.projectile.thrown.EnderPearlEntity; +import net.minecraft.entity.vehicle.BoatEntity; +import net.minecraft.entity.vehicle.ChestMinecartEntity; +import net.minecraft.entity.vehicle.HopperMinecartEntity; +import net.minecraft.entity.vehicle.MinecartEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +public class EntityInteractEvents { + + public static ActionResult attackEntity(PlayerEntity player, World world, Hand hand, Entity entity, EntityHitResult hitResult) { + return attackSimple(player, entity); + } + + public static ActionResult useAtEntity(PlayerEntity player, World world, Hand hand, Entity entity, /* Nullable */ EntityHitResult hitResult) { + if (player.world.isClient) + return ActionResult.PASS; + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + BlockPos pos = entity.getBlockPos(); + Claim claim = storage.getClaimAt(pos); + if (claim != null) { + if (entity instanceof ArmorStandEntity) { + if (!claim.canInteract(player, EnumPermission.ARMORSTAND, pos)) + return ActionResult.FAIL; + } + } + return ActionResult.PASS; + } + + public static ActionResult useEntity(PlayerEntity player, World world, Hand hand, Entity entity) { + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + BlockPos pos = entity.getBlockPos(); + Claim claim = storage.getClaimAt(pos); + if (claim != null) { + //works + if (entity instanceof BoatEntity) + return claim.canInteract(player, EnumPermission.BOAT, pos) ? ActionResult.PASS : ActionResult.FAIL; + if (entity instanceof MinecartEntity) { + if (entity instanceof HopperMinecartEntity || entity instanceof ChestMinecartEntity) + return claim.canInteract(player, EnumPermission.OPENCONTAINER, pos) ? ActionResult.PASS : ActionResult.FAIL; + return claim.canInteract(player, EnumPermission.MINECART, pos) ? ActionResult.PASS : ActionResult.FAIL; + } + if (entity instanceof VillagerEntity) + return claim.canInteract(player, EnumPermission.TRADING, pos) ? ActionResult.PASS : ActionResult.FAIL; + if (entity instanceof ItemFrameEntity) + return claim.canInteract(player, EnumPermission.ITEMFRAMEROTATE, pos) ? ActionResult.PASS : ActionResult.FAIL; + + return claim.canInteract(player, EnumPermission.ANIMALINTERACT, pos) ? ActionResult.PASS : ActionResult.FAIL; + } + return ActionResult.PASS; + } + + public static boolean projectileHit(ProjectileEntity proj, HitResult res) { + if (proj.world.isClient) + return false; + Entity owner = proj.getOwner(); + if (owner instanceof PlayerEntity) { + PlayerEntity player = (PlayerEntity) owner; + if (res.getType() == HitResult.Type.BLOCK) { + BlockHitResult blockRes = (BlockHitResult) res; + BlockPos pos = blockRes.getBlockPos(); + BlockState state = proj.world.getBlockState(pos); + EnumPermission perm = ObjectToPermissionMap.getFromBlock(state.getBlock()); + if (proj instanceof EnderPearlEntity) + perm = EnumPermission.ENDERPEARL; + if (perm == null || (perm != EnumPermission.ENDERPEARL && perm != EnumPermission.TARGETBLOCK && perm != EnumPermission.PROJECTILES)) + return false; + ClaimStorage storage = ClaimStorage.get((ServerWorld) proj.world); + Claim claim = storage.getClaimAt(pos); + if (claim == null) + return false; + boolean flag = !claim.canInteract(player, perm, pos); + if (flag && proj instanceof PersistentProjectileEntity) { + PersistentProjectileEntity pers = (PersistentProjectileEntity) proj; + ((IPersistentProjectileVars) pers).setInBlockState(pers.world.getBlockState(pos)); + Vec3d vec3d = blockRes.getPos().subtract(pers.getX(), pers.getY(), pers.getZ()); + pers.setVelocity(vec3d); + Vec3d vec3d2 = vec3d.normalize().multiply(0.05000000074505806D); + pers.setPos(pers.getX() - vec3d2.x, pers.getY() - vec3d2.y, pers.getZ() - vec3d2.z); + pers.playSound(((IPersistentProjectileVars) pers).getSoundEvent(), 1.0F, 1.2F / (pers.world.random.nextFloat() * 0.2F + 0.9F)); + ((IPersistentProjectileVars) pers).setInGround(true); + pers.shake = 7; + pers.setCritical(false); + pers.setPierceLevel((byte) 0); + pers.setSound(SoundEvents.ENTITY_ARROW_HIT); + pers.setShotFromCrossbow(false); + ((IPersistentProjectileVars) pers).resetPiercingStatus(); + } + return flag; + } else if (res.getType() == HitResult.Type.ENTITY) + return attackSimple(player, ((EntityHitResult) res).getEntity()) != ActionResult.PASS; + } + return false; + } + + public static ActionResult attackSimple(PlayerEntity player, Entity entity) { + if (player.world.isClient) + return ActionResult.PASS; + if (entity instanceof Monster) + return ActionResult.PASS; + ClaimStorage storage = ClaimStorage.get((ServerWorld) player.world); + BlockPos pos = entity.getBlockPos(); + Claim claim = storage.getClaimAt(pos); + if (claim != null) { + if (entity instanceof ArmorStandEntity || entity instanceof MinecartEntity || entity instanceof BoatEntity || entity instanceof ItemFrameEntity) + return claim.canInteract(player, EnumPermission.BREAKNONLIVING, pos) ? ActionResult.PASS : ActionResult.FAIL; + if (entity instanceof PlayerEntity) + return claim.canInteract(player, EnumPermission.HURTPLAYER, pos) ? ActionResult.PASS : ActionResult.FAIL; + return claim.canInteract(player, EnumPermission.HURTANIMAL, pos) ? ActionResult.PASS : ActionResult.FAIL; + } + return ActionResult.PASS; + } + + public static boolean xpAbsorb(PlayerEntity player) { + if (player instanceof ServerPlayerEntity) { + ClaimStorage storage = ClaimStorage.get((ServerWorld) player.world); + BlockPos pos = player.getBlockPos(); + Claim claim = storage.getClaimAt(pos); + if (claim != null) + return !claim.canInteract(player, EnumPermission.XP, pos); + } + return false; + } + + public static boolean witherCanDestroy(WitherEntity wither) { + if (wither.world.isClient) + return true; + ClaimStorage storage = ClaimStorage.get((ServerWorld) wither.world); + for (int x = -1; x <= 1; x++) + for (int z = -1; z <= 1; z++) { + if (storage.getClaimAt(wither.getBlockPos().add(x, 0, z)) != null) + return false; + } + return true; + } +} diff --git a/src/main/java/com/flemmli97/flan/event/ItemInteractEvents.java b/src/main/java/com/flemmli97/flan/event/ItemInteractEvents.java new file mode 100644 index 0000000..6acc8eb --- /dev/null +++ b/src/main/java/com/flemmli97/flan/event/ItemInteractEvents.java @@ -0,0 +1,109 @@ +package com.flemmli97.flan.event; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.claim.EnumPermission; +import com.flemmli97.flan.config.ConfigHandler; +import com.flemmli97.flan.player.EnumEditMode; +import com.flemmli97.flan.player.PlayerClaimData; +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BucketItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.Text; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class ItemInteractEvents { + + public static TypedActionResult useItem(PlayerEntity player, World world, Hand hand) { + if (world.isClient) + return TypedActionResult.pass(player.getStackInHand(hand)); + ItemStack stack = player.getStackInHand(hand); + if (stack.getItem() == ConfigHandler.config.claimingItem) { + HitResult ray = player.rayTrace(64, 0, false); + if (ray != null && ray.getType() == HitResult.Type.BLOCK) { + BlockHitResult blockRay = (BlockHitResult) ray; + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + Claim claim = storage.getClaimAt(blockRay.getBlockPos()); + PlayerClaimData data = PlayerClaimData.get(player); + if (claim != null) { + if (claim.canInteract(player, EnumPermission.EDITCLAIM, blockRay.getBlockPos())) { + if (data.getEditMode() == EnumEditMode.SUBCLAIM) { + Claim subClaim = claim.getSubClaim(blockRay.getBlockPos()); + if (subClaim != null) { + if (subClaim.isCorner(blockRay.getBlockPos())) + data.setEditClaim(subClaim); + } else { + if (data.editingCorner() != null) { + if (data.currentEdit() == null) { + boolean fl = claim.tryCreateSubClaim(data.editingCorner(), blockRay.getBlockPos()); + } else { + //subClaim.resizeClaim(data.currentEdit(), data.editingCorner()); + data.setEditClaim(null); + } + data.setEditingCorner(null); + } else + data.setEditingCorner(blockRay.getBlockPos()); + } + } else { + if (claim.isCorner(blockRay.getBlockPos())) + data.setEditClaim(claim); + } + } else { + data.addDisplayClaim(claim); + player.sendMessage(Text.of(ConfigHandler.lang.cantClaimHere), false); + } + } else { + if (data.editingCorner() != null) { + if (data.currentEdit() == null) + storage.createClaim(data.editingCorner(), blockRay.getBlockPos(), player); + else { + storage.resizeClaim(data.currentEdit(), data.editingCorner()); + data.setEditClaim(null); + } + data.setEditingCorner(null); + } else + data.setEditingCorner(blockRay.getBlockPos()); + } + } + return TypedActionResult.success(stack); + } + if (stack.getItem() == ConfigHandler.config.inspectionItem) { + HitResult ray = player.rayTrace(32, 0, false); + if (ray != null && ray.getType() == HitResult.Type.BLOCK) { + BlockHitResult blockRay = (BlockHitResult) ray; + Claim claim = ClaimStorage.get((ServerWorld) world).getClaimAt(new BlockPos(ray.getPos())); + if (claim != null) { + String owner = ""; + GameProfile prof = world.getServer().getUserCache().getByUuid(claim.getOwner()); + if (prof != null && prof.getName() != null) + owner = prof.getName(); + Text text = Text.of(String.format(ConfigHandler.lang.inspectBlockOwner, + owner, + blockRay.getBlockPos().getX(), blockRay.getBlockPos().getY(), blockRay.getBlockPos().getZ())); + player.sendMessage(text, false); + PlayerClaimData.get(player).addDisplayClaim(claim); + } else + player.sendMessage(Text.of(ConfigHandler.lang.inspectNoClaim), false); + } + return TypedActionResult.success(stack); + } + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + BlockPos pos = player.getBlockPos(); + Claim claim = storage.getClaimAt(pos); + if (claim == null) + return TypedActionResult.pass(stack); + if (stack.getItem() == Items.ENDER_PEARL) + return claim.canInteract(player, EnumPermission.ENDERPEARL, pos) ? TypedActionResult.pass(stack) : TypedActionResult.fail(stack); + if (stack.getItem() instanceof BucketItem) + return claim.canInteract(player, EnumPermission.BUCKET, pos) ? TypedActionResult.pass(stack) : TypedActionResult.fail(stack); + return TypedActionResult.pass(stack); + } +} diff --git a/src/main/java/com/flemmli97/flan/event/WorldEvents.java b/src/main/java/com/flemmli97/flan/event/WorldEvents.java new file mode 100644 index 0000000..25b1ab5 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/event/WorldEvents.java @@ -0,0 +1,25 @@ +package com.flemmli97.flan.event; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.claim.EnumPermission; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.List; + +public class WorldEvents { + + public static void modifyExplosion(List list, World world) { + if (world.isClient) + return; + ClaimStorage storage = ClaimStorage.get((ServerWorld) world); + list.removeIf(pos -> { + Claim claim = storage.getClaimAt(pos); + if (claim != null) + return !claim.canInteract(null, EnumPermission.EXPLOSIONS, pos); + return false; + }); + } +} diff --git a/src/main/java/com/flemmli97/flan/gui/ClaimMenuScreenHandler.java b/src/main/java/com/flemmli97/flan/gui/ClaimMenuScreenHandler.java new file mode 100644 index 0000000..4707733 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/ClaimMenuScreenHandler.java @@ -0,0 +1,107 @@ +package com.flemmli97.flan.gui; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.config.ConfigHandler; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +public class ClaimMenuScreenHandler extends ServerOnlyScreenHandler { + + private Claim claim; + + private ClaimMenuScreenHandler(int syncId, PlayerInventory playerInventory, Claim claim) { + super(syncId, playerInventory, 1); + this.claim = claim; + } + + public static void openClaimMenu(PlayerEntity player, Claim claim) { + NamedScreenHandlerFactory fac = new NamedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new ClaimMenuScreenHandler(syncId, inv, claim); + } + + @Override + public Text getDisplayName() { + return Text.of("Claim-Menu"); + } + }; + player.openHandledScreen(fac); + } + + @Override + protected void fillInventoryWith(PlayerEntity player, Inventory inv, Object... additionalData) { + for (int i = 0; i < 9; i++) { + switch (i) { + case 0: + ItemStack close = new ItemStack(Items.TNT); + close.setCustomName(new LiteralText("Close").setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + inv.setStack(i, close); + break; + case 2: + ItemStack perm = new ItemStack(Items.BEACON); + perm.setCustomName(new LiteralText("Edit Global Permissions").setStyle(Style.EMPTY.withFormatting(Formatting.GOLD))); + inv.setStack(i, perm); + break; + case 3: + ItemStack group = new ItemStack(Items.WRITABLE_BOOK); + group.setCustomName(new LiteralText("Edit Permissiongroups").setStyle(Style.EMPTY.withFormatting(Formatting.GOLD))); + inv.setStack(i, group); + break; + case 8: + ItemStack delete = new ItemStack(Items.BARRIER); + delete.setCustomName(new LiteralText("Delete Claim").setStyle(Style.EMPTY.withFormatting(Formatting.RED))); + inv.setStack(i, delete); + break; + default: + inv.setStack(i, ServerScreenHelper.emptyFiller()); + } + } + } + + @Override + protected boolean isRightSlot(int slot) { + return slot == 0 || slot == 2 || slot == 3 || slot == 8; + } + + @Override + protected boolean handleSlotClicked(ServerPlayerEntity player, int index, Slot slot, int clickType) { + switch (index) { + case 0: + player.closeHandledScreen(); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + break; + case 2: + player.closeHandledScreen(); + player.getServer().execute(() -> PermissionScreenHandler.openClaimMenu(player, this.claim, null)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + break; + case 3: + player.closeHandledScreen(); + player.getServer().execute(() -> GroupScreenHandler.openGroupMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + break; + case 8: + ClaimStorage storage = ClaimStorage.get(player.getServerWorld()); + storage.deleteClaim(this.claim); + player.closeHandledScreen(); + player.sendMessage(Text.of(ConfigHandler.lang.deleteClaim), false); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.BLOCK_ANVIL_PLACE, 1, 1f); + break; + } + return true; + } +} diff --git a/src/main/java/com/flemmli97/flan/gui/GroupPlayerScreenHandler.java b/src/main/java/com/flemmli97/flan/gui/GroupPlayerScreenHandler.java new file mode 100644 index 0000000..024fb56 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/GroupPlayerScreenHandler.java @@ -0,0 +1,141 @@ +package com.flemmli97.flan.gui; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.config.ConfigHandler; +import com.mojang.authlib.GameProfile; +import net.minecraft.block.entity.SkullBlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtHelper; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.List; + +public class GroupPlayerScreenHandler extends ServerOnlyScreenHandler { + + private Claim claim; + private String group; + private boolean removeMode; + + private GroupPlayerScreenHandler(int syncId, PlayerInventory playerInventory, Claim claim, String group) { + super(syncId, playerInventory, 6, claim, group); + this.claim = claim; + this.group = group; + } + + public static void openPlayerGroupMenu(PlayerEntity player, Claim claim, String group) { + NamedScreenHandlerFactory fac = new NamedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new GroupPlayerScreenHandler(syncId, inv, claim, group); + } + + @Override + public Text getDisplayName() { + return Text.of(group + "-Players"); + } + }; + player.openHandledScreen(fac); + } + + @Override + protected void fillInventoryWith(PlayerEntity player, Inventory inv, Object... additionalData) { + if (additionalData == null || additionalData.length < 2) + return; + Claim claim = (Claim) additionalData[0]; + List players = claim.playersFromGroup(player.getServer(), (String) additionalData[1]); + for (int i = 0; i < 54; i++) { + if (i == 0) { + ItemStack close = new ItemStack(Items.TNT); + close.setCustomName(new LiteralText("Back").setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + inv.setStack(i, close); + } else if (i == 3) { + ItemStack stack = new ItemStack(Items.ANVIL); + stack.setCustomName(new LiteralText("Add").setStyle(Style.EMPTY.withFormatting(Formatting.DARK_GREEN))); + inv.setStack(i, stack); + } else if (i == 4) { + ItemStack stack = new ItemStack(Items.REDSTONE_BLOCK); + stack.setCustomName(new LiteralText("Remove Mode: " + this.removeMode).setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + inv.setStack(i, stack); + } else if (i < 9 || i > 44 || i % 9 == 0 || i % 9 == 8) + inv.setStack(i, ServerScreenHelper.emptyFiller()); + else { + int row = i / 9 - 1; + int id = (i % 9) + row * 7 - 1; + if (id < players.size()) { + ItemStack group = new ItemStack(Items.PLAYER_HEAD); + GameProfile gameProfile = new GameProfile(null, players.get(id)); + gameProfile = SkullBlockEntity.loadProperties(gameProfile); + group.getOrCreateTag().put("SkullOwner", NbtHelper.fromGameProfile(new CompoundTag(), gameProfile)); + inv.setStack(i, group); + } + } + } + } + + @Override + protected boolean isRightSlot(int slot) { + return slot == 0 || slot == 3 || slot == 4 || (slot < 45 && slot > 8 && slot % 9 != 0 && slot % 9 != 8); + } + + @Override + protected boolean handleSlotClicked(ServerPlayerEntity player, int index, Slot slot, int clickType) { + if (index == 0) { + player.closeHandledScreen(); + player.getServer().execute(() -> GroupScreenHandler.openGroupMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + if (index == 3) { + player.closeHandledScreen(); + player.getServer().execute(() -> StringResultScreenHandler.createNewStringResult(player, this.claim, (s) -> { + GameProfile prof = player.getServer().getUserCache().findByName(s); + boolean fl = prof == null || this.claim.setPlayerGroup(prof.getId(), this.group, false); + player.closeHandledScreen(); + player.getServer().execute(() -> GroupPlayerScreenHandler.openPlayerGroupMenu(player, claim, group)); + if (fl) + ServerScreenHelper.playSongToPlayer(player, SoundEvents.BLOCK_ANVIL_USE, 1, 1f); + else { + player.sendMessage(Text.of(ConfigHandler.lang.playerGroupAddFail), false); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.ENTITY_VILLAGER_NO, 1, 1f); + } + }, () -> { + player.closeHandledScreen(); + player.getServer().execute(() -> GroupPlayerScreenHandler.openPlayerGroupMenu(player, claim, group)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.ENTITY_VILLAGER_NO, 1, 1f); + })); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + if (index == 4) { + this.removeMode = !this.removeMode; + ItemStack stack = new ItemStack(Items.REDSTONE_BLOCK); + stack.setCustomName(new LiteralText("Remove Mode: " + this.removeMode).setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + slot.setStack(stack); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + ItemStack stack = slot.getStack(); + if (!stack.isEmpty()) { + CompoundTag tag = stack.getOrCreateSubTag("SkullOwner"); + if (this.removeMode && tag.contains("Id")) { + this.claim.setPlayerGroup(tag.getUuid("Id"), null, false); + slot.setStack(ItemStack.EMPTY); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.ENTITY_BAT_DEATH, 1, 1f); + } + } + return false; + } +} diff --git a/src/main/java/com/flemmli97/flan/gui/GroupScreenHandler.java b/src/main/java/com/flemmli97/flan/gui/GroupScreenHandler.java new file mode 100644 index 0000000..01440e3 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/GroupScreenHandler.java @@ -0,0 +1,138 @@ +package com.flemmli97.flan.gui; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.EnumPermission; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +import java.util.List; + +public class GroupScreenHandler extends ServerOnlyScreenHandler { + + private Claim claim; + + private boolean removeMode; + + private GroupScreenHandler(int syncId, PlayerInventory playerInventory, Claim claim) { + super(syncId, playerInventory, 6, claim); + this.claim = claim; + } + + public static void openGroupMenu(PlayerEntity player, Claim claim) { + NamedScreenHandlerFactory fac = new NamedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new GroupScreenHandler(syncId, inv, claim); + } + + @Override + public Text getDisplayName() { + return Text.of("Claim-Groups"); + } + }; + player.openHandledScreen(fac); + } + + @Override + protected void fillInventoryWith(PlayerEntity player, Inventory inv, Object... additionalData) { + if (additionalData == null) + return; + Claim claim = (Claim) additionalData[0]; + for (int i = 0; i < 54; i++) { + if (i == 0) { + ItemStack close = new ItemStack(Items.TNT); + close.setCustomName(new LiteralText("Back").setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + inv.setStack(i, close); + } else if (i == 3) { + ItemStack stack = new ItemStack(Items.ANVIL); + stack.setCustomName(new LiteralText("Add").setStyle(Style.EMPTY.withFormatting(Formatting.DARK_GREEN))); + inv.setStack(i, stack); + } else if (i == 4) { + ItemStack stack = new ItemStack(Items.REDSTONE_BLOCK); + stack.setCustomName(new LiteralText("Remove Mode: " + this.removeMode).setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + inv.setStack(i, stack); + } else if (i < 9 || i > 44 || i % 9 == 0 || i % 9 == 8) + inv.setStack(i, ServerScreenHelper.emptyFiller()); + else { + List groups = claim.groups(); + int row = i / 9 - 1; + int id = (i % 9) + row * 7 - 1; + if (id < groups.size()) { + ItemStack group = new ItemStack(Items.PAPER); + group.setCustomName(new LiteralText(groups.get(id)).setStyle(Style.EMPTY.withFormatting(Formatting.DARK_BLUE))); + inv.setStack(i, group); + } + } + } + } + + @Override + protected boolean isRightSlot(int slot) { + return slot == 0 || slot == 3 || slot == 4 || (slot < 45 && slot > 8 && slot % 9 != 0 && slot % 9 != 8); + } + + @Override + protected boolean handleSlotClicked(ServerPlayerEntity player, int index, Slot slot, int clickType) { + if (index == 0) { + player.closeHandledScreen(); + player.getServer().execute(() -> ClaimMenuScreenHandler.openClaimMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + if (index == 3) { + player.closeHandledScreen(); + player.getServer().execute(() -> StringResultScreenHandler.createNewStringResult(player, this.claim, (s) -> { + this.claim.editPerms(player, s, EnumPermission.EDITCLAIM, -1); + player.closeHandledScreen(); + player.getServer().execute(() -> GroupScreenHandler.openGroupMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.BLOCK_ANVIL_USE, 1, 1f); + }, () -> { + player.closeHandledScreen(); + player.getServer().execute(() -> GroupScreenHandler.openGroupMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.ENTITY_VILLAGER_NO, 1, 1f); + })); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + if (index == 4) { + this.removeMode = !this.removeMode; + ItemStack stack = new ItemStack(Items.REDSTONE_BLOCK); + stack.setCustomName(new LiteralText("Remove Mode: " + this.removeMode).setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + slot.setStack(stack); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + return true; + } + ItemStack stack = slot.getStack(); + if (!stack.isEmpty()) { + String name = stack.getName().asString(); + if (this.removeMode) { + this.claim.removePermGroup(player, name); + slot.setStack(ItemStack.EMPTY); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.ENTITY_BAT_DEATH, 1, 1f); + } else { + if (clickType == 1) { + player.closeHandledScreen(); + player.getServer().execute(() -> PermissionScreenHandler.openClaimMenu(player, this.claim, name)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } else { + player.closeHandledScreen(); + player.getServer().execute(() -> GroupPlayerScreenHandler.openPlayerGroupMenu(player, this.claim, name)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } + } + } + return false; + } +} diff --git a/src/main/java/com/flemmli97/flan/gui/PermissionScreenHandler.java b/src/main/java/com/flemmli97/flan/gui/PermissionScreenHandler.java new file mode 100644 index 0000000..849e1f4 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/PermissionScreenHandler.java @@ -0,0 +1,137 @@ +package com.flemmli97.flan.gui; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.EnumPermission; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundEvents; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +public class PermissionScreenHandler extends ServerOnlyScreenHandler { + + private Claim claim; + private String group; + private int page; + + private PermissionScreenHandler(int syncId, PlayerInventory playerInventory, Claim claim, String group, int page) { + super(syncId, playerInventory, 6, claim, group, page); + this.claim = claim; + this.group = group; + this.page = page; + } + + public static void openClaimMenu(PlayerEntity player, Claim claim, String group) { + NamedScreenHandlerFactory fac = new NamedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new PermissionScreenHandler(syncId, inv, claim, group, 0); + } + + @Override + public Text getDisplayName() { + return Text.of(group == null ? "Global-Permissions" : String.format("%s-Permissions", group)); + } + }; + player.openHandledScreen(fac); + } + + private static void openClaimMenu(PlayerEntity player, Claim claim, String group, int page) { + NamedScreenHandlerFactory fac = new NamedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new PermissionScreenHandler(syncId, inv, claim, group, page); + } + + @Override + public Text getDisplayName() { + return Text.of(group == null ? "Global-Permissions" : String.format("%s-Permissions", group)); + } + }; + player.openHandledScreen(fac); + } + + @Override + protected void fillInventoryWith(PlayerEntity player, Inventory inv, Object... additionalData) { + if (additionalData == null) + return; + for (int i = 0; i < 54; i++) { + int page = (int) additionalData[2]; + if (i == 0) { + ItemStack close = new ItemStack(Items.TNT); + close.setCustomName(new LiteralText("Back").setStyle(Style.EMPTY.withFormatting(Formatting.DARK_RED))); + inv.setStack(i, close); + } else if (page == 1 && i == 47) { + ItemStack close = new ItemStack(Items.ARROW); + close.setCustomName(new LiteralText("Prev").setStyle(Style.EMPTY.withFormatting(Formatting.WHITE))); + inv.setStack(i, close); + } else if (page == 0 && i == 51) { + ItemStack close = new ItemStack(Items.ARROW); + close.setCustomName(new LiteralText("Next").setStyle(Style.EMPTY.withFormatting(Formatting.WHITE))); + inv.setStack(i, close); + } else if (i < 9 || i > 44 || i % 9 == 0 || i % 9 == 8) + inv.setStack(i, ServerScreenHelper.emptyFiller()); + else { + int row = i / 9 - 1; + int id = (i % 9) + row * 7 - 1 + page * 54; + if (id < EnumPermission.values().length) + inv.setStack(i, ServerScreenHelper.fromPermission((Claim) additionalData[0], EnumPermission.values()[id], additionalData.length == 1 ? null : String.valueOf(additionalData[1]))); + } + } + } + + @Override + protected boolean handleSlotClicked(ServerPlayerEntity player, int index, Slot slot, int clickType) { + if (index == 0) { + if (this.group == null) { + player.closeHandledScreen(); + player.getServer().execute(() -> ClaimMenuScreenHandler.openClaimMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } else { + player.closeHandledScreen(); + player.getServer().execute(() -> GroupScreenHandler.openGroupMenu(player, this.claim)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } + return true; + } + if (index == 47) { + player.closeHandledScreen(); + player.getServer().execute(() -> PermissionScreenHandler.openClaimMenu(player, this.claim, this.group, 0)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } + if (index == 51) { + player.closeHandledScreen(); + player.getServer().execute(() -> PermissionScreenHandler.openClaimMenu(player, this.claim, this.group, 1)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.UI_BUTTON_CLICK, 1, 1f); + } + ItemStack stack = slot.getStack(); + String name = stack.getName().asString(); + EnumPermission perm; + try { + perm = EnumPermission.valueOf(name); + } catch (IllegalArgumentException e) { + return false; + } + if (this.group == null) + this.claim.editGlobalPerms(perm); + else + this.claim.editPerms(player, this.group, perm, this.claim.groupHasPerm(this.group, perm) + 1); + slot.setStack(ServerScreenHelper.fromPermission(this.claim, perm, this.group)); + ServerScreenHelper.playSongToPlayer(player, SoundEvents.BLOCK_NOTE_BLOCK_PLING, 1, 1.2f); + return true; + } + + @Override + protected boolean isRightSlot(int slot) { + return slot == 0 || (this.page == 1 && slot == 47) || (this.page == 0 && slot == 51) || (slot < 45 && slot > 8 && slot % 9 != 0 && slot % 9 != 8); + } +} diff --git a/src/main/java/com/flemmli97/flan/gui/ServerOnlyScreenHandler.java b/src/main/java/com/flemmli97/flan/gui/ServerOnlyScreenHandler.java new file mode 100644 index 0000000..797a4fe --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/ServerOnlyScreenHandler.java @@ -0,0 +1,122 @@ +package com.flemmli97.flan.gui; + +import com.google.common.collect.Lists; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SimpleInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerListener; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.server.network.ServerPlayerEntity; + +import java.util.Iterator; +import java.util.List; + +public abstract class ServerOnlyScreenHandler extends ScreenHandler { + + private final Inventory inventory; + private final List listeners = Lists.newArrayList(); + + protected ServerOnlyScreenHandler(int syncId, PlayerInventory playerInventory, int rows, Object... additionalData) { + super(fromRows(rows), syncId); + int i = (rows - 4) * 18; + this.inventory = new SimpleInventory(rows * 9); + this.fillInventoryWith(playerInventory.player, this.inventory, additionalData); + int n; + int m; + for (n = 0; n < rows; ++n) { + for (m = 0; m < 9; ++m) { + this.addSlot(new Slot(inventory, m + n * 9, 8 + m * 18, 18 + n * 18)); + } + } + + for (n = 0; n < 3; ++n) { + for (m = 0; m < 9; ++m) { + this.addSlot(new Slot(playerInventory, m + n * 9 + 9, 8 + m * 18, 103 + n * 18 + i)); + } + } + + for (n = 0; n < 9; ++n) { + this.addSlot(new Slot(playerInventory, n, 8 + n * 18, 161 + i)); + } + } + + private static ScreenHandlerType fromRows(int rows) { + switch (rows) { + case 2: + return ScreenHandlerType.GENERIC_9X2; + case 3: + return ScreenHandlerType.GENERIC_9X3; + case 4: + return ScreenHandlerType.GENERIC_9X4; + case 5: + return ScreenHandlerType.GENERIC_9X5; + case 6: + return ScreenHandlerType.GENERIC_9X6; + } + return ScreenHandlerType.GENERIC_9X1; + } + + protected abstract void fillInventoryWith(PlayerEntity player, Inventory inv, Object... additionalData); + + @Override + public boolean canUse(PlayerEntity player) { + return true; + } + + @Override + public ItemStack onSlotClick(int i, int j, SlotActionType actionType, PlayerEntity playerEntity) { + if (i < 0) + return ItemStack.EMPTY; + Slot slot = this.slots.get(i); + if (this.isRightSlot(i)) + this.handleSlotClicked((ServerPlayerEntity) playerEntity, i, slot, j); + this.sendContentUpdates(); + return ItemStack.EMPTY; + } + + @Override + public ItemStack transferSlot(PlayerEntity player, int index) { + if (!(player instanceof ServerPlayerEntity)) + return ItemStack.EMPTY; + Slot slot = this.slots.get(index); + if (this.isRightSlot(index)) + this.handleSlotClicked((ServerPlayerEntity) player, index, slot, 0); + this.sendContentUpdates(); + return ItemStack.EMPTY; + } + + @Override + public void addListener(ScreenHandlerListener listener) { + if (!this.listeners.contains(listener)) { + this.listeners.add(listener); + listener.onHandlerRegistered(this, this.getStacks()); + this.sendContentUpdates(); + } + } + + @Override + public void sendContentUpdates() { + int j; + for (j = 0; j < this.slots.size(); ++j) { + ItemStack itemStack = this.slots.get(j).getStack(); + Iterator var5 = this.listeners.iterator(); + + while (var5.hasNext()) { + ScreenHandlerListener screenHandlerListener = (ScreenHandlerListener) var5.next(); + screenHandlerListener.onSlotUpdate(this, j, itemStack.copy()); + } + } + } + + protected abstract boolean isRightSlot(int slot); + + /** + * @param clickType 0 for left click, 1 for right click + */ + protected abstract boolean handleSlotClicked(ServerPlayerEntity player, int index, Slot slot, int clickType); +} diff --git a/src/main/java/com/flemmli97/flan/gui/ServerScreenHelper.java b/src/main/java/com/flemmli97/flan/gui/ServerScreenHelper.java new file mode 100644 index 0000000..28d1426 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/ServerScreenHelper.java @@ -0,0 +1,57 @@ +package com.flemmli97.flan.gui; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.EnumPermission; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.StringTag; +import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvent; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; + +public class ServerScreenHelper { + + public static ItemStack emptyFiller() { + ItemStack stack = new ItemStack(Items.GRAY_STAINED_GLASS_PANE); + stack.setCustomName(Text.of("")); + return stack; + } + + public static ItemStack fromPermission(Claim claim, EnumPermission perm, String group) { + ItemStack stack = new ItemStack(perm.getItem()); + stack.setCustomName(new LiteralText(perm.toString()).setStyle(Style.EMPTY.withFormatting(Formatting.GOLD))); + ListTag lore = new ListTag(); + String permFlag; + if (group == null) + permFlag = "" + claim.permEnabled(perm); + else { + switch (claim.groupHasPerm(group, perm)) { + case -1: + permFlag = "default"; + break; + case 1: + permFlag = "true"; + break; + default: + permFlag = "false"; + break; + } + } + Text text = new LiteralText("Enabled: " + permFlag).setStyle(Style.EMPTY.withFormatting(permFlag.equals("true") ? Formatting.GREEN : Formatting.RED)); + lore.add(StringTag.of(Text.Serializer.toJson(text))); + stack.getOrCreateSubTag("display").put("Lore", lore); + return stack; + } + + public static void playSongToPlayer(ServerPlayerEntity player, SoundEvent event, float vol, float pitch) { + player.networkHandler.sendPacket( + new PlaySoundS2CPacket(event, SoundCategory.PLAYERS, player.getPos().x, player.getPos().y, player.getPos().z, vol, pitch)); + + } +} diff --git a/src/main/java/com/flemmli97/flan/gui/StringResultScreenHandler.java b/src/main/java/com/flemmli97/flan/gui/StringResultScreenHandler.java new file mode 100644 index 0000000..baa578f --- /dev/null +++ b/src/main/java/com/flemmli97/flan/gui/StringResultScreenHandler.java @@ -0,0 +1,145 @@ +package com.flemmli97.flan.gui; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.config.ConfigHandler; +import com.google.common.collect.Lists; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.AnvilScreenHandler; +import net.minecraft.screen.NamedScreenHandlerFactory; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerListener; +import net.minecraft.screen.slot.Slot; +import net.minecraft.screen.slot.SlotActionType; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import org.apache.commons.lang3.StringUtils; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +public class StringResultScreenHandler extends AnvilScreenHandler { + + private final List listeners = Lists.newArrayList(); + + private final Consumer cons; + private final Runnable ret; + + private boolean init; + private String name; + + private StringResultScreenHandler(int syncId, PlayerInventory playerInventory, Consumer cons, Runnable ret) { + super(syncId, playerInventory); + ItemStack stack = new ItemStack(Items.PAPER); + stack.setCustomName(Text.of("")); + this.input.setStack(0, stack); + ItemStack out = new ItemStack(Items.BOOK); + out.setCustomName(Text.of(ConfigHandler.lang.stringScreenReturn)); + this.output.setStack(0, out); + this.cons = cons; + this.ret = ret; + + } + + public static void createNewStringResult(PlayerEntity player, Claim claim, Consumer cons, Runnable ret) { + NamedScreenHandlerFactory fac = new NamedScreenHandlerFactory() { + @Override + public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) { + return new StringResultScreenHandler(syncId, inv, cons, ret); + } + + @Override + public Text getDisplayName() { + return Text.of(""); + } + }; + player.openHandledScreen(fac); + } + + @Override + public boolean canUse(PlayerEntity player) { + return true; + } + + @Override + protected boolean canTakeOutput(PlayerEntity player, boolean present) { + return true; + } + + @Override + public ItemStack onSlotClick(int i, int j, SlotActionType actionType, PlayerEntity playerEntity) { + if (i < 0) + return ItemStack.EMPTY; + if (i == 0) + this.ret.run(); + else if (i == 2) { + Slot slot = this.slots.get(i); + String s = slot.getStack().hasCustomName() ? slot.getStack().getName().asString() : ""; + if (!s.isEmpty() && !s.equals(ConfigHandler.lang.stringScreenReturn)) + this.cons.accept(s); + } + this.sendContentUpdates(); + return ItemStack.EMPTY; + } + + @Override + public ItemStack transferSlot(PlayerEntity player, int index) { + if (index == 0) + this.ret.run(); + else if (index == 2) { + Slot slot = this.slots.get(index); + String s = slot.getStack().hasCustomName() ? slot.getStack().getName().asString() : ""; + if (!s.isEmpty() && !s.equals(ConfigHandler.lang.stringScreenReturn)) + this.cons.accept(s); + } + this.sendContentUpdates(); + return ItemStack.EMPTY; + } + + @Override + public void addListener(ScreenHandlerListener listener) { + if (!this.listeners.contains(listener)) { + this.listeners.add(listener); + listener.onHandlerRegistered(this, this.getStacks()); + this.sendContentUpdates(); + } + } + + @Override + public void sendContentUpdates() { + int j; + for (j = 0; j < this.slots.size(); ++j) { + ItemStack itemStack = this.slots.get(j).getStack(); + Iterator var5 = this.listeners.iterator(); + + while (var5.hasNext()) { + ScreenHandlerListener screenHandlerListener = (ScreenHandlerListener) var5.next(); + screenHandlerListener.onSlotUpdate(this, j, itemStack.copy()); + } + } + } + + @Override + public void updateResult() { + if (!init) + this.init = true; + else { + ItemStack out = this.slots.get(2).getStack(); + if (StringUtils.isBlank(this.name)) + out.removeCustomName(); + else if (!this.name.equals(out.getName().getString())) { + out.setCustomName(new LiteralText(this.name)); + } + } + this.sendContentUpdates(); + } + + @Override + public void setNewItemName(String string) { + this.name = string; + this.updateResult(); + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/AbstractBlockStateMixin.java b/src/main/java/com/flemmli97/flan/mixin/AbstractBlockStateMixin.java new file mode 100644 index 0000000..7c8d0f5 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/AbstractBlockStateMixin.java @@ -0,0 +1,27 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.BlockInteractEvents; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(AbstractBlock.AbstractBlockState.class) +public abstract class AbstractBlockStateMixin { + + @Inject(method = "onEntityCollision", at = @At(value = "HEAD"), cancellable = true) + public void collision(World world, BlockPos pos, Entity entity, CallbackInfo info) { + if (BlockInteractEvents.blockCollisionEntity(this.asBlockState(), world, pos, entity)) { + info.cancel(); + } + } + + @Shadow + protected abstract BlockState asBlockState(); +} diff --git a/src/main/java/com/flemmli97/flan/mixin/EnderPearlEntityMixin.java b/src/main/java/com/flemmli97/flan/mixin/EnderPearlEntityMixin.java new file mode 100644 index 0000000..28e2421 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/EnderPearlEntityMixin.java @@ -0,0 +1,20 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.EntityInteractEvents; +import net.minecraft.entity.projectile.thrown.EnderPearlEntity; +import net.minecraft.util.hit.HitResult; +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(EnderPearlEntity.class) +public abstract class EnderPearlEntityMixin { + + @Inject(method = "onCollision", at = @At(value = "HEAD"), cancellable = true) + public void collision(HitResult hitResult, CallbackInfo info) { + if (EntityInteractEvents.projectileHit((EnderPearlEntity) (Object) this, hitResult)) { + info.cancel(); + } + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/EntityMixin.java b/src/main/java/com/flemmli97/flan/mixin/EntityMixin.java new file mode 100644 index 0000000..ce700e3 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/EntityMixin.java @@ -0,0 +1,21 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.BlockInteractEvents; +import net.minecraft.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +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(Entity.class) +public abstract class EntityMixin { + + @Inject(method = "fall", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/Block;onLandedUpon(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/entity/Entity;F)V"), cancellable = true) + public void fallOnBlock(double heightDifference, boolean onGround, BlockState landedState, BlockPos landedPosition, CallbackInfo info) { + if (BlockInteractEvents.entityFall((Entity) (Object) this, heightDifference, onGround, landedState, landedPosition)) + info.cancel(); + } + +} diff --git a/src/main/java/com/flemmli97/flan/mixin/ExplosionMixin.java b/src/main/java/com/flemmli97/flan/mixin/ExplosionMixin.java new file mode 100644 index 0000000..3a0f6eb --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/ExplosionMixin.java @@ -0,0 +1,27 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.WorldEvents; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.explosion.Explosion; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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.List; + +@Mixin(Explosion.class) +public class ExplosionMixin { + + @Shadow + private List affectedBlocks; + @Shadow + private World world; + + @Inject(method = "collectBlocksAndDamageEntities", at = @At(value = "RETURN")) + public void collision(CallbackInfo info) { + WorldEvents.modifyExplosion(this.affectedBlocks, this.world); + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/IPersistentProjectileVars.java b/src/main/java/com/flemmli97/flan/mixin/IPersistentProjectileVars.java new file mode 100644 index 0000000..3280f33 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/IPersistentProjectileVars.java @@ -0,0 +1,24 @@ +package com.flemmli97.flan.mixin; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.projectile.PersistentProjectileEntity; +import net.minecraft.sound.SoundEvent; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(PersistentProjectileEntity.class) +public interface IPersistentProjectileVars { + + @Accessor("inBlockState") + void setInBlockState(BlockState state); + + @Accessor("inGround") + void setInGround(boolean flag); + + @Invoker("getSound") + SoundEvent getSoundEvent(); + + @Invoker("clearPiercingStatus") + void resetPiercingStatus(); +} diff --git a/src/main/java/com/flemmli97/flan/mixin/PlayerClaimMixin.java b/src/main/java/com/flemmli97/flan/mixin/PlayerClaimMixin.java new file mode 100644 index 0000000..74f1650 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/PlayerClaimMixin.java @@ -0,0 +1,48 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.IClaimData; +import com.flemmli97.flan.player.PlayerClaimData; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +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(ServerPlayerEntity.class) +public abstract class PlayerClaimMixin implements IClaimData { + @Unique + private PlayerClaimData claimData; + + @Shadow + private MinecraftServer server; + + @Inject(method = "*", at = @At("RETURN")) + private void initData(CallbackInfo info) { + this.claimData = new PlayerClaimData((ServerPlayerEntity) (Object) this); + } + + @Inject(method = "readCustomDataFromTag", at = @At("RETURN")) + private void readData(CompoundTag tag, CallbackInfo info) { + this.claimData.read(this.server); + } + + @Inject(method = "readCustomDataFromTag", at = @At("RETURN")) + private void writeData(CompoundTag tag, CallbackInfo info) { + this.claimData.save(this.server); + } + + @Inject(method = "tick", at = @At("RETURN")) + private void tickData(CallbackInfo info) { + this.claimData.tick(); + } + + @Override + public PlayerClaimData getClaimData() { + return this.claimData; + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/ProjectileMixin.java b/src/main/java/com/flemmli97/flan/mixin/ProjectileMixin.java new file mode 100644 index 0000000..7080c51 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/ProjectileMixin.java @@ -0,0 +1,20 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.EntityInteractEvents; +import net.minecraft.entity.projectile.ProjectileEntity; +import net.minecraft.util.hit.HitResult; +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(ProjectileEntity.class) +public abstract class ProjectileMixin { + + @Inject(method = "onCollision", at = @At(value = "HEAD"), cancellable = true) + public void collision(HitResult hitResult, CallbackInfo info) { + if (EntityInteractEvents.projectileHit((ProjectileEntity) (Object) this, hitResult)) { + info.cancel(); + } + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/ServerPlayNetworkHandlerMixin.java b/src/main/java/com/flemmli97/flan/mixin/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 0000000..792153c --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,36 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.EntityInteractEvents; +import net.minecraft.entity.Entity; +import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket; +import net.minecraft.server.network.ServerPlayNetworkHandler; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * Fabric APIs UseEntityCallback is at Entity#interactAt and thats only used for armor stand. Why its only there idk... + */ +@Mixin(ServerPlayNetworkHandler.class) +public abstract class ServerPlayNetworkHandlerMixin { + + @Shadow + public ServerPlayerEntity player; + + @Inject(method = "onPlayerInteractEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerEntity;interact(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;"), cancellable = true) + public void onPlayerInteractEntity(PlayerInteractEntityC2SPacket packet, CallbackInfo info) { + World world = player.getEntityWorld(); + Entity entity = packet.getEntity(world); + if (entity != null) { + ActionResult result = EntityInteractEvents.useEntity(player, world, packet.getHand(), entity); + if (result != ActionResult.PASS) { + info.cancel(); + } + } + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/TurtleEggMixin.java b/src/main/java/com/flemmli97/flan/mixin/TurtleEggMixin.java new file mode 100644 index 0000000..23e72e5 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/TurtleEggMixin.java @@ -0,0 +1,22 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.BlockInteractEvents; +import net.minecraft.block.TurtleEggBlock; +import net.minecraft.entity.Entity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +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(TurtleEggBlock.class) +public class TurtleEggMixin { + + @Inject(method = "onSteppedOn", at = @At(value = "HEAD"), cancellable = true) + public void collision(World world, BlockPos pos, Entity entity, CallbackInfo info) { + if (BlockInteractEvents.turtleEggHandle(world, pos, entity)) { + info.cancel(); + } + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/WitherMixin.java b/src/main/java/com/flemmli97/flan/mixin/WitherMixin.java new file mode 100644 index 0000000..30459a7 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/WitherMixin.java @@ -0,0 +1,22 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.EntityInteractEvents; +import net.minecraft.entity.boss.WitherEntity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(WitherEntity.class) +public class WitherMixin { + + @Shadow + private int field_7082; + + @Inject(method = "mobTick", at = @At(value = "HEAD")) + public void preventClaimDmg(CallbackInfo info) { + if (!EntityInteractEvents.witherCanDestroy((WitherEntity) (Object) this)) + this.field_7082 = -1; + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/WorldClaimMixin.java b/src/main/java/com/flemmli97/flan/mixin/WorldClaimMixin.java new file mode 100644 index 0000000..012e61c --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/WorldClaimMixin.java @@ -0,0 +1,42 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.IClaimData; +import com.flemmli97.flan.claim.ClaimStorage; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.MutableWorldProperties; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +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.function.Supplier; + +@Mixin(ServerWorld.class) +public abstract class WorldClaimMixin extends World implements IClaimData { + @Unique + private ClaimStorage claimData; + + protected WorldClaimMixin(MutableWorldProperties properties, RegistryKey registryKey, DimensionType dimensionType, Supplier supplier, boolean bl, boolean bl2, long l) { + super(properties, registryKey, dimensionType, supplier, bl, bl2, l); + } + + @Inject(method = "*", at = @At("RETURN")) + private void initData(CallbackInfo info) { + this.claimData = new ClaimStorage(this.getServer(), this.getRegistryKey()); + } + + @Inject(method = "saveLevel()V", at = @At("RETURN")) + private void saveClaimData(CallbackInfo info) { + this.claimData.save(this.getServer(), this.getRegistryKey()); + } + + @Override + public ClaimStorage getClaimData() { + return this.claimData; + } +} diff --git a/src/main/java/com/flemmli97/flan/mixin/XpEntityMixin.java b/src/main/java/com/flemmli97/flan/mixin/XpEntityMixin.java new file mode 100644 index 0000000..baffddf --- /dev/null +++ b/src/main/java/com/flemmli97/flan/mixin/XpEntityMixin.java @@ -0,0 +1,21 @@ +package com.flemmli97.flan.mixin; + +import com.flemmli97.flan.event.EntityInteractEvents; +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.entity.player.PlayerEntity; +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(ExperienceOrbEntity.class) +public class XpEntityMixin { + + @Inject(method = "onPlayerCollision", at = @At(value = "HEAD"), cancellable = true) + public void collision(PlayerEntity player, CallbackInfo info) { + if (EntityInteractEvents.xpAbsorb(player)) { + info.cancel(); + } + } + +} diff --git a/src/main/java/com/flemmli97/flan/player/ClaimDisplay.java b/src/main/java/com/flemmli97/flan/player/ClaimDisplay.java new file mode 100644 index 0000000..2d05a80 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/player/ClaimDisplay.java @@ -0,0 +1,113 @@ +package com.flemmli97.flan.player; + +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ParticleIndicators; +import com.flemmli97.flan.config.ConfigHandler; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.world.Heightmap; +import net.minecraft.world.World; + +import java.util.List; +import java.util.Set; + +public class ClaimDisplay { + + private int displayTime; + private Claim toDisplay; + private int[][] poss; + + private int[][] middlePoss; + + private int[] prevDims; + + public ClaimDisplay(Claim claim) { + this.toDisplay = claim; + this.displayTime = ConfigHandler.config.claimDisplayTime; + this.prevDims = claim.getDimensions(); + } + + public boolean display(ServerPlayerEntity player) { + this.displayTime--; + int[] dims = this.toDisplay.getDimensions(); + if (this.poss == null || this.changed(dims)) { + this.middlePoss = this.calculateDisplayPos(player.world); + this.poss = new int[][]{ + this.getPosFrom(player.world, this.prevDims[0], this.prevDims[2], this.prevDims[4]), + this.getPosFrom(player.world, this.prevDims[1], this.prevDims[2], this.prevDims[4]), + this.getPosFrom(player.world, this.prevDims[0], this.prevDims[3], this.prevDims[4]), + this.getPosFrom(player.world, this.prevDims[1], this.prevDims[3], this.prevDims[4]), + }; + } + + if (this.poss != null) + for (int[] pos : this.poss) { + player.networkHandler.sendPacket(new ParticleS2CPacket(ParticleIndicators.CLAIMCORNER, true, pos[0] + 0.5, pos[1] + 0.25, pos[2] + 0.5, 0, 0.25f, 0, 0, 1)); + } + if (this.middlePoss != null) + for (int[] pos : this.middlePoss) { + player.networkHandler.sendPacket(new ParticleS2CPacket(ParticleIndicators.CLAIMMIDDLE, true, pos[0] + 0.5, pos[1] + 0.25, pos[2] + 0.5, 0, 0.25f, 0, 0, 1)); + } + this.prevDims = dims; + return toDisplay.isRemoved() || displayTime < 0; + } + + private boolean changed(int[] dims) { + for (int i = 0; i < dims.length; i++) + if (dims[i] != this.prevDims[i]) + return true; + return false; + } + + private int[][] calculateDisplayPos(World world) { + List l = Lists.newArrayList(); + Set xs = Sets.newHashSet(); + this.addEvenly(this.prevDims[0], this.prevDims[1], 10, xs); + Set zs = Sets.newHashSet(); + this.addEvenly(this.prevDims[2], this.prevDims[3], 10, zs); + for (int x : xs) { + l.add(this.getPosFrom(world, x, this.prevDims[2], this.prevDims[4])); + l.add(this.getPosFrom(world, x, this.prevDims[3], this.prevDims[4])); + + } + for (int z : zs) { + l.add(this.getPosFrom(world, this.prevDims[0], z, this.prevDims[4])); + l.add(this.getPosFrom(world, this.prevDims[1], z, this.prevDims[4])); + } + + return l.toArray(new int[0][]); + } + + private void addEvenly(int min, int max, int step, Set l) { + if (max - min < step * 1.5) + return; + if (max - min > 0 && max - min <= step * 0.5) { + l.add(max - step + 1); + l.add(min + step - 1); + return; + } + l.add(max - step); + l.add(min + step); + this.addEvenly(min + step, max - step, step, l); + } + + private int[] getPosFrom(World world, int x, int z, int maxY) { + return new int[]{x, Math.max(maxY, world.getChunk(x >> 4, z >> 4).sampleHeightmap(Heightmap.Type.WORLD_SURFACE, x & 15, z & 15) + 1), z}; + } + + @Override + public int hashCode() { + return this.toDisplay.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj instanceof ClaimDisplay) + return this.toDisplay.equals(((ClaimDisplay) obj).toDisplay); + return false; + } +} diff --git a/src/main/java/com/flemmli97/flan/player/EnumEditMode.java b/src/main/java/com/flemmli97/flan/player/EnumEditMode.java new file mode 100644 index 0000000..1772f84 --- /dev/null +++ b/src/main/java/com/flemmli97/flan/player/EnumEditMode.java @@ -0,0 +1,7 @@ +package com.flemmli97.flan.player; + +public enum EnumEditMode { + + DEFAULT, + SUBCLAIM +} diff --git a/src/main/java/com/flemmli97/flan/player/PlayerClaimData.java b/src/main/java/com/flemmli97/flan/player/PlayerClaimData.java new file mode 100644 index 0000000..d1d3bba --- /dev/null +++ b/src/main/java/com/flemmli97/flan/player/PlayerClaimData.java @@ -0,0 +1,272 @@ +package com.flemmli97.flan.player; + +import com.flemmli97.flan.IClaimData; +import com.flemmli97.flan.claim.Claim; +import com.flemmli97.flan.claim.ClaimStorage; +import com.flemmli97.flan.claim.ParticleIndicators; +import com.flemmli97.flan.config.ConfigHandler; +import com.google.common.collect.Sets; +import com.google.gson.JsonObject; +import net.minecraft.block.BlockState; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.packet.s2c.play.ParticleS2CPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.WorldSavePath; +import net.minecraft.util.math.BlockPos; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Collection; +import java.util.Set; +import java.util.UUID; + +public class PlayerClaimData { + + private int claimBlocks, additionalClaimBlocks, usedClaimsBlocks, confirmTick; + + private int lastBlockTick; + private EnumEditMode mode = EnumEditMode.DEFAULT; + private Claim editingClaim; + + private BlockPos firstCorner; + + private Set claimDisplayList = Sets.newHashSet(); + private Set displayToAdd = Sets.newHashSet(); + + private ServerPlayerEntity player; + + private boolean confirmDeleteAll, adminIgnoreClaim; + private boolean dirty; + + public PlayerClaimData(ServerPlayerEntity player) { + this.player = player; + this.claimBlocks = ConfigHandler.config.startingBlocks; + } + + public static PlayerClaimData get(PlayerEntity player) { + return (PlayerClaimData) ((IClaimData) player).getClaimData(); + } + + public int getClaimBlocks() { + return this.claimBlocks; + } + + public void setClaimBlocks(int amount) { + this.claimBlocks = amount; + this.dirty = true; + } + + public boolean addClaimBlocks(int amount) { + if (this.claimBlocks + amount > ConfigHandler.config.maxClaimBlocks) + return false; + this.claimBlocks += amount; + this.dirty = true; + return true; + } + + public int getAdditionalClaims() { + return this.additionalClaimBlocks; + } + + public void setAdditionalClaims(int amount) { + this.additionalClaimBlocks = amount; + this.dirty = true; + } + + public boolean useClaimBlocks(int amount) { + if (this.usedClaimsBlocks + amount > this.claimBlocks + this.additionalClaimBlocks) + return false; + this.usedClaimsBlocks += amount; + this.dirty = true; + return true; + } + + public Claim currentEdit() { + return this.editingClaim; + } + + public void setEditClaim(Claim claim) { + this.editingClaim = claim; + } + + public void addDisplayClaim(Claim claim) { + this.displayToAdd.add(new ClaimDisplay(claim)); + } + + public EnumEditMode getEditMode() { + return this.mode; + } + + public void setEditMode(EnumEditMode mode) { + this.mode = mode; + this.editingClaim = null; + this.firstCorner = null; + } + + public BlockPos editingCorner() { + return this.firstCorner; + } + + public void setEditingCorner(BlockPos pos) { + if (pos != null) { + BlockState state = this.player.world.getBlockState(pos); + while (state.isAir() || state.getMaterial().isReplaceable()) { + pos = pos.down(); + state = this.player.world.getBlockState(pos); + } + } + this.firstCorner = pos; + } + + public boolean confirmedDeleteAll() { + return this.confirmDeleteAll; + } + + public void setConfirmDeleteAll(boolean flag) { + this.confirmDeleteAll = flag; + this.confirmTick = 400; + } + + public void setAdminIgnoreClaim(boolean flag) { + this.adminIgnoreClaim = flag; + } + + public boolean isAdminIgnoreClaim() { + return this.adminIgnoreClaim; + } + + public void tick() { + ServerPlayerEntity sPlayer = this.player; + this.claimDisplayList.addAll(this.displayToAdd); + this.displayToAdd.clear(); + this.claimDisplayList.removeIf(d -> d.display(sPlayer)); + if (++this.lastBlockTick > ConfigHandler.config.ticksForNextBlock) { + this.addClaimBlocks(1); + this.lastBlockTick = 0; + } + if (this.firstCorner != null) { + this.player.networkHandler.sendPacket(new ParticleS2CPacket(ParticleIndicators.SETCORNER, true, this.firstCorner.getX() + 0.5, this.firstCorner.getY() + 1.25, this.firstCorner.getZ() + 0.5, 0, 0.25f, 0, 0, 3)); + if (this.player.getMainHandStack().getItem() != ConfigHandler.config.claimingItem && this.player.getOffHandStack().getItem() != ConfigHandler.config.claimingItem) { + this.firstCorner = null; + this.editingClaim = null; + } + } + if (--this.confirmTick < 0) + this.confirmDeleteAll = false; + } + + public void save(MinecraftServer server) { + File dir = new File(server.getSavePath(WorldSavePath.PLAYERDATA).toFile(), "/claimData/"); + if (!dir.exists()) + dir.mkdirs(); + try { + if (!this.dirty) + return; + File file = new File(dir, this.player.getUuid() + ".json"); + if (!file.exists()) + file.createNewFile(); + FileWriter writer = new FileWriter(file); + JsonObject obj = new JsonObject(); + obj.addProperty("ClaimBlocks", this.claimBlocks); + obj.addProperty("AdditionalBlocks", this.additionalClaimBlocks); + ClaimStorage.GSON.toJson(obj, writer); + writer.close(); + } catch (IOException e) { + + } + } + + public void read(MinecraftServer server) { + File dir = new File(server.getSavePath(WorldSavePath.PLAYERDATA).toFile(), "/claimData/"); + if (!dir.exists()) + return; + try { + File file = new File(dir, this.player.getUuid() + ".json"); + if (!file.exists()) + return; + FileReader reader = new FileReader(file); + JsonObject obj = ClaimStorage.GSON.fromJson(reader, JsonObject.class); + this.claimBlocks = obj.get("ClaimBlocks").getAsInt(); + this.additionalClaimBlocks = obj.get("AdditionalBlocks").getAsInt(); + reader.close(); + } catch (IOException e) { + + } + } + + public static void editForOfflinePlayer(MinecraftServer server, UUID uuid, int additionalClaimBlocks) { + File dir = new File(server.getSavePath(WorldSavePath.PLAYERDATA).toFile(), "/claimData/"); + if (!dir.exists()) + dir.mkdirs(); + try { + File file = new File(dir, uuid.toString() + ".json"); + if (!file.exists()) + file.createNewFile(); + FileReader reader = new FileReader(file); + JsonObject obj = ClaimStorage.GSON.fromJson(reader, JsonObject.class); + reader.close(); + if (obj == null) + obj = new JsonObject(); + int additionalBlocks = obj.get("AdditionalBlocks").getAsInt(); + obj.addProperty("AdditionalBlocks", additionalBlocks + additionalClaimBlocks); + FileWriter writer = new FileWriter(file); + ClaimStorage.GSON.toJson(obj, writer); + writer.close(); + } catch (IOException e) { + + } + } + + private void calculateUsedClaimBlocks() { + this.usedClaimsBlocks = 0; + for (ServerWorld world : this.player.getServer().getWorlds()) { + Collection claims = ClaimStorage.get(world).playerClaimMap.get(this.player.getUuid()); + if (claims != null) + claims.forEach(claim -> this.usedClaimsBlocks += claim.getPlane()); + } + } + + public static void readGriefPreventionPlayerData(MinecraftServer server) { + File griefPrevention = server.getSavePath(WorldSavePath.ROOT).resolve("GriefPreventionData/PlayerData").toFile(); + if (!griefPrevention.exists()) + return; + try { + for (File f : griefPrevention.listFiles()) { + if (f.getName().startsWith("$")) { + + } else { + BufferedReader reader = new BufferedReader(new FileReader(f)); + PlayerEntity player = server.getPlayerManager().getPlayer(UUID.fromString(f.getName())); + if (player != null) { + PlayerClaimData data = PlayerClaimData.get(player); + reader.readLine(); + data.claimBlocks = Integer.parseInt(reader.readLine()); + data.additionalClaimBlocks = Integer.parseInt(reader.readLine()); + } else { + File dir = new File(server.getSavePath(WorldSavePath.PLAYERDATA).toFile(), "/claimData/"); + if (!dir.exists()) + dir.mkdir(); + File file = new File(dir, f.getName() + ".json"); + if (!file.exists()) + file.createNewFile(); + reader.readLine(); + FileWriter writer = new FileWriter(file); + JsonObject obj = new JsonObject(); + obj.addProperty("ClaimBlocks", reader.readLine()); + obj.addProperty("AdditionalBlocks", reader.readLine()); + ClaimStorage.GSON.toJson(obj, writer); + writer.close(); + } + reader.close(); + } + } + } catch (IOException e) { + + } + } +} diff --git a/src/main/resources/assets/flan/icon.png b/src/main/resources/assets/flan/icon.png new file mode 100644 index 0000000..047b91f Binary files /dev/null and b/src/main/resources/assets/flan/icon.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..edf495b --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,37 @@ +{ + "schemaVersion": 1, + "id": "flan", + "version": "${version}", + + "name": "Flan", + "description": "A claiming mod for fabric", + "authors": [ + "Flemmli97" + ], + "contact": { + "homepage": "", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + + "license": "CC0-1.0", + "icon": "assets/modid/icon.png", + + "environment": "*", + "entrypoints": { + "main": [ + "com.flemmli97.flan.Flan" + ] + }, + "mixins": [ + "flan.mixins.json" + ], + + "depends": { + "fabricloader": ">=0.7.4", + "fabric": "*", + "minecraft": "1.16.x" + }, + "suggests": { + "flamingo": "*" + } +} diff --git a/src/main/resources/flan.mixins.json b/src/main/resources/flan.mixins.json new file mode 100644 index 0000000..5f5e65c --- /dev/null +++ b/src/main/resources/flan.mixins.json @@ -0,0 +1,25 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "com.flemmli97.flan.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "PlayerClaimMixin", + "WorldClaimMixin", + "ServerPlayNetworkHandlerMixin", + "AbstractBlockStateMixin", + "EntityMixin", + "ProjectileMixin", + "TurtleEggMixin", + "XpEntityMixin", + "WitherMixin", + "ExplosionMixin", + "EnderPearlEntityMixin", + "IPersistentProjectileVars" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +}