From ff1c9342ca4e77bbb4becd6caae5be79724627bb Mon Sep 17 00:00:00 2001 From: Oth3r Date: Thu, 20 Jul 2023 20:17:52 -0500 Subject: [PATCH] Initial commit --- .gitignore | 40 +++ build.gradle | 76 +++++ gradle.properties | 19 ++ gradlew | 248 ++++++++++++++++ gradlew.bat | 92 ++++++ settings.gradle | 10 + src/main/java/one/oth3r/sit/Events.java | 265 ++++++++++++++++++ src/main/java/one/oth3r/sit/LangReader.java | 100 +++++++ src/main/java/one/oth3r/sit/ModMenu.java | 196 +++++++++++++ src/main/java/one/oth3r/sit/Sit.java | 31 ++ src/main/java/one/oth3r/sit/SitCommand.java | 66 +++++ src/main/java/one/oth3r/sit/SitServer.java | 12 + src/main/java/one/oth3r/sit/config.java | 201 +++++++++++++ src/main/resources/assets/sit/icon.png | Bin 0 -> 9842 bytes src/main/resources/assets/sit/lang/en_us.json | 55 ++++ src/main/resources/fabric.mod.json | 41 +++ src/main/resources/sit.mixins.json | 11 + 17 files changed, 1463 insertions(+) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle create mode 100644 src/main/java/one/oth3r/sit/Events.java create mode 100644 src/main/java/one/oth3r/sit/LangReader.java create mode 100644 src/main/java/one/oth3r/sit/ModMenu.java create mode 100644 src/main/java/one/oth3r/sit/Sit.java create mode 100644 src/main/java/one/oth3r/sit/SitCommand.java create mode 100644 src/main/java/one/oth3r/sit/SitServer.java create mode 100644 src/main/java/one/oth3r/sit/config.java create mode 100644 src/main/resources/assets/sit/icon.png create mode 100644 src/main/resources/assets/sit/lang/en_us.json create mode 100644 src/main/resources/fabric.mod.json create mode 100644 src/main/resources/sit.mixins.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c476faf --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# macos + +*.DS_Store + +# fabric + +run/ + +# java + +hs_err_*.log +replay_*.log +*.hprof +*.jfr diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..243770a --- /dev/null +++ b/build.gradle @@ -0,0 +1,76 @@ +plugins { + id 'fabric-loom' version '1.3-SNAPSHOT' + id 'maven-publish' +} + +version = project.mod_version +group = project.maven_group + +base { + archivesName = project.archives_base_name +} + +repositories { + maven { url "https://maven.terraformersmc.com/releases/" } + maven { url "https://maven.isxander.dev/releases" } +} + +dependencies { + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + modImplementation "com.terraformersmc:modmenu:${project.modmenu_version}" + modImplementation "dev.isxander.yacl:yet-another-config-lib-fabric:${project.yacl_version}" + + // Uncomment the following line to enable the deprecated Fabric API modules. + // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. + // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" +} + +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 17 +} + +java { + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +jar { + from("LICENSE") { + rename { "${it}_${project.base.archivesName.get()}"} + } +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..0a2f8b1 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,19 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +org.gradle.parallel=true + +# Fabric Properties +# check these on https://fabricmc.net/develop +minecraft_version=1.20.1 +yarn_mappings=1.20.1+build.9 +loader_version=0.14.21 + +# Mod Properties +mod_version=b0.0.1+1.20-1.20.1 +maven_group=one.oth3r +archives_base_name=sit! + +# Dependencies +fabric_version=0.85.0+1.20.1 +modmenu_version=7.0.0 +yacl_version=3.0.0+1.20 diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..fcb6fca --- /dev/null +++ b/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..75c4d72 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + mavenCentral() + gradlePluginPortal() + } +} \ No newline at end of file diff --git a/src/main/java/one/oth3r/sit/Events.java b/src/main/java/one/oth3r/sit/Events.java new file mode 100644 index 0000000..a97d336 --- /dev/null +++ b/src/main/java/one/oth3r/sit/Events.java @@ -0,0 +1,265 @@ +package one.oth3r.sit; + +import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; +import net.minecraft.block.*; +import net.minecraft.block.enums.BlockHalf; +import net.minecraft.block.enums.SlabType; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.decoration.DisplayEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.registry.Registries; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class Events { + private static int tick; + public static HashMap entities = new HashMap<>(); + public static HashMap checkPlayers = new HashMap<>(); + public static boolean checkLogic(ServerPlayerEntity player) { + Item mainItem = player.getMainHandStack().getItem(); + Item offItem = player.getOffHandStack().getItem(); + if (player.isSneaking()) return false; + if (config.mainReq.equals(config.MainReq.empty) && !player.getMainHandStack().isEmpty()) return false; + if (config.mainReq.equals(config.MainReq.restrictive)) { + if (checkList(config.mainBlacklist,mainItem)) return false; + if (!checkList(config.mainWhitelist,mainItem)) { + if (config.mainBlock && (mainItem instanceof BlockItem)) return false; + if (config.mainFood && mainItem.isFood()) return false; + if (config.mainUsable && player.getMainHandStack().isUsedOnRelease()) return false; + } + } + if (config.offReq.equals(config.OffReq.empty) && !player.getOffHandStack().isEmpty()) return false; + if (config.offReq.equals(config.OffReq.restrictive)) { + if (checkList(config.offBlacklist,offItem)) return false; + if (!checkList(config.offWhitelist,offItem)) { + if (config.offBlock && (offItem instanceof BlockItem)) return false; + if (config.offFood && offItem.isFood()) return false; + if (config.offUsable && player.getOffHandStack().isUsedOnRelease()) return false; + } + } + return true; + } + public static boolean checkList(List list, Item item) { + String itemID = Registries.ITEM.getId(item).toString(); + System.out.println(itemID); + return list.contains(itemID); + } + public static HashMap> getCustomBlocks() { + HashMap> map = new HashMap<>(); + int i = 1; + for (String s:config.customBlocks) { + String[] split = s.split("\\|"); + HashMap data = new HashMap<>(); + data.put("block",split[0]); + data.put("height",split[1]); + data.put("hitbox",split[2]); + if (split.length==4) data.put("state",split[3]); + map.put(i+"",data); + i++; + } + return map; + } + @SuppressWarnings("deprecation") + public static boolean checkBlocks(BlockPos pos, World world) { + BlockState blockState = world.getBlockState(pos); + Block block = blockState.getBlock(); + BlockState blockStateAbove = world.getBlockState(pos.add(0,1,0)); + Block blockAbove = blockStateAbove.getBlock(); + System.out.println(blockState); + //not the biggest fan but ah well + if (blockStateAbove.isFullCube(world,pos.add(0,1,0)) && blockStateAbove.blocksMovement()) return false; + else if (blockAbove instanceof StairsBlock || blockAbove instanceof SlabBlock || blockAbove instanceof CarpetBlock) return false; + for (Entity entity:entities.values()) if (entity.getBlockPos().equals(pos) || entity.getBlockPos().add(0,1,0).equals(pos)) return false; + if (block instanceof StairsBlock && config.stairsOn) return blockState.get(StairsBlock.HALF) == BlockHalf.BOTTOM; + if (block instanceof SlabBlock && config.slabsOn) return blockState.get(SlabBlock.TYPE) == SlabType.BOTTOM; + if (block instanceof CarpetBlock && config.carpetsOn) return true; + if (blockState.isFullCube(world,pos.add(0,1,0)) && config.fullBlocksOn) return true; + if (config.customOn && config.customBlocks.size() != 0) { + System.out.println("checking custom"); + for (HashMap map:getCustomBlocks().values()) { + String blockID = Registries.BLOCK.getId(block).toString(); + if (map.get("block").equals(blockID)) { + if (!map.containsKey("state")) return true; + String[] states = ((String) map.get("state")).split(",\\s*"); + boolean matching = true; + for (String state:states) { + if (state.charAt(0) == '!') + if (blockState.toString().contains(state.substring(1))) matching = false; + else if (!blockState.toString().contains(state)) matching = false; + } + return matching; + } + } + } + return false; + } + public static void setEntity(BlockPos pos, World world, Entity entity) { + Block block = world.getBlockState(pos).getBlock(); + entity.setCustomName(Text.of(Sit.ENTITY_NAME)); + entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.47, pos.getZ() + 0.5, 0, 0); + entity.setInvulnerable(true); + if (block instanceof StairsBlock) { + entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.27, pos.getZ() + 0.5, 0, 0); + entity.setBoundingBox(Box.of(Vec3d.of(pos),1.5,2,1.5)); + } + if (block instanceof SlabBlock) { + entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.27, pos.getZ() + 0.5, 0, 0); + entity.setBoundingBox(Box.of(Vec3d.of(pos),1.5,1,1.5)); + } + if (block instanceof CarpetBlock) { + entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()-.17, pos.getZ() + 0.5, 0, 0); + entity.setBoundingBox(Box.of(Vec3d.of(pos),1.5,0.125,1.5)); + } + if (world.getBlockState(pos).isFullCube(world,pos.add(0,1,0))) { + entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+.78, pos.getZ() + 0.5, 0, 0); + entity.setBoundingBox(Box.of(Vec3d.of(pos),1.5,2,1.5)); + } + if (config.customOn && config.customBlocks.size() != 0) { + System.out.println("checking custom sit height"); + for (HashMap map:getCustomBlocks().values()) { + String blockID = Registries.BLOCK.getId(block).toString(); + if (map.get("block").equals(blockID)) { + double input = Math.max(Math.min(Double.parseDouble((String) map.get("height")),1),0); + entity.updatePositionAndAngles(pos.getX() + 0.5, pos.getY()+input-.22, pos.getZ() + 0.5, 0, 0); + entity.setBoundingBox(Box.of(Vec3d.of(pos),1.5,Double.parseDouble((String) map.get("hitbox")),1.5)); + } + } + } + //change pitch based on if player is sitting below block height or not + if (entity.getY() <= pos.getY()+.35) entity.setPitch(90); + else entity.setPitch(-90); + } + public static void register() { + UseBlockCallback.EVENT.register((pl, world, hand, hitResult) -> { + ServerPlayerEntity player = Sit.server.getPlayerManager().getPlayer(pl.getUuid()); + if (player == null) return ActionResult.PASS; + if (hand == net.minecraft.util.Hand.MAIN_HAND && hitResult.getType() == HitResult.Type.BLOCK) { + BlockPos pos = hitResult.getBlockPos(); + //todo idk find bugs and polish + if (!checkLogic(player)) return ActionResult.PASS; + if (checkBlocks(pos,world)) { + if (entities.containsKey(player)) { + if (!config.sitWhileSeated) return ActionResult.PASS; + entities.get(player).setRemoved(Entity.RemovalReason.DISCARDED); + entities.remove(player); + } + DisplayEntity.TextDisplayEntity entity = new DisplayEntity.TextDisplayEntity(EntityType.TEXT_DISPLAY,player.getServerWorld()); + setEntity(pos,world,entity); + player.getServerWorld().spawnEntity(entity); + player.startRiding(entity); + entities.put(player,entity); + } + } + return ActionResult.PASS; + }); + ServerTickEvents.END_SERVER_TICK.register(minecraftServer -> minecraftServer.execute(Events::cleanUp)); + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ServerPlayerEntity player = handler.player; + checkPlayers.put(player,2); + }); + ServerPlayConnectionEvents.DISCONNECT.register((handler, server) -> { + ServerPlayerEntity player = handler.player; + if (entities.containsKey(player)) { + if (!config.keepActive) { + player.dismountVehicle(); + entities.get(player).setRemoved(Entity.RemovalReason.DISCARDED); + } + entities.remove(player); + } + checkPlayers.remove(player); + }); + ServerLifecycleEvents.SERVER_STARTED.register(s -> { + Sit.server = s; + Sit.commandManager = s.getCommandManager(); + }); + CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> SitCommand.register(dispatcher)); + } + public static void cleanUp() { + tick++; + if (tick >= 5) { + tick = 0; + Iterator> entityLoop = entities.entrySet().iterator(); + while (entityLoop.hasNext()) { + Map.Entry entry = entityLoop.next(); + ServerPlayerEntity player = entry.getKey(); + Entity entity = entry.getValue(); + if (player.getVehicle() == null || !player.getVehicle().equals(entity)) { + entity.setRemoved(Entity.RemovalReason.DISCARDED); + System.out.println("removed.."); + entityLoop.remove(); + } else { + BlockPos pos = new BlockPos(entity.getBlockX(),(int) Math.floor(player.getY()),entity.getBlockZ()); + if (entity.getPitch() == 90) pos = new BlockPos(entity.getBlockX(),(int) Math.ceil(player.getY()),entity.getBlockZ()); + BlockState blockState = player.getWorld().getBlockState(pos); + if (blockState.isAir()) { + System.out.println(pos); + System.out.println(entity.getY()); + System.out.println("dismount"); + player.teleport(player.getX(),player.getBlockY()+1,player.getZ()); + entity.setRemoved(Entity.RemovalReason.DISCARDED); + entityLoop.remove(); + } + } + } + Iterator> playerCheckLoop = checkPlayers.entrySet().iterator(); + while (playerCheckLoop.hasNext()) { + Map.Entry entry = playerCheckLoop.next(); + ServerPlayerEntity player = entry.getKey(); + int i = entry.getValue(); + checkPlayers.put(player,i-1); + if (i<0) { + System.out.println("fail"); + playerCheckLoop.remove(); + continue; + } + System.out.println("trying to add back"); + if (player.getVehicle() != null) { + Entity entity = player.getVehicle(); + if (entity.getName().getString().equals(Sit.ENTITY_NAME)) { + System.out.println("adding back"); + setEntity(player.getBlockPos().add(0,1,0),player.getServerWorld(),entity); + entities.put(player,entity); + playerCheckLoop.remove(); + } + } + } + + for (ServerPlayerEntity player:checkPlayers.keySet()) { + int i = checkPlayers.get(player); + checkPlayers.put(player,i-1); + if (i<0) { + System.out.println("fail"); + checkPlayers.remove(player); + continue; + } + System.out.println("trying to add back"); + if (player.getVehicle() != null) { + Entity entity = player.getVehicle(); + if (entity.getName().getString().equals(Sit.ENTITY_NAME)) { + System.out.println("adding back"); + setEntity(player.getBlockPos().add(0,1,0),player.getServerWorld(),entity); + entities.put(player,entity); + checkPlayers.remove(player); + } + } + } + } + } +} diff --git a/src/main/java/one/oth3r/sit/LangReader.java b/src/main/java/one/oth3r/sit/LangReader.java new file mode 100644 index 0000000..e34692c --- /dev/null +++ b/src/main/java/one/oth3r/sit/LangReader.java @@ -0,0 +1,100 @@ +package one.oth3r.sit; + +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.text.TextContent; + +import java.io.InputStream; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class LangReader { + private static final Map languageMap = new HashMap<>(); + private final String translationKey; + private final Object[] placeholders; + public LangReader(String translationKey, Object... placeholders) { + this.translationKey = translationKey; + this.placeholders = placeholders; + } + public MutableText getTxT() { + String translated = getLanguageValue(translationKey); + if (placeholders != null && placeholders.length > 0) { + //removed all double \\ and replaces with \ + translated = translated.replaceAll("\\\\\\\\", "\\\\"); + String regex = "%\\d*\\$?[dfs]"; + Matcher anyMatch = Pattern.compile(regex).matcher(translated); + Matcher endMatch = Pattern.compile(regex+"$").matcher(translated); + //Arraylist with all the %(#$)[dfs] + ArrayList matches = new ArrayList<>(); + while (anyMatch.find()) { + String match = anyMatch.group(); + matches.add(match); + } + //SPLITS the text at each regex and remove the regex + String[] parts = translated.split(regex); + //if the last element of the array ends with regex, remove it and add an empty string to the end of the array + if (endMatch.find()) { + String[] newParts = Arrays.copyOf(parts, parts.length + 1); + newParts[parts.length] = ""; + parts = newParts; + } + //if there are placeholders specified, and the split is more than 1, it will replace %(dfs) with the placeholder objects + if (parts.length > 1) { + MutableText txt = Text.empty(); + int i = 0; + for (String match : matches) { + int get = i; + //if the match is numbered, change GET to the number it wants + if (match.contains("$")) { + match = match.substring(1,match.indexOf('$')); + get = Integer.parseInt(match)-1; + } + if (parts.length != i) txt.append(parts[i]); + //convert the obj into txt + Object obj = placeholders[get]; + if (obj instanceof Text) txt.append((Text) obj); + else txt.append(String.valueOf(obj)); + i++; + } + if (parts.length != i) txt.append(parts[i]); + return txt; + } + } + return MutableText.of(TextContent.EMPTY).append(translated); + } + public static LangReader of(String translationKey, Object... placeholders) { + return new LangReader(translationKey, placeholders); + } + public static void loadLanguageFile() { + try { + ClassLoader classLoader = Sit.class.getClassLoader(); + InputStream inputStream = classLoader.getResourceAsStream("assets/sit/lang/"+ config.lang+".json"); + if (inputStream == null) { + inputStream = classLoader.getResourceAsStream("assets/sit/lang/"+config.defaults.lang+".json"); + config.lang = config.defaults.lang; + } + if (inputStream == null) throw new IllegalArgumentException("CANT LOAD THE LANGUAGE FILE. DIRECTIONHUD WILL BREAK."); + Scanner scanner = new Scanner(inputStream); + String currentLine; + while (scanner.hasNextLine()) { + currentLine = scanner.nextLine().trim(); + if (currentLine.startsWith("{") || currentLine.startsWith("}")) { + continue; + } + String[] keyValue = currentLine.split(":", 2); + String key = keyValue[0].trim(); + key = key.substring(1,key.length()-1).replace("\\",""); + String value = keyValue[1].trim(); + if (value.endsWith(",")) value = value.substring(0, value.length() - 1); + value = value.substring(1,value.length()-1).replace("\\",""); + languageMap.put(key, value); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + public static String getLanguageValue(String key) { + return languageMap.getOrDefault(key, key); + } +} \ No newline at end of file diff --git a/src/main/java/one/oth3r/sit/ModMenu.java b/src/main/java/one/oth3r/sit/ModMenu.java new file mode 100644 index 0000000..31f6528 --- /dev/null +++ b/src/main/java/one/oth3r/sit/ModMenu.java @@ -0,0 +1,196 @@ +package one.oth3r.sit; + +import com.terraformersmc.modmenu.api.ConfigScreenFactory; +import com.terraformersmc.modmenu.api.ModMenuApi; +import dev.isxander.yacl3.api.*; +import dev.isxander.yacl3.api.controller.BooleanControllerBuilder; +import dev.isxander.yacl3.api.controller.EnumControllerBuilder; +import dev.isxander.yacl3.api.controller.StringControllerBuilder; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.text.TextColor; +import net.minecraft.util.Formatting; + +public class ModMenu implements ModMenuApi { + private static MutableText lang(String key) { + return Text.translatable("config.sit."+key); + } + private static MutableText lang(String key, Object... args) { + return Text.translatable("config.sit."+key,args); + } + @Override + public ConfigScreenFactory getModConfigScreenFactory() { + return parent -> YetAnotherConfigLib.createBuilder() + .title(Text.of("Sit!")) + .category(ConfigCategory.createBuilder() + .name(lang("category.general")) + .tooltip(lang("category.general.tooltip")) + .option(Option.createBuilder() + .name(lang("general.keep_active")) + .description(OptionDescription.of(lang("general.keep_active.description"))) + .binding(config.defaults.keepActive, () -> config.keepActive, n -> config.keepActive = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("general.sit_while_seated")) + .description(OptionDescription.of(lang("general.sit_while_seated.description"))) + .binding(config.defaults.sitWhileSeated, () -> config.sitWhileSeated, n -> config.sitWhileSeated = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .group(OptionGroup.createBuilder() + .name(lang("general.sittable")) + .description(OptionDescription.of(lang("general.sittable.description"))) + .option(Option.createBuilder() + .name(lang("general.sittable.stairs")) + .binding(config.defaults.stairsOn, () -> config.stairsOn, n -> config.stairsOn = n) + .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("general.sittable.slabs")) + .binding(config.defaults.slabsOn, () -> config.slabsOn, n -> config.slabsOn = n) + .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("general.sittable.carpets")) + .binding(config.defaults.carpetsOn, () -> config.carpetsOn, n -> config.carpetsOn = n) + .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("general.sittable.full_blocks")) + .binding(config.defaults.fullBlocksOn, () -> config.fullBlocksOn, n -> config.fullBlocksOn = n) + .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("general.sittable.custom")) + .description(OptionDescription.of(lang("general.sittable.custom.description"))) + .binding(config.defaults.customOn, () -> config.customOn, n -> config.customOn = n) + .controller(opt -> BooleanControllerBuilder.create(opt).onOffFormatter()) + .build()) + .build()) + .group(ListOption.createBuilder() + .name(lang("general.sittable_blocks")) + .description(OptionDescription.of( + lang("general.sittable_blocks.description") + .append("\n\n").append(lang("general.sittable_blocks.description_2")) + .append(lang("general.sittable_blocks.description_3", + lang("general.sittable_blocks.description_3_2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA))), + lang("general.sittable_blocks.description_3_3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED))), + lang("general.sittable_blocks.description_3_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN))), + lang("general.sittable_blocks.description_3_5").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD)))).styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY)))) + .append("\n\n").append(lang("general.sittable_blocks.description_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) + .append("\n").append(lang("general.sittable_blocks.description_5").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))) + .append("\n").append(lang("general.sittable_blocks.description_6").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) + .append("\n").append(lang("general.sittable_blocks.description_7").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GOLD)))) + .append("\n\n").append(lang("general.sittable_blocks.description_8").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.YELLOW)))))) + .binding(config.defaults.customBlocks, () -> config.customBlocks, n -> config.customBlocks = n) + .controller(StringControllerBuilder::create) + .initial("") + .build()) + .build()) + .category(ConfigCategory.createBuilder() + .name(lang("category.main_hand")) + .tooltip(lang("category.main_hand.tooltip")) + .option(Option.createBuilder() + .name(lang("hand.requirements")) + .description(OptionDescription.of(lang("hand.requirements.description") + .append("\n\n").append(lang("hand.requirements.description_2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) + .append("\n").append(lang("hand.requirements.description_3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) + .append("\n").append(lang("hand.requirements.description_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))))) + .binding(config.defaults.mainReq, () -> config.mainReq, n -> config.mainReq = n) + .controller(opt -> EnumControllerBuilder.create(opt).enumClass(config.MainReq.class) + .valueFormatter(v -> Text.translatable("config.sit."+v.name().toLowerCase()))) + .build()) + .group(OptionGroup.createBuilder() + .name(lang("hand.restrictions")) + .description(OptionDescription.of(lang("hand.restrictions.description"))) + .option(Option.createBuilder() + .name(lang("hand.restrictions.blocks")) + .binding(config.defaults.mainBlock,()-> config.mainBlock,n -> config.mainBlock = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("hand.restrictions.food")) + .binding(config.defaults.mainFood,()-> config.mainFood,n -> config.mainFood = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("hand.restrictions.usable")) + .description(OptionDescription.of(lang("hand.restrictions.usable.description"))) + .binding(config.defaults.mainUsable,()-> config.mainUsable,n -> config.mainUsable = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .build()) + .group(ListOption.createBuilder() + .name(lang("hand.whitelist")) + .description(OptionDescription.of(lang("hand.whitelist.description") + .append("\n\n").append(lang("hand.list.description")) + .append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY)))))) + .binding(config.defaults.mainWhitelist, () -> config.mainWhitelist, n -> config.mainWhitelist = n) + .controller(StringControllerBuilder::create) + .initial("") + .build()) + .group(ListOption.createBuilder() + .name(lang("hand.blacklist")) + .description(OptionDescription.of(lang("hand.blacklist.description") + .append("\n\n").append(lang("hand.list.description")) + .append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY)))))) + .binding(config.defaults.mainBlacklist, () -> config.mainBlacklist, n -> config.mainBlacklist = n) + .controller(StringControllerBuilder::create) + .initial("") + .build()) + .build()) + .category(ConfigCategory.createBuilder() + .name(lang("category.off_hand")) + .tooltip(lang("category.off_hand.tooltip")) + .option(Option.createBuilder() + .name(lang("hand.requirements")) + .description(OptionDescription.of(lang("hand.requirements.description") + .append("\n\n").append(lang("hand.requirements.description_2").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.AQUA)))) + .append("\n").append(lang("hand.requirements.description_3").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))) + .append("\n").append(lang("hand.requirements.description_4").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.RED)))))) + .binding(config.defaults.offReq, () -> config.offReq, n -> config.offReq = n) + .controller(opt -> EnumControllerBuilder.create(opt).enumClass(config.OffReq.class) + .valueFormatter(v -> Text.translatable("config.sit."+v.name().toLowerCase()))) + .build()) + .group(OptionGroup.createBuilder() + .name(lang("hand.restrictions")) + .description(OptionDescription.of(lang("hand.restrictions.description"))) + .option(Option.createBuilder() + .name(lang("hand.restrictions.blocks")) + .binding(config.defaults.offBlock,()-> config.offBlock,n -> config.offBlock = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("hand.restrictions.food")) + .binding(config.defaults.offFood,()-> config.offFood,n -> config.offFood = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .option(Option.createBuilder() + .name(lang("hand.restrictions.usable")) + .description(OptionDescription.of(lang("hand.restrictions.usable.description"))) + .binding(config.defaults.offUsable,()-> config.offUsable,n -> config.offUsable = n) + .controller(opt -> BooleanControllerBuilder.create(opt).trueFalseFormatter()) + .build()) + .build()) + .group(ListOption.createBuilder() + .name(lang("hand.whitelist")) + .description(OptionDescription.of(lang("hand.whitelist.description") + .append("\n\n").append(lang("hand.list.description")) + .append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY)))))) + .binding(config.defaults.offWhitelist, () -> config.offWhitelist, n -> config.offWhitelist = n) + .controller(StringControllerBuilder::create) + .initial("") + .build()) + .group(ListOption.createBuilder() + .name(lang("hand.blacklist")) + .description(OptionDescription.of(lang("hand.blacklist.description") + .append("\n\n").append(lang("hand.list.description")) + .append(lang("hand.list.description_2").styled(style -> style.withItalic(true).withColor(TextColor.fromFormatting(Formatting.GRAY)))))) + .binding(config.defaults.offBlacklist, () -> config.offBlacklist, n -> config.offBlacklist = n) + .controller(StringControllerBuilder::create) + .initial("") + .build()) + .build()) + .build().generateScreen(parent); + } +} diff --git a/src/main/java/one/oth3r/sit/Sit.java b/src/main/java/one/oth3r/sit/Sit.java new file mode 100644 index 0000000..ee4d704 --- /dev/null +++ b/src/main/java/one/oth3r/sit/Sit.java @@ -0,0 +1,31 @@ +package one.oth3r.sit; + +import net.fabricmc.api.ModInitializer; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.command.CommandManager; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class Sit implements ModInitializer { + public static final Logger LOGGER = LoggerFactory.getLogger("sit"); + public static final String ENTITY_NAME = "-sit!-entity-"; + public static MinecraftServer server; + public static CommandManager commandManager; + public static boolean isClient = true; + + @Override + public void onInitialize() { + //todo future: + // make it so it updates the sitting height and pos based on the block so if it changed while offline it still works (or if stair changes shape) + // inner stair offset & custom support for that ig + config.load(); + Events.register(); + } + public static MutableText lang(String key, Object... args) { + if (isClient) return Text.translatable(key, args); + else return LangReader.of(key, args).getTxT(); + } +} \ No newline at end of file diff --git a/src/main/java/one/oth3r/sit/SitCommand.java b/src/main/java/one/oth3r/sit/SitCommand.java new file mode 100644 index 0000000..68f64f1 --- /dev/null +++ b/src/main/java/one/oth3r/sit/SitCommand.java @@ -0,0 +1,66 @@ +package one.oth3r.sit; + +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.ParseResults; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import net.minecraft.server.command.CommandManager; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.TextColor; +import net.minecraft.util.Formatting; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +public class SitCommand { + public static void register(CommandDispatcher dispatcher) { + dispatcher.register(CommandManager.literal("sit") + .requires((commandSource) -> commandSource.hasPermissionLevel(2)) + .executes((context2) -> command(context2.getSource(), context2.getInput())) + .then(CommandManager.argument("args", StringArgumentType.string()) + .suggests(SitCommand::getSuggestions) + .executes((context2) -> command(context2.getSource(), context2.getInput())))); + } + public static CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) { + ServerPlayerEntity player = Objects.requireNonNull(context.getSource().getPlayer()); + String[] args = context.getInput().split(" "); + builder.suggest("reload"); + builder.suggest("purgeChairEntities"); + return builder.buildFuture(); + } + private static int command(ServerCommandSource source, String arg) { + ServerPlayerEntity player = source.getPlayer(); + if (player == null) return 1; + //trim all the arguments before the command + String keyword = "sit"; + int index = Integer.MAX_VALUE; + if (arg.contains(keyword)) index = arg.indexOf(keyword); + //trims the words before the text + if (index != Integer.MAX_VALUE) arg = arg.substring(index).trim(); + String[] args = arg.split(" "); + if (args[0].equalsIgnoreCase("sit")) + args = arg.replaceFirst("sit ", "").split(" "); + + if (args[0].equalsIgnoreCase("reload")) { + config.load(); + player.sendMessage(Sit.lang("key.sit.command.reloaded").styled(style -> style.withColor(TextColor.fromFormatting(Formatting.GREEN)))); + } + if (args[0].equalsIgnoreCase("purgeChairEntities")) { + String cmd = "kill @e[type=minecraft:text_display,name=\""+Sit.ENTITY_NAME+"\"]"; + try { + ParseResults parse = + Sit.commandManager.getDispatcher().parse(cmd, player.getCommandSource()); + Sit.commandManager.getDispatcher().execute(parse); + player.sendMessage(Sit.lang("key.sit.command.purged")); + } catch (CommandSyntaxException e) { + player.sendMessage(Sit.lang("key.sit.command.purged")); + e.printStackTrace(); + } + } + return 1; + } +} diff --git a/src/main/java/one/oth3r/sit/SitServer.java b/src/main/java/one/oth3r/sit/SitServer.java new file mode 100644 index 0000000..199f5da --- /dev/null +++ b/src/main/java/one/oth3r/sit/SitServer.java @@ -0,0 +1,12 @@ +package one.oth3r.sit; + +import net.fabricmc.api.DedicatedServerModInitializer; + +public class SitServer implements DedicatedServerModInitializer { + @Override + public void onInitializeServer() { + Sit.isClient = false; + config.load(); + LangReader.loadLanguageFile(); + } +} diff --git a/src/main/java/one/oth3r/sit/config.java b/src/main/java/one/oth3r/sit/config.java new file mode 100644 index 0000000..4e31a03 --- /dev/null +++ b/src/main/java/one/oth3r/sit/config.java @@ -0,0 +1,201 @@ +package one.oth3r.sit; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.text.MutableText; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class config { + public static String lang = defaults.lang; + public static boolean keepActive = defaults.keepActive; + public static boolean sitWhileSeated = defaults.sitWhileSeated; + public static boolean stairsOn = defaults.stairsOn; + public static boolean slabsOn = defaults.slabsOn; + public static boolean carpetsOn = defaults.carpetsOn; + public static boolean fullBlocksOn = defaults.fullBlocksOn; + public static boolean customOn = defaults.customOn; + public static List customBlocks = defaults.customBlocks; + enum MainReq { + empty, + restrictive, + none + } + public static MainReq mainReq = defaults.mainReq; + public static boolean mainBlock = defaults.mainBlock; + public static boolean mainFood = defaults.mainFood; + public static boolean mainUsable = defaults.mainUsable; + public static List mainWhitelist = defaults.mainWhitelist; + public static List mainBlacklist = defaults.mainBlacklist; + enum OffReq { + empty, + restrictive, + none + } + public static OffReq offReq = defaults.offReq; + public static boolean offBlock = defaults.offBlock; + public static boolean offFood = defaults.offFood; + public static boolean offUsable = defaults.offUsable; + public static List offWhitelist = defaults.offWhitelist; + public static List offBlacklist = defaults.offBlacklist; + public static void resetDefaults() { + lang = defaults.lang; + keepActive = defaults.keepActive; + sitWhileSeated = defaults.sitWhileSeated; + stairsOn = defaults.stairsOn; + slabsOn = defaults.slabsOn; + carpetsOn = defaults.carpetsOn; + fullBlocksOn = defaults.fullBlocksOn; + customOn = defaults.customOn; + customBlocks = defaults.customBlocks; + mainReq = defaults.mainReq; + mainBlock = defaults.mainBlock; + mainFood = defaults.mainFood; + mainUsable = defaults.mainUsable; + mainWhitelist = defaults.mainWhitelist; + mainBlacklist = defaults.mainBlacklist; + offReq = defaults.offReq; + offBlock = defaults.offBlock; + offFood = defaults.offFood; + offUsable = defaults.offUsable; + offWhitelist = defaults.offWhitelist; + offBlacklist = defaults.offBlacklist; + save(); + } + public static File configFile() { + return new File(FabricLoader.getInstance().getConfigDir().toFile()+"/Sit!.properties"); + } + public static void load() { + if (!configFile().exists() || !configFile().canRead()) { + save(); + load(); + return; + } + try (FileInputStream fileStream = new FileInputStream(configFile())) { + Properties properties = new Properties(); + properties.load(fileStream); + loadVersion(properties,(String) properties.computeIfAbsent("version", a -> defaults.version+"")); + save(); + } catch (Exception f) { + //read fail + f.printStackTrace(); + resetDefaults(); + } + } + public static void loadVersion(Properties properties, String version) { + Type mapType = new TypeToken>() {}.getType(); + lang = (String) properties.computeIfAbsent("lang", a -> defaults.lang+""); + //CONFIG + keepActive = Boolean.parseBoolean((String) properties.computeIfAbsent("keep-active", a -> defaults.keepActive+"")); + sitWhileSeated = Boolean.parseBoolean((String) properties.computeIfAbsent("sit-while-seated", a -> defaults.sitWhileSeated+"")); + stairsOn = Boolean.parseBoolean((String) properties.computeIfAbsent("stairs", a -> defaults.stairsOn+"")); + slabsOn = Boolean.parseBoolean((String) properties.computeIfAbsent("slabs", a -> defaults.slabsOn+"")); + carpetsOn = Boolean.parseBoolean((String) properties.computeIfAbsent("carpets", a -> defaults.carpetsOn+"")); + fullBlocksOn = Boolean.parseBoolean((String) properties.computeIfAbsent("full-blocks", a -> defaults.fullBlocksOn+"")); + customOn = Boolean.parseBoolean((String) properties.computeIfAbsent("custom", a -> defaults.customOn+"")); + customBlocks = new Gson().fromJson((String) + properties.computeIfAbsent("custom-blocks", a -> defaults.customBlocks+""),mapType); + mainReq = MainReq.valueOf((String) properties.computeIfAbsent("main-hand-requirement", a -> defaults.mainReq+"")); + mainBlock = Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-block", a -> defaults.mainBlock+"")); + mainFood = Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-food", a -> defaults.mainFood+"")); + mainUsable = Boolean.parseBoolean((String) properties.computeIfAbsent("main-hand-usable", a -> defaults.mainUsable +"")); + mainWhitelist = new Gson().fromJson((String) + properties.computeIfAbsent("main-hand-whitelist", a -> defaults.mainWhitelist+""),mapType); + mainBlacklist = new Gson().fromJson((String) + properties.computeIfAbsent("main-hand-blacklist", a -> defaults.mainBlacklist+""),mapType); + offReq = OffReq.valueOf((String) properties.computeIfAbsent("off-hand-requirement", a -> defaults.offReq+"")); + offBlock = Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-block", a -> defaults.offBlock+"")); + offFood = Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-food", a -> defaults.offFood+"")); + offUsable = Boolean.parseBoolean((String) properties.computeIfAbsent("off-hand-usable", a -> defaults.offUsable +"")); + offWhitelist = new Gson().fromJson((String) + properties.computeIfAbsent("off-hand-whitelist", a -> defaults.offWhitelist+""),mapType); + offBlacklist = new Gson().fromJson((String) + properties.computeIfAbsent("off-hand-blacklist", a -> defaults.offBlacklist+""),mapType); + } + public static MutableText lang(String key, Object... args) { + LangReader.loadLanguageFile(); + return LangReader.of("config.sit."+key, args).getTxT(); + } + public static void save() { + try (var file = new FileOutputStream(configFile(), false)) { + Gson gson = new GsonBuilder().disableHtmlEscaping().create(); + file.write("# Sit! Config\n".getBytes()); + file.write(("version="+defaults.version).getBytes()); + file.write(("\n# all available languages: en_us").getBytes()); + file.write(("\nlang=" + lang).getBytes()); + file.write(("\n\n# "+lang("general.keep_active.description").getString()).getBytes()); + file.write(("\nkeep-active=" + keepActive).getBytes()); + file.write(("\n# "+lang("general.sit_while_seated.description").getString()).getBytes()); + file.write(("\nsit-while-seated=" + sitWhileSeated).getBytes()); + file.write(("\n# "+lang("general.sittable.description").getString()).getBytes()); + file.write(("\nstairs=" + stairsOn).getBytes()); + file.write(("\nslabs=" + slabsOn).getBytes()); + file.write(("\ncarpets=" + carpetsOn).getBytes()); + file.write(("\nfull-blocks=" + fullBlocksOn).getBytes()); + file.write(("\ncustom=" + customOn).getBytes()); + file.write(("\n# "+lang("general.sittable_blocks.description") + .append("\n# ").append(lang("general.sittable_blocks.description_2")) + .append(lang("general.sittable_blocks.description_3", + lang("general.sittable_blocks.description_3_2"), + lang("general.sittable_blocks.description_3_3"), + lang("general.sittable_blocks.description_3_4"), + lang("general.sittable_blocks.description_3_5"))) + .append("\n# ").append(lang("general.sittable_blocks.description_4")) + .append("\n# ").append(lang("general.sittable_blocks.description_5")) + .append("\n# ").append(lang("general.sittable_blocks.description_6")) + .append("\n# ").append(lang("general.sittable_blocks.description_7")) + .append("\n# ").append(lang("general.sittable_blocks.description_8")).getString()).getBytes()); + file.write(("\ncustom-blocks="+gson.toJson(customBlocks)).getBytes()); + file.write(("\n\n# "+lang("hand.requirements.description") + .append("\n# ").append(lang("hand.requirements.description_2")) + .append("\n# ").append(lang("hand.requirements.description_3")) + .append("\n# ").append(lang("hand.requirements.description_4")).getString()).getBytes()); + file.write(("\nmain-hand-requirement=" + mainReq).getBytes()); + file.write(("\nmain-hand-block=" + mainBlock).getBytes()); + file.write(("\nmain-hand-food=" + mainFood).getBytes()); + file.write(("\nmain-hand-usable=" + mainUsable).getBytes()); + file.write(("\nmain-hand-whitelist="+gson.toJson(mainWhitelist)).getBytes()); + file.write(("\nmain-hand-blacklist="+gson.toJson(mainBlacklist)).getBytes()); + file.write(("\noff-hand-requirement=" + offReq).getBytes()); + file.write(("\noff-hand-block=" + offBlock).getBytes()); + file.write(("\noff-hand-food=" + offFood).getBytes()); + file.write(("\noff-hand-usable=" + offUsable).getBytes()); + file.write(("\noff-hand-whitelist="+gson.toJson(offWhitelist)).getBytes()); + file.write(("\noff-hand-blacklist="+gson.toJson(offBlacklist)).getBytes()); + } catch (Exception e) { + e.printStackTrace(); + } + } + public static class defaults { + public static String version = "v1.0"; + public static String lang = "en_us"; + public static boolean keepActive = true; + public static boolean sitWhileSeated = true; + public static boolean stairsOn = true; + public static boolean slabsOn = true; + public static boolean carpetsOn = true; + public static boolean fullBlocksOn = false; + public static boolean customOn = false; + public static List customBlocks = List.of("minecraft:campfire|.46|.5|lit=false","minecraft:soul_campfire|.46|.5|lit=false"); + public static MainReq mainReq = MainReq.empty; + public static boolean mainBlock = false; + public static boolean mainFood = false; + public static boolean mainUsable = false; + public static List mainWhitelist = new ArrayList<>(); + public static List mainBlacklist = new ArrayList<>(); + public static OffReq offReq = OffReq.restrictive; + public static boolean offBlock = true; + public static boolean offFood = false; + public static boolean offUsable = true; + public static List offWhitelist = List.of("minecraft:torch","minecraft:soul_torch"); + public static List offBlacklist = new ArrayList<>(); + } +} diff --git a/src/main/resources/assets/sit/icon.png b/src/main/resources/assets/sit/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3ba951af86309146de4c36369bc0bf55ede3cb44 GIT binary patch literal 9842 zcmeAS@N?(olHy`uVBq!ia0y~yU}ykg4mJh`hQoG=rx_R+SkfJR9T^xl_H+M9WMyFB z^2~I04k!+CcT(_lbv84!G&9pR(lcaW@aUWyTpls`yO`bm@2UJ@PB%VmoSxIjprpKp z5g3;QQe_27VqTmEZE^&+aCwHf48eXFci*mn7Q`A;^x1FiFsw~g8H7HW^ppi z`~F<{-|^P^zkQk)ADL{7(Gl(X7}2>SK*{%b<<6jqE{Z3oJ`#FaZ}d@q+F#De<-81Q z+WZgrZDZehI_E&$J4U8%zKBa@3=Valb$g_^Co%}6n;2DoXJDAT|7X90HY3B?=}R6n zFzk6D5wl{7xX&>T1_qY}janNV*?A6%tU16p=b-GK1L91HY%UHwDhF%?oY!6BTeXw@N@ z)OSPa9EbSKJ{F}!50gm^OB7yqhy*GfJyEoTX{A%v#8?mIPr5}Smc20!zb4#1po-l7jW910l|C>p@jZtMQ+I>#8;-aZfkQb> z6DGJv_(V9bP<^AkMQ9gCIA?Q<;URUU$t(P~s8$L6JW`QlwQ)j(+ZwfZigJqcRO8h7 zgyScBsPLVf^u&)#QFVfmC%0#|$88VYCBaMVE(v7L@lks{A@}6HCmfp^)+kJ$xP1cu z1pi6DPab}avsBN{7IQwmM0fGk3$rrQGrwo(zbx6sdAC{4b^3+rm$F~5zkL3(`Aazu zZyRs(agQVo$!y7L$>kE;CG}_eEMvVqeddV}gX>1pGt+1A&&Usr(E6rTBRcVv&{V6b zVN>g-K3^3QS{!PBwQ?1A$m&r3)p239%iKaY2RvTMc|~mX)s?cLyH}d6I~P~`y#1JDucFv7qtuTPPS=XUm|yE;&+tu(-t_a0PZ{fP z=`#IlpJ3@Fw2u6)V)_0(6s zmv=9^f6e`}_^bG<_t)NEls7jp;V_#ZnPX^?{Nc=mfZC&a*=cre=S@-d2x2DycW}W6c?faS;VRm7a zVPC_pukpMV^IGS1?zQlo0O|1AJhQE4pWe1&?d-Kj%4X-@7kMPouX#!HYjEBz!#984 zaJ`xJhV8B8x5RI%-*Ug5mpvmRBzw)e#JZ-ar1VT#PQjknOCFjWUU_8Y;g{j*(&-C} z=YBR7U*Egk;%e$86&96E=^{LdmU6;0A{%mk1LCdjQhP;&VTb9wRzVJa!=eo68&KB z>FNY4JKNM>=Uy_~9kXMaUp2pd-?Dv5_igtn*IlcdS;zio-f!z)r~mf<*#EHdlh{W; z)&$0bj87T&HcB;aX3l1oXPL>el--oImvuLrK98NK6AveEq0btC)O_Tw3HG&}=eRFWm%r?%&&xC0I65A<=XC6l&y<`g{x24W6?T8 zX!<7mr_BmZ0s0dDPnYNU$_jsKnceE|x^GeMqQH&YcX-)MdNwy~>NktK*0s*RGTQvz zN{<8%twEPc15&Abj1#jy&h3ljPIxYd-YS9 zyGg8O?}QBjJ2q^-v7;jL;{&DruDivQyMx8c^$cT!cBNEgez;V7I^*=FX@3JAMFfR@ z%BsBcsV}Jc($b~Q+D+jmQ&&zoc{*?1m#Ce|qKQ*eLf>aizZxA@uO&V;eoeue73+R% zaNF_hQMh0H)taxBxwmfJ^V)vu?Q4(MOJ3)#`5w7{z1Q9>$Ez3GKJc!U{@D9eIzHFy zUdh6$tgn4%x12q7mf1AX^lkK+ZEJ3ST4=WTTh-k9*wbNu*RI~a@21+VYy0n(SAXVf zmKC+W_kPNoJzKRa!n60f)_%>q^seb{zf_X+uKmyI?(T3e_dhzXzj|pk`#0D3ud_<> zbMCC)zkd^FZjf28oQGAx)7cIAw`RYcRlc<#N{jE1u+x+y1}qz2W2J(&MK6;qw;E)v*2e z^GVa>$IDZe&ztLKZ+m6toyzY%e`aRK2FC79cRoMQUcBU;&-VE5CqLhN-XHs6Pr(piR z;r!u9{`Y*G?eqRk`G2|n;U)Jo?pKxFlzaQ<%F9dhO6~oWa&Gd&<(rlZpFdR>_P_FV z@#^RI|33QdeLmvPjSt*EyU*`mSGn?Y(fida*IOM|J}$rKT&3;DWq;P5yIuQ!$NOFP zkMEVAsqx3*U%=;!zmktHzu^Df?s?6>KlZzhz@U)q5#-CjP^HGe(9pub z@C(!keZjy`YQVtoDuIE)Y6b&?c)^@qfi?^b44efXk;M!Qa)&^eG4DdD9Rq{(WKS2z zkcv5PV>5eXj+g#hwLJZs!pk16D=A94>V11>C8FY zDJ$Js&%*Xd+e_evqtF3MMrJ#P!<(M`o{;O=r!2owBzBo@{1wL_rJZ}GR~NMxe+ir_ z9~=62)vl_twB_mLD{gLoF?Zg(dGB8Ry7&9u>hP;q-`x8ckPyliwr8r|fmLhPtkF8q zaC#LJ&khiyTYrNTGvB5)Mh61@L-+e|+iPD?v3rY2qSD>`_`2WP&2Z_;{V?lJA@*p&X}-PvC8iA)?<-1Hmc z%{zJbizR=5-;;Pfzvr;_(gx0n^}9tXe(#Rj|D{Isd`&S|aDU~2i@Fl)`o(MbPiu#7 zWhxL`yzQZmSM{?EKd(!E+gm3S{k`|)-?aypB{AR6+8-4@e|eov^Wyunj=p(l^k?$z zfXqJ2^B30_g=#t^XNW!A)-7Rs;lNh&-Un^h^N!8>xNuwJvP}{%*7lWZwmh#Ckg@o9 zM5M2_ns0M^ZH4-_q!l~&J>I0de8c%KE15Ws1x8mhR@^i(+Z&Yd|9$SEZ_TfF7wv!B za8FPAg8!~5UaA%I*pEpZa%(yN_nGPx_3b))FW64om&tZ4uH)CS%`4u_KmIK|bi;q% z*&7povoT12F`WD3z0!Amwq4IFKkQLis$}6V($?`lI=iq~aNF=W%% zNM8DChiv4sj|@y(FKTwo^(?9Tn|=N9ui4uUd@fJxk6AQTKQ&(NgC2MIdr8XKy?7xtt+mzb2c=#i|Fq0WP&wd)w}_Oah6IpJ=cu^>k8wc3PLHeWdvKF?I&Huc%t z_&4Qi8I~W67GRMoQGc-N%#};BQ`TP#eaX_WK#X}$OPyTtMN{UOKdHv;5{^4UvN=M=YWialp(?$~~KzIyA)fZc&M z+<$CVo^7qY%f!Hy(D32R3Pz2|Ve7T-eXpHzI(5qFrz){t5ssRDvidhJaXxV3*go|z z<2KeU!IEp2#j+JVyT-`&;FQmWFxhoWO6=7Niq5PFNnN;P(_;-M0hTC14eckay zG7W-zIL{r_JRtUi;p5Ab;^u32@7t~NoPkkchs^h_|Jk_`8WtXNGg(!LV9_pwIbr@3svOY#93u3mBRVD{g5`PSD|Ck~Nv;wbuRag|t~=V(nAYmC7TR z^{w5*`svWdW&4HZ%ZF5+u71U?sUmDqy{S>Q{hGD*Wafl9>RksW&4}P&>*s714Y}aa z`m6YrR*v?0ZjIpSN*Tg);}#sYKFc(Zmn~SAWA&QzvJQ?j51bYjY}jHnNy|WcuJTGT zwV93v(|A195(>{5+RRb$J7mDppImS-bzQ8cL-qyhPmeF1x_j*1ja!PddVj9iEWf7V zN5b9L8DDkIU+JCDc0k18SsVk;9Oq@e!Ve31F-*iVLy<)*$=t??bDaIQ|qLn}AM`D;5lOt6{3)02AC@Pcep zae<^t(Yb>urw?p>F?pfI>O58Ny==@EVjf6nZZfc);53it)2dI7ToaSarmXs^7H&N^ zeML;9trhG3+dMI+Bb+2|7k6LKdH(LTxMqq=z{^us4l@}09UlE>WjOI7{&K@I=E^mF zZ*=4R4lLWSJ@gS@{^_SYMY1gh{F_Q0>Usa1;8VTe!p97^Y|c#!Qx&vipC}>laO%6)+pc>X^0#xfc^_Zx8M~svgE@~i zFRa-2Mee7JRSY`vAC69SkYIl*cfZg3q|18C>&iT;3{w^@boJhO>5*#h=XcY0UQWAZ z%zA&z4<2rZ$o(f7*6wP$yed!iOvzPUzSD6E)mwsDi+0)z>aP+B+P*i2YqmntzYybS zb|wL>2h)9>l*I}<-ZEKzI_o`gj&SE5=1==>-L`D!IQ8QDxdn%wv9E|#Xz=nXkE~1E zy{JA>*GuA(!lvL%bG{7Kw-3_U*KM+V{rzWw!2$=?jF<__FWJdGE8iJ7;q4azYl}pw z5^gKD>(^v5&;N4i&fn=C^-kwyrjNTA>sJoB{amveT?MDikZ0v>Vz|j;V$|p(wREP6 zmw(b$rkK1#O6}L4#y4%=P%Cj)<&AF8LQgwp1_|*M@qCOAzwTt#_;hl?Pr=nqGycr? zc=atap&@6rLs**i`H!XXMc*YqCDk=wDXFw%QBUS|x%6v?O|15kmc7#s#W*b8$=D?P zYxzuTZRd>RY-!9|(i}`D3jPJ1xVv??>R;i@+mFkyu;Y>|J~BtSFX?XS*#jF&ud|t~ zx8^+ftJa6vEb_Gk`IzA zrFm32cS)`HXkYx^#-wlVf4e@5Cl!C@J+64D%`|oL?gyR!UTEr+%-S(in0Kcd5BDbH z#+zMg_hlOwtYnE4%h1d^78UZGRI9d3izn4y64r} z-G$HpRu{ZxHeIvxt>hK+`FWcg_D*(^=Zm#a{wv!%Z40-6(ZA$Kw}AUk`zI?Hyw_q~ z(m2O!M)KQ~Cq|!brqsyKdoC%K-yc&JZ>0Nq+1%G3j_tqAe@vp!wu-Uc-mv?{N?8r| z*SmJFSM^wE6Jnch%ItWHxoPL-rcdHdWviFkHl^4v{M&crsg}&XyKM7>A2dEuyfle* z7jI3_8L^kyp<Z^}-16%zr*9MhLm)Wge zV!@3uABr>X#Y|#cKINJ1dFPwod096!vPUtmI-MqadDm*|yZav>>)r8ozgg39CjXj$ zDt)z@PA`9y+Md)AvvTf;k7mEM$UK%ID0M-X!z8y^jAEzRgsyB3o#ktO`@rjV&nv+$ z4#zINO!0pkvD@27Hab_UrARog^Wih=vd7P?8(v-xwfS{Yc*mE&rV{gR_32fa^Jto| zeR!SRarksm(y=w%443{a5R_ICWMEiQC#kDtHT`|-LKn>+p4<9HYP z$CWO1Mh7go9U1Vo_VT&Xip%ygEzc`0z8zt;`T5bCqkfBU+~VDV?XCOt8w%w&KhL_c zBRM25u$Iy2v;Sj8YcqyRYK#Bms8;T?4P=_ga8GH)XYq~SlyvT?R_Z(mGK=D~^1s-4 z|5jss<=4`RKc|m>{Jj6&y5k!^}@4de*(^$5M@!y>snER-ckSZYcHDDy!J{dA{{TISmKl9g^=jzr{7rH#4cIuV0qq&7>jxAY0-@Xhcw&rK5EZl%o1l*`1-(7KL^M=A}?%NOhafdfltV=SvIAe9tn>!6G z@f>MCN<>93JNVgZ&f$FZN2Fx-v&r7imS$KId3vD0^Mc$c7hQN}Zjqw&k1v=_%^cn&69vgY_vD5Kn!d?b+N>eL+bhqpLi ziE;0`v`9ZzG3KmgRj*C=^Er!e<}CAf)86)2rs_cFnw1OW7KKPVZ~q}`7rr6fUryLN znW5VCmu{$}Nu|yV#$Css=*(Ru?stMuQoBoks+XTUmx%klq)UY1!)4k!h?r9H`?xl(G%CtLlQnMXc9n11@x_M4eEcW3T? z&iQu3%V*!WoSE|MYD=V}fC5L8iKA=d^)31<{yH=ye)`GEaCiUOB_DP+d0*66cP8f8 zi#9G!mdUlZI4`)_omsY!@5dvFxTQ@GCr)e;TDpJx+T9)(VlQStdwU&U`b`t6|EajIQG+L^&3!PYcpKZ_#C7W7Ooe zbW!uNqaq7eEQ{67WdEVTBN$;kb=iX1pXE{=%8eY749;rGyO!{McVTQ=Y2^7@F_g(# zE@WdPv$~#zfOEK$PP%Y#&V@duFHW4Fl&W4mZanhnuz`zCw0`6V(FdC)Azl!5h%fy3goV5Ad8LqrgP`n^=a!aAJv$KShlu^-> zvikZ@lXI@W3R)WbV6ldi1dCN$q5IeF=smL;Rem@fSiRO&@W$7)oKH=sSUtoUE?r-{ zsqRTZ*Zz6-9=o{s7;N6g2QX-x1qcTPn=#yJOj_Ra;MA?BLA4@F#pVlNE$6aYYaf;P z^(RB!j%{y$XQB2>y=w!eCw z(vDe0C3o58?JGX8p~Cc52TR#WQ%|@2Kvj>^p3&#T=f^VyoZ)yhZ;$bb{59Y;ZLCzhTYHC5uuvtT^_3b(vWx)7_0JN7+3EZ+YLmb)fj1 z@Pox3{gx;C-9=uw{JfpWaGG_+{Bv`%M6Q*+KAHX4E0A^i@>deK=kSGJ+Q^{ewOH5b z;R~~Cjsgr5ZJLfgWc1m|$|%V7*NEfmgf=gJ?GK?b3;a_xo3wXMVXu*B+tq%q&e|)l z;QGX;ug#`x^qrdh&Zl8f!Rw2kJ$WvxzmC}6>9R_TV~Wm#&CO1xxlih9Yaa2jBnNSZ z1Wy7A(9LWs@Cmb_p5%y#E|eTM0j_cqpt2sc2V{f4AUg)i{@A{CNg|YUg)nuq=UG+E4qTX_CHl=L{`|avJw^Ba z%zHHB7-L%5g$P3lhrc&wG(>&XIH_KI)#pi@(uXIe>qH-ky;-(spAnBm-mdv)WN>Mz}m#Zm>52gOYVRr%N$Bm;F;ANkQ+ z<#T%_hmqZaFL}oqy$%`p-20#XyZn-M`j7JETc2yPFotToiq%YboB8%cU8i<-fJmNg zG2_D?)A|htvm1AwHEdd$#&98I(}hCD6Lnvu@1|@KW#pXjidED>?1x2{z@_iPTNYG_ z-c8q;y)Iqi0Mp$Kf3E2)ICc85#G6yM4xQPS{+{m{cP7J%-}MY{zpPZ^P~1}A+%Qqn zRUDS+w)H462q;PViX7iqr|-BaR)L54@3esD*%_bK*yZ0n$*}U!W&g>n zo4h7=9r&}9&8x=d_R?K0FK;TZSh};&D9`pXiL?39HPTq_4N1V7$Lj z=13?9>yi!IR)3DvS)jL+*Og(CQsKvpwGnf=E-bRqJfCy;{QdpR{&$MoOg7JvO!(xg ztHizK@5?0S*`geqCB$;|m*k#5x$~>(f`%!rCZ{Ie>*!_-Qg~Un{e1Y-uu#S&8&7fD z&pdKux>*UAv-iuNIxI^wSd8b}w*0N*jvQucRUzS}vuxOBo^BsBhA zxz61&EM9zJeKTXxL2|F8T zt)Sokq+1@lZcLgatjau*(f+ZNh6Z0Zi-tm9t6aa%hRUw=c=h+e^6ELK&DW(}lS;Pu z_r$g4<+sR|`+q|#_N=&8uVpJKG);Z#&9^^Z{+6=%`1^RlY3s6vsWUwPGkC0BcH86I zhPi1A4do}^;b(ji$+6|ApnT2_;ZPR#6UTO4cyq5$=tX>B+Q~avNg`KwTFL!7&fQVB zh2MG6jEC`hk!oxnOGWq>SKU{vc`JK)#{4zX8ykg`C6jebN#1;^UEhkm$3!}S?*=OU!BhCF2D0Z z8M_qc`*aiJ5W3|e9Lj}>_&uJ3tSwsOwR=J)%GCEWLw%gsA(bW)ii?dfg3 z#ynvbn~7Q0GQS-y&xo6O(mTP^+`DXzF%U4B46nsLIWqJ>t|g4j;vI8S3_N#x*C2^FZ8ExCJ?;g#|9 zcTcT0{tC9Ae~8~M=;()^(i<=7PmA8DVBjzD{o;>*y+2MxKP!Crb7#)AfO;#5hP>d{ zYb6}A*-AOPH#o{MKe@2i>zRQ;%UOZ%cS}Y3_od4me*Rr7G&Qz!dYFH`?$ndhA3fY3 z)qi|{!6}*c^2?~zqfDH=rQ(noy_aQw!yJHcXMXkLx0=K zs=Dpc9$WqDJnpX&F}z=>3hjn#bod z_dNP5UU1m=wofsu&;f}r#_XP-1%(2tld@WOp5+Ufm=M!E@xQ|&266v$4{z67w_f6| zez^Ge&)?I$f5p2NA6eh`SY7^BSG!%=9D~L?p2@Cr-#8xI)LPmjDKBvPJmch(amVui zKi^#OVQuP^xEsl_d;ULN70STy;gOFe>WdYc=jPU ze8IuxKfF(Ux8Ywtf9A2}`STB45&w3W|GLigTyd@NtxOu4vbWoRzsq@a;&A%hW}ht) zoeEsr9zJjF-ElKeb;ki_`C762zq8Em4YeG^(j&Vb%_>t4uN3A}ch_v~pZ>Sag`@zf4@q0flN?=g!`5jSFVE^vl zWzI8mVheULzj~j`R*T~)1oTBG)|bi|V&yWP_Ke`dDJ z*M3eZ>uJ2y#&cD8A%B-q+wy(IT;K1Rb-y_N`(QxS$KTpTJF|ow=X$NQYg;TI+uf-? z@9^w*x0v@Yl55(O#IlNoXO_N1!>btH_}>ROkJ#UCKNWgmS$x-q{x`FB?3x=PEtG57 zYyRhQRL=f?stn9F(|lf;*cdT6DDXJhy07mN{P({5{NoeHuP+RGUuSi#PVC#n*yV9w zxEL5dUSL{Re_M6Wum10cCZF9gapDu#>xmLC%K3ce%{pvuSHX5~$#3%pwAun^Z_5AytS;AJ{QyU8zw-xMfyj$+KsLt}p&h>HKK{02}%nqOZ z#?;{Rf@c}e4DJZg=&(OK8$u%^BU7OhRgyOp3POe8T<`?e)wBl< rr?Uhs9&CEW#1<1KnsDIhf5zLYTGj`B?Q|I!7#KWV{an^LB{Ts5EEI1Z literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/sit/lang/en_us.json b/src/main/resources/assets/sit/lang/en_us.json new file mode 100644 index 0000000..cf40690 --- /dev/null +++ b/src/main/resources/assets/sit/lang/en_us.json @@ -0,0 +1,55 @@ +{ + "config.sit.empty": "Empty", + "config.sit.restrictive": "Restrictive", + "config.sit.none": "None", + "config.sit.category.general": "General", + "config.sit.category.general.tooltip": "General settings", + "config.sit.category.main_hand": "Main Hand", + "config.sit.category.main_hand.tooltip": "Main hand settings", + "config.sit.category.off_hand": "Off Hand", + "config.sit.category.off_hand.tooltip": "Off hand settings", + "config.sit.general.keep_active": "Keep Active", + "config.sit.general.keep_active.description": "Keeps the entities active even when logging off / shutting down", + "config.sit.general.sittable": "Sittable Blocks", + "config.sit.general.sittable.description": "Toggle the ability to sit on different block types.", + "config.sit.general.sit_while_seated": "Sit While Seated", + "config.sit.general.sit_while_seated.description": "Toggle the ability to sit on other blocks while already being seated on one.", + "config.sit.general.sittable.stairs": "Stairs", + "config.sit.general.sittable.slabs": "Slabs", + "config.sit.general.sittable.carpets": "Carpets", + "config.sit.general.sittable.full_blocks": "Full Blocks", + "config.sit.general.sittable.custom": "Custom", + "config.sit.general.sittable.custom.description": "Enables adding custom blocks to sit on.", + "config.sit.general.sittable_blocks": "Custom Sittable Blocks", + "config.sit.general.sittable_blocks.description": "Add custom sittable blocks!", + "config.sit.general.sittable_blocks.description_2": "Example: ", + "config.sit.general.sittable_blocks.description_3": "\"%s|%s|%s|%s\"", + "config.sit.general.sittable_blocks.description_3_2": "minecraft:campfire", + "config.sit.general.sittable_blocks.description_3_3": ".255", + "config.sit.general.sittable_blocks.description_3_4": "1", + "config.sit.general.sittable_blocks.description_3_5": "lit=false", + "config.sit.general.sittable_blocks.description_4": "First entry: custom block", + "config.sit.general.sittable_blocks.description_5": "Second entry: sitting height (number from 0-1 eg 0.52)", + "config.sit.general.sittable_blocks.description_6": "Third entry: hitbox size (where the player spawns above the entity when dismounting)", + "config.sit.general.sittable_blocks.description_7": "Fourth entry (optional): required blockstate to sit (Put a \"!\" to exclude blockstates)", + "config.sit.general.sittable_blocks.description_8": "Separate different entries with \"|\"!", + "config.sit.hand.requirements": "Requirements", + "config.sit.hand.requirements.description": "Hand requirements for sitting.", + "config.sit.hand.requirements.description_2": "Empty = hand has to be empty", + "config.sit.hand.requirements.description_3": "Restrictive = set restrictions for hand state", + "config.sit.hand.requirements.description_4": "None = can sit whenever", + "config.sit.hand.restrictions": "Restrictions", + "config.sit.hand.restrictions.description": "Toggle preset hand restrictions for sitting.", + "config.sit.hand.restrictions.blocks": "Blocks", + "config.sit.hand.restrictions.food": "Food", + "config.sit.hand.restrictions.usable": "Usable", + "config.sit.hand.restrictions.usable.description": "eg. bows, tridents, shield", + "config.sit.hand.whitelist": "Whitelist", + "config.sit.hand.whitelist.description": "Make a custom whitelist for items that the player can use to sit with.", + "config.sit.hand.blacklist": "Blacklist", + "config.sit.hand.blacklist.description": "Make a custom blacklist for items that the player can't use to sit with.", + "config.sit.hand.list.description": "Example: ", + "config.sit.hand.list.description_2": "\"minecraft:torch\"", + "key.sit.command.reloaded": "Reloaded the config!", + "key.sit.command.purged": "Purged all active chair entities!" +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..8314b1e --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,41 @@ +{ + "schemaVersion": 1, + "id": "sit", + "version": "${version}", + "name": "Sit!", + "description": "Adds sitting to minecraft! Endless customizability for hand restrictions and sittable blocks.", + "authors": [ + "Oth3r" + ], + "contact": { + "homepage": "https://modrinth.com/mod/sit!", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + "license": "CC0-1.0", + "icon": "assets/sit/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "one.oth3r.sit.Sit" + ], + "server": [ + "one.oth3r.sit.SitServer" + ], + "modmenu": [ + "one.oth3r.sit.ModMenu" + ] + }, + "mixins": [ + "sit.mixins.json" + ], + "depends": { + "fabricloader": ">=0.14.21", + "minecraft": "~1.20.1", + "java": ">=17", + "fabric-api": "*" + }, + "suggests": { + "yet-another-config-lib": "*", + "modmenu": "*" + } +} \ No newline at end of file diff --git a/src/main/resources/sit.mixins.json b/src/main/resources/sit.mixins.json new file mode 100644 index 0000000..29b78c8 --- /dev/null +++ b/src/main/resources/sit.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "one.oth3r.sit.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file