diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4bf2007 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# macos + +*.DS_Store + +# fabric + +run/ +trash/ diff --git a/COPYING.md b/COPYING.md new file mode 100644 index 0000000..c8ea309 --- /dev/null +++ b/COPYING.md @@ -0,0 +1,15 @@ + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + Version 2, December 2004 + +Copyright (C) 2004 Sam Hocevar + +Everyone is permitted to copy and distribute verbatim or modified +copies of this license document, and changing it is allowed as long +as the name is changed. + + DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. You just DO WHAT THE FUCK YOU WANT TO. + +yog addendum 1: p.s.: warranty null when void \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..c60f0c1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,87 @@ +Minecraft Mod Public License Japanese Transration (MMPL_J) + +Version 1.0.1 + + +(A.序文) + +一条 [MMPL_J] + 本ライセンスは、"Minecraft Mod Public License"(以下MMPL) (原文:http://tsoft-web.com/nokiyen/minecraft/modding/MMPL)の日本語訳及びその拡張であり、"Minecraft Mod Public License Japanese Transration"(以下MMPL_J)と呼称する。 + +二条 [構成と効力] + MMPL_JはA.序文、B.翻訳からなる。MMPL_Jをライセンスとして使用する場合、特に表示のない限りA及びBの両方がライセンスとして効力を持つ。 + +三条 [Bの効力] + B.翻訳は、MMPLの翻訳部分であり、MMPLと同等の意味内容を持つ。B.翻訳のいかなる翻訳間違えも無効となり、MMPLの該当部分が代わりに適用される。 + +四条 [版] + B.翻訳はMMPL Version1.0.1の翻訳である。 + + +(B.翻訳) + +0. 定義 +-------- + +Minecraft: Mojang ABがライセンスを持つMinecraftというゲームの複製を指す。 + +利用者: 以下のいずれかの方法で当該ソフトウェアに関わるすべての者。 +- プレイする +- デコンパイルする +- リコンパイルまたコンパイルする +- 改変する +- 配布する + +Mod: ゲーム拡張のためのコードであり、本ライセンスでは、ソース形式またはバイナリ形式の、それ単体で入手されるもの、より大きな配布の一部分、またはオリジナルのソースもしくは改変されたソースをコンパイルしたものを示す。 + +依存: 当該modが正しく機能するために必要とされるコード。これは、当該コードをコンパイルするのに必要な依存、及び当該modが機能するために明示的または暗黙に必要とされるすべてのファイルまたは改変を含む。 + + +1. 範囲 +-------- + +本ライセンスは当該modのすべての利用者に適用される。前提条件として、利用者は法的に正しく取得されたMinecraftの複製を所持していなければならない。 + + +2. 責任 +-------- + +当該modは、暗黙にせよそうでないにせよ、"現状のもの"が保証なしに提供される。当該modの権利所有者は当該modの利用により受けたいかなる損害に対しても責任を持たない。当該modはMinecraftというゲームの根本的な部分を変えるものであり、Minecraftの一部分が当該modが導入されたことにより機能しない場合がある。当該modの利用や誤用により引き起こされるすべての損害は、利用者が負うこととなる。 + + +3. プレイする権利 +-------- + +利用者は、制限なしに、当該modをクライアントまたはサーバに導入し、プレイすることができる。 + + +4. 改変する権利 +-------- + +利用者は、当該modのソースコードをデコンパイルする、デコンパイルされたまたはオリジナルのソースコードを見る、及びそれを改変する権利を持つ。 + + +5. 引用する権利 +-------- + +利用者は、当該modのコードを引用する、すなわち、当該modのクラスまたはインターフェースを継承またはインスタンス化する、当該modのオブジェクトを参照する、及び当該modの関数をコールする権利を持つ。こうしたコードは"引用"コードとして知られ、当該modと異なるライセンスの元で保障されうる。 + + +6. オリジナルないし改変された著作権物の配布 +-------- + +当該mod全体が、様々な形式において、配布に関する権利に従う。様々な形式とは以下を含む。 +- オリジナルの、バイナリまたはソース形式の当該modファイル +- これらのバイナリまたはソースファイルを改変したもの、及びソースを改変することにより得られたバイナリ +- 当該modのソースまたはバイナリファイルへのパッチ +- 当該modのバイナリまたはソースファイルの一部の複製 + +利用者は、当該modの一部分または全体を再配布する、もしくは配布物に含めて再配布することができる。 + +バイナリファイルを配布する場合は、利用者は当該modのソースまたは改変したソース全体を入手する手段を無償で提供しなければならない。 + +当該modの配布物のライセンスは、すべてMMPLのままでなければならない。 + +当該modが他のModやクラスに持つ依存はすべて、現行版のMMPLに相当する条件のもとでライセンスが適用されなければならない。ただし、MinecraftのコードとModを読みこむフレームワーク(ModLoader、ModLoaderMP, Bukkitなど)についてはこの限りでない。 + +バイナリ及びソースを改変したもの、並びに当該modを複製して得られた部分を含むファイルは、本ライセンスの条項の元で配布されなければならない。 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..e5207e0 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# Sips +A Minecraft Mod that adds small fluid containers you can drink from! +
+[**CF project**]() / [**Demo Website**]() +

+ +
+POOP badge +

diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..b70ec93 --- /dev/null +++ b/build.gradle @@ -0,0 +1,105 @@ +plugins { + id 'fabric-loom' version '0.5-SNAPSHOT' + id 'maven-publish' + id 'org.jetbrains.gradle.plugin.idea-ext' version '0.7' +} + +sourceCompatibility = JavaVersion.VERSION_1_8 +targetCompatibility = JavaVersion.VERSION_1_8 + +archivesBaseName = project.archives_base_name +version = project.mod_version+"+"+project.minecraft_version +group = project.maven_group + +repositories { + mavenLocal() + maven { url = "https://jitpack.io" } + maven { + name = "BuildCraft" + url = "https://mod-buildcraft.com/maven" + } + maven { url = 'https://maven.dblsaiko.net' } + + flatDir { + dirs "libs" + } +} + +dependencies { + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + implementation 'org.jetbrains:annotations:15.0' + compileOnly "com.google.code.findbugs:jsr305:3.0.2" + + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation "io.github.prospector:modmenu:${project.mod_menu_version}" + modImplementation ("me.shedaniel:RoughlyEnoughItems:${project.rei_version}") { exclude(module: "ModMenu") } + modImplementation "alexiil.mc.lib:libblockattributes-all:${project.lba_version}" + modImplementation "alexiil.mc.mod:simplepipes-all:0.4.3" + modRuntime 'net.dblsaiko:winwonders:0.1.2-4' +} + +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +tasks.withType(JavaCompile).configureEach { + // 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 + // If Javadoc is generated, this must be specified in that task too. + it.options.encoding = "UTF-8" + + // The Minecraft launcher currently installs Java 8 for users, so your mod probably wants to target Java 8 too + // JDK 9 introduced a new way of specifying this that will make sure no newer classes or methods are used. + // We'll use that if it's available, but otherwise we'll use the older option. + def targetVersion = 8 + if (JavaVersion.current().isJava9Compatible()) { + it.options.release = targetVersion + } +} + +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() +} + +jar { + from "LICENSE.md" +} + +idea.project.settings { + delegateActions { + delegateBuildRunToGradle = false + testRunner = org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM + } +} + +// 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 + // To publish to maven local, no extra repositories are necessary. Just use the task `publishToMavenLocal`. + repositories { + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + } +} diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..009e05f --- /dev/null +++ b/docs/index.html @@ -0,0 +1,54 @@ + + + + + Sips + + + + + +

Sips

+
+
+Yoghurt4C: This mod adds 2 items: Lil Sip and Big Chug, which are functionally identical, with the only difference being the amount of Fluid they can hold.

+Creative Tab +


+ +Yoghurt4C: Let's use a Lil Sip as an example. To fill it, grab it in your main hand and click on any fluid block.

+Filling from block +


+ +Yoghurt4C: You can also empty and fill Sips to/from any Lib Block Attributes-compatible containers, such as Simple Pipes tanks.

+Filling from container +


+ +Yoghurt4C: Once you have a fluid inside your Lil Sip, you can take a Sip from it! If your beverage of choice has a Sippable associated with it, you should receive a new effect!

+Taking Sips +


+ +Yoghurt4C: Sips also adds some "new" fluids to the game, like Milk and Mushroom Stew. You can get them from their respective Cow, or shift click a Milk Bucket or a bowl of Mushroom Stew in the world, or on an LBA fluid container!
Of course, their default Sippables are virtually identical to those items.

+ +


+ +Yoghurt4C: You may be wondering: "What are Sippables? How do I add my own effects to a fluid?". Sippables are collections of various data applied to the player on each Sip, and they're also entirely data-driven! Define your own Sip effects for fluids in JSON!
Sips also has builtin compatibility for some modded fluids, from mods such as TechReborn, Astromine and Modern Industrialization!

+JSON +


+ +Yoghurt4C: Sips also has a config, which lets you change some of the things about the mod. For example, you can increase the maximum amount of Sips that Lil Sip and Big Chug can hold, or turn off "fancy" 3D Sip rendering for that classic look!
Or, if you're a modpack maker, you can prevent the default Sippables from loading!

+Config +


+ +Yoghurt4C: If you have REI installed, you will be able to view details about every drinkable fluid in the game in this beverage list designed to catch your attention! You will be gripped by the legally distinct complimentary slogans!
Yes, you can also fill Sips with potions! (Currently LBA-exclusive.)

+REI +


+ +Yoghurt4C: Seeing this image means you've reached the end of this small showcase. Good job. So, get merry and have a Sip!

+Sendoff +
+ + + \ No newline at end of file diff --git a/docs/sips/icon.png b/docs/sips/icon.png new file mode 100644 index 0000000..aa42fe3 Binary files /dev/null and b/docs/sips/icon.png differ diff --git a/docs/sips/sip.png b/docs/sips/sip.png new file mode 100644 index 0000000..b14de3a Binary files /dev/null and b/docs/sips/sip.png differ diff --git a/docs/sips/sips.css b/docs/sips/sips.css new file mode 100644 index 0000000..ec5ae83 --- /dev/null +++ b/docs/sips/sips.css @@ -0,0 +1,13 @@ +img { height: auto; max-width: 90%; } + +body { text-align: center; background-color: #36393E; color: #DCDDDE; } + +.code { background-color: #2F3136; font: monospace; } + +.spoiler { color: black; background-color: black; } + +strong { color: white; } + +.spoiler:hover { background-color: #36393E; color: #DCDDDE; } + +hr { background: url(sipsborder.png); border: none; height: 32px; } \ No newline at end of file diff --git a/docs/sips/sips_1.png b/docs/sips/sips_1.png new file mode 100644 index 0000000..e2dc932 Binary files /dev/null and b/docs/sips/sips_1.png differ diff --git a/docs/sips/sips_2.gif b/docs/sips/sips_2.gif new file mode 100644 index 0000000..20f323f Binary files /dev/null and b/docs/sips/sips_2.gif differ diff --git a/docs/sips/sips_3.gif b/docs/sips/sips_3.gif new file mode 100644 index 0000000..a24c430 Binary files /dev/null and b/docs/sips/sips_3.gif differ diff --git a/docs/sips/sips_4.gif b/docs/sips/sips_4.gif new file mode 100644 index 0000000..4bf79a5 Binary files /dev/null and b/docs/sips/sips_4.gif differ diff --git a/docs/sips/sips_5.webm b/docs/sips/sips_5.webm new file mode 100644 index 0000000..70440f0 Binary files /dev/null and b/docs/sips/sips_5.webm differ diff --git a/docs/sips/sips_6.png b/docs/sips/sips_6.png new file mode 100644 index 0000000..366a6b3 Binary files /dev/null and b/docs/sips/sips_6.png differ diff --git a/docs/sips/sips_7.png b/docs/sips/sips_7.png new file mode 100644 index 0000000..8c8d058 Binary files /dev/null and b/docs/sips/sips_7.png differ diff --git a/docs/sips/sips_8.png b/docs/sips/sips_8.png new file mode 100644 index 0000000..80742a5 Binary files /dev/null and b/docs/sips/sips_8.png differ diff --git a/docs/sips/sips_9.png b/docs/sips/sips_9.png new file mode 100644 index 0000000..ff131f6 Binary files /dev/null and b/docs/sips/sips_9.png differ diff --git a/docs/sips/sipsborder.png b/docs/sips/sipsborder.png new file mode 100644 index 0000000..9412c60 Binary files /dev/null and b/docs/sips/sipsborder.png differ diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..9efa6f8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,13 @@ +org.gradle.jvmargs=-Xmx1G + minecraft_version=1.16.4 + yarn_mappings=1.16.4+build.6 + loader_version=0.10.6+build.214 + + mod_version = 0.6.0 + maven_group = mod.codewarrior + archives_base_name = sips + + fabric_version=0.25.1+build.416-1.16 + mod_menu_version=1.14.9+build.13 + rei_version=5.8.5 + lba_version=0.8.4 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..e708b1c 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..be52383 --- /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.7-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/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..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@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 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%"=="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/mod/codewarrior/sips/SipsMod.java b/src/main/java/mod/codewarrior/sips/SipsMod.java new file mode 100644 index 0000000..9ffac93 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/SipsMod.java @@ -0,0 +1,51 @@ +package mod.codewarrior.sips; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.registry.*; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.client.itemgroup.FabricItemGroupBuilder; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.time.LocalDateTime; +import java.time.Month; + +public class SipsMod implements ModInitializer { + public static String modid = "sips"; + public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + public static final Logger LOGGER = LogManager.getLogger(modid); + public static LocalDateTime date = LocalDateTime.now(); + static boolean fool = false; + + @Override + public void onInitialize() { + if (date.getMonth() == Month.APRIL && date.getDayOfMonth() == 1) { + fool = true; + } + SipsConfig.tryInit(); + SipsItems.init(); + SipsBlocks.init(); + SipsFluids.init(); + SipsEffects.init(); + SipsEvents.init(); + SippableRegistry.init(); + } + + public static boolean isApril1st() { + return fool; + } + + public static Identifier getId(String name) { + return new Identifier(modid, name); + } + + public static ItemGroup SipsGroup = FabricItemGroupBuilder.build( + getId(modid), + () -> new ItemStack(SipsItems.LIL_SIP) + ); +} diff --git a/src/main/java/mod/codewarrior/sips/client/FluidResourceListener.java b/src/main/java/mod/codewarrior/sips/client/FluidResourceListener.java new file mode 100644 index 0000000..432fcdd --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/client/FluidResourceListener.java @@ -0,0 +1,45 @@ +package mod.codewarrior.sips.client; + +import com.google.common.collect.ImmutableList; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.registry.SipsFluids; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; +import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.fluid.Fluid; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; + +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +@Environment(EnvType.CLIENT) +public class FluidResourceListener implements SimpleSynchronousResourceReloadListener { + @Override + public Identifier getFabricId() { + return SipsMod.getId("fluid_resourcelistener"); + } + + @Override + public void apply(ResourceManager manager) { + final Function atlas = MinecraftClient.getInstance().getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE); + Map, FluidRenderHandler> map = new Object2ObjectOpenHashMap<>(); + map.put(ImmutableList.of(SipsFluids.MILK, SipsFluids.FLOWING_MILK), (blockRenderView, blockPos, fluidState) -> new Sprite[]{ + atlas.apply(SipsMod.getId("block/fluid/milk_still")), + atlas.apply(SipsMod.getId("block/fluid/milk_flow")) + }); + map.put(ImmutableList.of(SipsFluids.MUSHROOM_STEW, SipsFluids.FLOWING_MUSHROOM_STEW), ((blockRenderView, blockPos, fluidState) -> new Sprite[]{ + atlas.apply(SipsMod.getId("block/fluid/mushroom_stew_still")), + atlas.apply(SipsMod.getId("block/fluid/mushroom_stew_flow")) + })); + + map.forEach((k, v) -> k.forEach(f -> FluidRenderHandlerRegistry.INSTANCE.register(f, v))); + } +} diff --git a/src/main/java/mod/codewarrior/sips/client/SipsClient.java b/src/main/java/mod/codewarrior/sips/client/SipsClient.java new file mode 100644 index 0000000..54ba7d5 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/client/SipsClient.java @@ -0,0 +1,88 @@ +package mod.codewarrior.sips.client; + +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.client.models.SipsModel; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.registry.SippableRegistry; +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; +import net.fabricmc.fabric.api.client.model.ModelLoadingRegistry; +import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; +import net.fabricmc.fabric.api.network.ClientSidePacketRegistry; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.resource.ResourceType; + +import static mod.codewarrior.sips.registry.SipsFluids.*; + +@Environment(EnvType.CLIENT) +public class SipsClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new FluidResourceListener()); + BlockRenderLayerMap.INSTANCE.putFluids(RenderLayer.getTranslucent(), MILK, FLOWING_MILK, MUSHROOM_STEW, FLOWING_MUSHROOM_STEW); + + ClientSidePacketRegistry.INSTANCE.register(SippableRegistry.SIPPABLES_S2C, (ctx, buf) -> { + if (FabricLoader.getInstance().isModLoaded("roughlyenoughitems")) { + SippableRegistry.fromPacket(buf); + } + }); + + String[] str = new String[]{ + "milk_still", + "milk_flow", + "mushroom_stew_still", + "mushroom_stew_flow" + }; + ClientSpriteRegistryCallback.event(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).register((atlas, registry) -> { + for (String s : str) registry.register(SipsMod.getId("block/fluid/" + s)); + }); + + if (!SipsConfig.use3DModels()) { + ModelLoadingRegistry.INSTANCE.registerAppender((manager, out) -> { + out.accept(new ModelIdentifier(SipsMod.getId("lil_sip_2d"), "inventory")); + out.accept(new ModelIdentifier(SipsMod.getId("big_chug_2d"), "inventory")); + }); + } + + ModelLoadingRegistry.INSTANCE.registerVariantProvider(manager -> (modelId, ctx) -> { + if (modelId.getNamespace().equals(SipsMod.modid)) { + String s, s2; + boolean bl = false, bl2 = false; + switch (modelId.getPath()) { + case "lil_sip": + if (SipsConfig.use3DModels()) { + s = "item/lil_sip_3d"; + s2 = s; + } else { + s = "item/lil_sip_2d"; + s2 = "item/lil_sip"; + bl2 = true; + } + break; + case "big_chug": + if (SipsConfig.use3DModels()) { + s = "item/big_chug_3d"; + s2 = s; + } else { + s = "item/big_chug_2d"; + s2 = "item/big_chug"; + bl2 = true; + } + bl = true; + break; + default: + return null; + } + return new SipsModel(s, s2, bl, bl2); + } + return null; + }); + } +} diff --git a/src/main/java/mod/codewarrior/sips/client/models/SipsModel.java b/src/main/java/mod/codewarrior/sips/client/models/SipsModel.java new file mode 100644 index 0000000..cc0c53b --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/client/models/SipsModel.java @@ -0,0 +1,324 @@ +package mod.codewarrior.sips.client.models; + +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import com.google.common.collect.ImmutableSet; +import com.mojang.datafixers.util.Pair; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.utils.FluidUtil; +import mod.codewarrior.sips.utils.LRUCache; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; +import net.fabricmc.fabric.api.renderer.v1.Renderer; +import net.fabricmc.fabric.api.renderer.v1.RendererAccess; +import net.fabricmc.fabric.api.renderer.v1.material.BlendMode; +import net.fabricmc.fabric.api.renderer.v1.material.RenderMaterial; +import net.fabricmc.fabric.api.renderer.v1.mesh.Mesh; +import net.fabricmc.fabric.api.renderer.v1.mesh.MeshBuilder; +import net.fabricmc.fabric.api.renderer.v1.mesh.MutableQuadView; +import net.fabricmc.fabric.api.renderer.v1.mesh.QuadEmitter; +import net.fabricmc.fabric.api.renderer.v1.model.FabricBakedModel; +import net.fabricmc.fabric.api.renderer.v1.model.ModelHelper; +import net.fabricmc.fabric.api.renderer.v1.render.RenderContext; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.model.*; +import net.minecraft.client.render.model.json.ModelOverrideList; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.ModelIdentifier; +import net.minecraft.client.util.SpriteIdentifier; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.Set; +import java.util.function.Function; +import java.util.function.Supplier; + +@Environment(EnvType.CLIENT) +public class SipsModel implements UnbakedModel { + final Identifier fallback; + final SpriteIdentifier tex; + final boolean isChug; + final boolean is2d; + + public SipsModel(String modelPath, String texPath, boolean isChug, boolean is2d) { + this.fallback = SipsMod.getId(modelPath); + this.tex = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, SipsMod.getId(texPath)); + this.isChug = isChug; + this.is2d = is2d; + } + + @Override + public Collection getModelDependencies() { + return ImmutableSet.of(fallback); + } + + @Override + public Collection getTextureDependencies(Function unbakedModelGetter, Set> unresolvedTextureReferences) { + return ImmutableSet.of(tex); + } + + @Override + public @Nullable BakedModel bake(ModelLoader loader, Function textureGetter, ModelBakeSettings rotationContainer, Identifier modelId) { + BakedModel fallback = loader.getOrLoadModel(this.fallback).bake(loader, textureGetter, rotationContainer, this.fallback); + return new BakedSip(fallback, textureGetter.apply(tex), isChug, is2d, this.fallback); + } + + static class BakedSip implements BakedModel, FabricBakedModel { + BakedModel fallback; + Mesh mesh; + boolean swap = true; + + final Sprite tex; + final boolean isChug; + final boolean is2d; + final Identifier id; + final Renderer renderer = RendererAccess.INSTANCE.getRenderer(); + final RenderMaterial layer = renderer.materialFinder().blendMode(0, BlendMode.TRANSLUCENT).find(); + final static LRUCache cache = new LRUCache<>(SipsConfig.getModelCacheSize()); + final static MinecraftClient mc = MinecraftClient.getInstance(); + + public BakedSip(BakedModel fallback, Sprite tex, boolean isChug, boolean is2d, Identifier id) { + this.fallback = fallback; + this.tex = tex; + this.mesh = createMesh(fallback); + this.isChug = isChug; + this.is2d = is2d; + this.id = id; + } + + @Override + public boolean isVanillaAdapter() { + return false; + } + + @Override + public void emitBlockQuads(BlockRenderView blockRenderView, BlockState blockState, BlockPos blockPos, Supplier supplier, RenderContext renderContext) { + + } + + @Override + public void emitItemQuads(ItemStack stack, Supplier supplier, RenderContext renderContext) { + if (swap) { + if (is2d) { + this.fallback = mc.getBakedModelManager().getModel(new ModelIdentifier(id.toString().replace("item/", ""), "inventory")); + this.mesh = createMesh(fallback); + } + swap = false; + } + + renderContext.meshConsumer().accept(mesh); + FluidKey fluid = FluidUtil.getFluid(stack); + if (fluid != FluidKeys.EMPTY) { + RenderState state = RenderState.resolve(fluid); + QuadEmitter qe = renderContext.getEmitter(); + int amount = FluidUtil.getAmount(stack); + float min, max, bot, y, depth; + if (is2d) { + if (isChug) { + min = 0.5F; + max = 0.75F; + bot = 0.125F; + y = (amount / (float) SipsConfig.getBigChugCapacity()) * 0.5F + bot; + depth = 0.47f; + qe.material(layer) + .square(Direction.NORTH, 0.25F, bot, 0.5625F, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.SOUTH, min, bot, max, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.UP, min, 0.47f, max, 0.53f, 1 - y) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + } else { + min = 0.625F; + max = 0.75F; + bot = 0.1875F; + y = (amount / (float) SipsConfig.getLilSipCapacity()) * 0.4375F + bot; + depth = 0.47f; + qe.material(layer) + .square(Direction.NORTH, 0.25F, bot, 0.375F, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.SOUTH, min, bot, max, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.UP, min, 0.47f, max, 0.53f, 1 - y) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + } + } else { + if (isChug) { + bot = 0.125f; + min = 0.313F; + max = 0.686F; + y = (amount / (float) SipsConfig.getBigChugCapacity()) * 0.38125F + bot; + depth = 0.252F; + float w1 = 0.376f; + float w2 = 0.624f; + qe.material(layer) + .square(Direction.UP, min, min, max, 0.6875f, 1f - y) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.UP, w1, depth, w2, min, 1f - y) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.UP, w1, max, w2, 0.7485f, 1f - y) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.NORTH, w1, bot, w2, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.SOUTH, w1, bot, w2, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + } else { + bot = 0.021875F; + min = 0.375F; + max = 0.625F; + y = (amount / (float) SipsConfig.getLilSipCapacity()) * 0.38125F + bot; + depth = 0.3126F; + qe.material(layer) + .square(Direction.UP, min, min, max, 0.6875f, 1f - y) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + qe.material(layer) + .square(Direction.NORTH, min, bot, max, y, depth) + .spriteColor(0, state.color, state.color, state.color, state.color) + .spriteBake(0, state.sprite, MutableQuadView.BAKE_LOCK_UV) + .emit(); + } + } + } + } + + private Mesh createMesh(BakedModel model) { + final MeshBuilder mb = renderer.meshBuilder(); + Random random = new Random(); + random.setSeed(42); + emitModel(random, model, mb.getEmitter()); + return mb.build(); + } + + void emitModel(Random random, BakedModel model, QuadEmitter qe) { + for (int i = 0; i <= ModelHelper.NULL_FACE_ID; i++) { + Direction cullFace = ModelHelper.faceFromIndex(i); + List quads = model.getQuads(null, cullFace, random); + + if (quads.isEmpty()) { + continue; + } + + for (final BakedQuad q : quads) { + qe.fromVanilla(q.getVertexData(), 0, false); + qe.cullFace(cullFace); + qe.nominalFace(q.getFace()); + qe.colorIndex(q.getColorIndex()); + qe.emit(); + } + } + } + + @Override + public List getQuads(@Nullable BlockState state, @Nullable Direction face, Random random) { + return fallback.getQuads(state, face, random); + } + + @Override + public boolean useAmbientOcclusion() { + return fallback.useAmbientOcclusion(); + } + + @Override + public boolean hasDepth() { + return fallback.hasDepth(); + } + + @Override + public boolean isSideLit() { + return false; + } + + @Override + public boolean isBuiltin() { + return fallback.isBuiltin(); + } + + @Override + public Sprite getSprite() { + return this.tex; + } + + @Override + public ModelTransformation getTransformation() { + return fallback.getTransformation(); + } + + @Override + public ModelOverrideList getOverrides() { + return fallback.getOverrides(); + } + + static class RenderState { + final Sprite sprite; + final int color; + + private RenderState(Sprite sprite, int color) { + this.sprite = sprite; + this.color = color; + } + + public static RenderState resolve(FluidKey fluid) { + if (cache.get(fluid) == null && mc.cameraEntity != null) { + Sprite s; + World world = mc.cameraEntity.world; + BlockPos pos = BlockPos.ORIGIN; + FluidRenderHandler fluidRenderHandler = FluidRenderHandlerRegistry.INSTANCE.get(fluid.getRawFluid()); + s = fluid.getRawFluid() == null + ? FluidRenderHandlerRegistry.INSTANCE.get(Fluids.WATER).getFluidSprites(world, pos, Fluids.WATER.getDefaultState())[0] + : fluidRenderHandler.getFluidSprites(world, pos, fluid.getRawFluid().getDefaultState())[0]; + int color = fluid.getRawFluid() == null + ? fluid.renderColor + : fluidRenderHandler.getFluidColor(world, pos, fluid.getRawFluid().getDefaultState()); + cache.put(fluid, new RenderState(s, color | 0xFF000000)); + } + return cache.get(fluid); + } + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/compat/rei/ClickableTexWidget.java b/src/main/java/mod/codewarrior/sips/compat/rei/ClickableTexWidget.java new file mode 100644 index 0000000..3368178 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/compat/rei/ClickableTexWidget.java @@ -0,0 +1,37 @@ +package mod.codewarrior.sips.compat.rei; + +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.ClientHelper; +import me.shedaniel.rei.api.ConfigObject; +import me.shedaniel.rei.api.widgets.Tooltip; +import me.shedaniel.rei.gui.widget.EntryWidget; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class ClickableTexWidget extends EntryWidget { + protected ClickableTexWidget(Rectangle rect) { + super(rect.getMinX(), rect.getMinY()); + this.getBounds().setSize(rect.getWidth(), rect.getHeight()); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (interactable && containsMouse(mouseX, mouseY)) + return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addCategory(SipsREIPlugin.BEVERAGES).fillPreferredOpenedCategory()); + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + protected void queueTooltip(MatrixStack matrices, int mouseX, int mouseY, float delta) { + Text text = new TranslatableText("rei.sips.show_category"); + Tooltip tooltip = Tooltip.create(new Point(mouseX, mouseY), text); + tooltip.queue(); + } +} diff --git a/src/main/java/mod/codewarrior/sips/compat/rei/SipsREICategory.java b/src/main/java/mod/codewarrior/sips/compat/rei/SipsREICategory.java new file mode 100644 index 0000000..baa23f7 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/compat/rei/SipsREICategory.java @@ -0,0 +1,267 @@ +package mod.codewarrior.sips.compat.rei; + +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.api.RecipeCategory; +import me.shedaniel.rei.api.widgets.Label; +import me.shedaniel.rei.api.widgets.Widgets; +import me.shedaniel.rei.gui.widget.Widget; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.registry.SippableRegistry; +import mod.codewarrior.sips.registry.SipsItems; +import mod.codewarrior.sips.utils.FluidUtil; +import mod.codewarrior.sips.utils.RomanConverter; +import mod.codewarrior.sips.utils.Sippable; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRenderDispatcher; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffectUtil; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.text.LiteralText; +import net.minecraft.util.Hand; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Quaternion; +import org.apache.commons.lang3.text.WordUtils; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Random; + +@Environment(EnvType.CLIENT) +public class SipsREICategory implements RecipeCategory { + protected Identifier bg = SipsMod.getId("textures/gui/background.png"); + private final Identifier RECIPECONTAINER = new Identifier("roughlyenoughitems:textures/gui/recipecontainer.png"); + private MinecraftClient mc = MinecraftClient.getInstance(); + + @Override + public @NotNull Identifier getIdentifier() { + return SipsREIPlugin.BEVERAGES; + } + + @Override + public @NotNull EntryStack getLogo() { + ItemStack logo = new ItemStack(SipsItems.LIL_SIP); + FluidUtil.setFluid(logo, FluidKeys.WATER); + FluidUtil.setAmount(logo, (int) (FluidUtil.getMaxCapacity(logo) * 0.75d)); + return EntryStack.create(logo); + } + + @Override + public @NotNull String getCategoryName() { + return I18n.translate("rei.sips.category"); + } + + @Override + public @NotNull List setupDisplay(SipsREIDisplay display, Rectangle bounds) { + List widgets = Lists.newArrayList(); + widgets.add(Widgets.createTexturedWidget(this.bg, bounds.x - 11, bounds.y - 50, 0, 0, 172, 229, 172, 229)); + widgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> { + matrices.translate(0.0D, 0.0D, 50.0D); + if (mc.player != null) { + drawEntity(bounds.getCenterX() - 12, bounds.getCenterY() + 105, 104, 35f, -35f, mc.player); + } + drawSippableDetails(helper, matrices, display.getFluid(), bounds); + })); + + widgets.add(Widgets.createSlot(new Point(bounds.getCenterX() - 33, bounds.getCenterY() - 16)).entries(display.getInputEntries().get(0))); + widgets.add(Widgets.createSlot(new Point(bounds.getCenterX() - 8, bounds.getCenterY())).entries(display.getInputEntries().get(1)).disableBackground().disableHighlight()); + widgets.add(Widgets.createLabel(new Point(bounds.getCenterX() - 8, bounds.getCenterY() + 4), new LiteralText("+"))); + Rectangle rect = new Rectangle(bounds.getCenterX() - 11, bounds.getCenterY() - 16, 24, 17); + widgets.add(Widgets.createTexturedWidget(RECIPECONTAINER, rect, 40, 223)); + widgets.add(new ClickableTexWidget(rect).noBackground().disableFavoritesInteractions()); + + widgets.add(new SipsWidget(bounds.x + 90, bounds.y + 16).entries(display.getResultingEntries().get(0)).noBackground().noHighlight()); + + int qnum = new Random().nextInt(48); + String quote = WordUtils.wrap(I18n.translate("rei.sips.quote" + qnum), 28, "\n", false); + String[] str = quote.split("\n"); + int i = 0; + int v = 5; + for (String q : str) { + Label text = Widgets.createLabel(new Point(bounds.getCenterX() - 13, bounds.getMaxY() + 35 - v * str.length + i), new LiteralText(q)); + widgets.add(text); + i += 10; + } + return widgets; + } + + @Override + public int getDisplayHeight() { + return 128; + } + + @Override + public int getDisplayWidth(SipsREIDisplay display) { + return 150; + } + + @Override + public int getMaximumRecipePerPage() { + return 1; + } + + @Override + public int getFixedRecipesPerPage() { + return -1; + } + + protected void drawEntity(int x, int y, int size, float mouseX, float mouseY, PlayerEntity entity) { + float f = (float) Math.atan(mouseX / 40.0F); + float g = (float) Math.atan(mouseY / 40.0F); + RenderSystem.pushMatrix(); + RenderSystem.translatef((float) x, (float) y, 50.0F); + RenderSystem.scalef(1.0F, 1.0F, -1.0F); + MatrixStack matrixStack = new MatrixStack(); + matrixStack.translate(0.0D, 0.0D, 50.0D); + matrixStack.scale((float) size, (float) size, (float) size); + Quaternion quaternion = Vector3f.POSITIVE_Z.getDegreesQuaternion(180.0F); + Quaternion quaternion2 = Vector3f.POSITIVE_X.getDegreesQuaternion(g * 20.0F); + quaternion.hamiltonProduct(quaternion2); + matrixStack.multiply(quaternion); + float h = entity.bodyYaw; + float i = entity.yaw; + float j = entity.pitch; + float k = entity.prevHeadYaw; + float l = entity.headYaw; + float hsp = entity.handSwingProgress; + ItemStack stack = entity.getOffHandStack(); + entity.preferredHand = Hand.OFF_HAND; + entity.handSwingProgress = 0.1f; + entity.lastHandSwingProgress = 0.1f; + entity.inventory.offHand.set(0, ItemStack.EMPTY); + entity.bodyYaw = 190.0F + f * 20.0F; + entity.yaw = 180.0F + f * 40.0F; + entity.pitch = -15f; + entity.headYaw = 180f; + entity.prevHeadYaw = 180f; + + EntityRenderDispatcher entityRenderDispatcher = MinecraftClient.getInstance().getEntityRenderDispatcher(); + quaternion2.conjugate(); + entityRenderDispatcher.setRotation(quaternion2); + entityRenderDispatcher.setRenderShadows(false); + VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers(); + entityRenderDispatcher.render(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F, matrixStack, immediate, 15728880); + immediate.draw(); + entityRenderDispatcher.setRenderShadows(true); + entity.bodyYaw = h; + entity.yaw = i; + entity.pitch = j; + entity.prevHeadYaw = k; + entity.headYaw = l; + entity.handSwingProgress = hsp; + entity.lastHandSwingProgress = hsp; + entity.inventory.offHand.set(0, stack); + RenderSystem.popMatrix(); + } + + protected void drawSippableDetails(DrawableHelper helper, MatrixStack matrices, FluidKey fluid, Rectangle bounds) { + int x, y = bounds.getMinY(), i = 0, j = 0, up = 0, amt = 0; + if (SippableRegistry.SIPS.containsKey(fluid)) { + Sippable sip = SippableRegistry.SIPS.get(fluid); + + if (sip.shanks > 0) { + int outline = 16; + int shank = 52; + int halfshank = shank + 9; + int shankloop = (int) Math.ceil(Math.abs(sip.shanks) / 2f); + x = bounds.getMaxX() - 22 + (9 * shankloop) / 2; + + mc.getTextureManager().bindTexture(Screen.GUI_ICONS_TEXTURE); + for (int h = 0; h < shankloop * 2; h += 2) { + x -= 9; + helper.drawTexture(matrices, x, y, outline, 27, 9, 9); + + if (sip.shanks > h) { + helper.drawTexture(matrices, x, y, sip.shanks - 1 == h ? halfshank : shank, 27, 9, 9); + } + } + up = 1; + } + if (sip.saturation > 0) { + int satX = 43; + int sat = 70; + int halfsat = sat + 9; + int satloop = (int) Math.max(1, Math.ceil(Math.abs(sip.saturation) / 2f)); + x = bounds.getMaxX() - 22 + (9 * satloop) / 2; + y -= 9 * up; + for (int h = 0; h < satloop * 2; h += 2) { + float effectiveSaturationOfBar = (Math.abs(sip.saturation) - h) / 2f; + x -= 9; + RenderSystem.color4f(1f, 0.8f, 0f, 1f); + helper.drawTexture(matrices, x, y, satX, 27, 9, 9); + RenderSystem.color4f(1f, 1f, 1f, 1f); + helper.drawTexture(matrices, x, y, effectiveSaturationOfBar >= 1 ? sat : halfsat, 27, 9, 9); + + } + up = 1; + } + + if (sip.damage != 0) { + boolean heal = sip.damage < 0; + int loop = (int) Math.max(1, Math.ceil(Math.abs(sip.damage) / 2f)); + int outline = heal ? 16 : 34; + int heart = heal ? 52 : 124; + int halfheart = heart + 9; + x = bounds.getMaxX() - 22 + (9 * loop) / 2; + y -= 9 * up; + mc.getTextureManager().bindTexture(Screen.GUI_ICONS_TEXTURE); + for (int h = 0; h < loop * 2; h += 2) { + float effectivedmg = (Math.abs(sip.damage) - h) / 2f; + x -= 9; + helper.drawTexture(matrices, x, y, outline, 0, 9, 9); + helper.drawTexture(matrices, x, y, effectivedmg >= 1 ? heart : halfheart, 0, 9, 9); + } + } + + for (Sippable.Effect effect : sip.effects) { + StatusEffectInstance fx = effect.getEffect(); + StatusEffect type = fx.getEffectType(); + + x = bounds.getMaxX() + 9; + y = bounds.getMaxY() - 2; + i++; + amt++; + x -= 24 * i; + if (amt > 7) { + x = bounds.getMaxX() + 9; + ++j; + x -= 24 * j; + y -= 24; + } + mc.getTextureManager().bindTexture(HandledScreen.BACKGROUND_TEXTURE); + helper.drawTexture(matrices, x, y, 141, 166, 24, 24); + String duration = StatusEffectUtil.durationToString(fx, 1f); + Sprite sprite = mc.getStatusEffectSpriteManager().getSprite(type); + mc.getTextureManager().bindTexture(sprite.getAtlas().getId()); + DrawableHelper.drawSprite(matrices, x + 3, y + 3, helper.getZOffset(), 18, 18, sprite); + matrices.push(); + float f = 0.65f; + matrices.scale(f, f, 1f); + if (fx.getAmplifier() > 0) { + String roman = RomanConverter.toRoman(fx.getAmplifier()); + mc.textRenderer.drawWithShadow(matrices, roman, (x + 12) / f - mc.textRenderer.getWidth(roman) / 2f, (y + 3) / f, 0xFFFFFFFF); + } + if (!duration.equals("0:00")) + mc.textRenderer.drawWithShadow(matrices, duration, (x + 12) / f - mc.textRenderer.getWidth(duration) / 2f, (y + 16) / f, 0xFFFFFFFF); + matrices.pop(); + } + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/compat/rei/SipsREIDisplay.java b/src/main/java/mod/codewarrior/sips/compat/rei/SipsREIDisplay.java new file mode 100644 index 0000000..304685e --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/compat/rei/SipsREIDisplay.java @@ -0,0 +1,105 @@ +package mod.codewarrior.sips.compat.rei; + +import alexiil.mc.lib.attributes.fluid.FluidContainerRegistry; +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import com.google.common.collect.ImmutableList; +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.api.RecipeDisplay; +import mod.codewarrior.sips.registry.SipsItems; +import mod.codewarrior.sips.utils.FluidUtil; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.potion.Potion; +import net.minecraft.potion.PotionUtil; +import net.minecraft.potion.Potions; +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +@Environment(EnvType.CLIENT) +public class SipsREIDisplay implements RecipeDisplay { + private static final ItemStack lilSip = new ItemStack(SipsItems.LIL_SIP); + private static final ItemStack bigChug = new ItemStack(SipsItems.BIG_CHUG); + public static List inputs = EntryStack.ofItemStacks(ImmutableList.of(lilSip, bigChug)); + private List buckets; + private List results; + private FluidKey fluid; + + public SipsREIDisplay(FluidKey fluid) { + List stacks = new ArrayList<>(); + Set items = FluidContainerRegistry.getFullContainersFor(fluid); + if (items.isEmpty()) { + if (fluid.getRawFluid() != null) + stacks.add(new ItemStack(fluid.getRawFluid().getBucketItem())); + } else { + items.forEach(item -> stacks.add(new ItemStack(item))); + } + this.buckets = EntryStack.ofItemStacks(stacks); + ItemStack sip = lilSip.copy(); + FluidUtil.setFluid(sip, fluid); + FluidUtil.setAmount(sip, FluidUtil.getMaxCapacity(sip)); + ItemStack chug = bigChug.copy(); + FluidUtil.setFluid(chug, fluid); + FluidUtil.setAmount(chug, FluidUtil.getMaxCapacity(chug)); + this.results = EntryStack.ofItemStacks(ImmutableList.of(sip, chug)); + this.fluid = fluid; + } + + public SipsREIDisplay(Set potions) { + List pots = new ArrayList<>(); + List filled = new ArrayList<>(); + potions.forEach(potion -> { + FluidKey key = FluidKeys.get(potion); + ItemStack pot = PotionUtil.setPotion(new ItemStack(Items.POTION), potion); + pots.add(pot); + ItemStack sip = lilSip.copy(); + FluidUtil.setFluid(sip, key); + FluidUtil.setAmount(sip, FluidUtil.getMaxCapacity(sip)); + filled.add(sip); + }); + potions.forEach(potion -> { + FluidKey key = FluidKeys.get(potion); + ItemStack chug = bigChug.copy(); + FluidUtil.setFluid(chug, key); + FluidUtil.setAmount(chug, FluidUtil.getMaxCapacity(chug)); + filled.add(chug); + }); + this.buckets = EntryStack.ofItemStacks(pots); + this.results = EntryStack.ofItemStacks(filled); + this.fluid = FluidKeys.get(Potions.LUCK); + } + + @Override + public @NotNull List> getInputEntries() { + List> list = new ArrayList<>(); + list.add(0, inputs); + list.add(1, buckets); + list.add(2, fluid.getRawFluid() != null + ? Collections.singletonList(EntryStack.create(fluid.getRawFluid())) + : Collections.emptyList()); + return list; + } + + @NotNull + @Override + public List> getResultingEntries() { + return Collections.singletonList(results); + } + + public FluidKey getFluid() { + return this.fluid; + } + + @Override + public @NotNull Identifier getRecipeCategory() { + return SipsREIPlugin.BEVERAGES; + } +} diff --git a/src/main/java/mod/codewarrior/sips/compat/rei/SipsREIPlugin.java b/src/main/java/mod/codewarrior/sips/compat/rei/SipsREIPlugin.java new file mode 100644 index 0000000..9c9e055 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/compat/rei/SipsREIPlugin.java @@ -0,0 +1,68 @@ +package mod.codewarrior.sips.compat.rei; + +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import com.google.common.collect.ImmutableSet; +import me.shedaniel.rei.api.RecipeHelper; +import me.shedaniel.rei.api.plugins.REIPluginV0; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.registry.SippableRegistry; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.fluid.Fluids; +import net.minecraft.potion.Potion; +import net.minecraft.potion.Potions; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import java.util.ArrayList; +import java.util.List; + + +@Environment(EnvType.CLIENT) +public class SipsREIPlugin implements REIPluginV0 { + public static final Identifier PLUGIN = SipsMod.getId("rei_plugin"); + public static final Identifier BEVERAGES = SipsMod.getId("beverages"); + + @Override + public Identifier getPluginIdentifier() { + return PLUGIN; + } + + @Override + public void registerPluginCategories(RecipeHelper recipeHelper) { + recipeHelper.registerCategory(new SipsREICategory()); + } + + @Override + public void registerRecipeDisplays(RecipeHelper recipeHelper) { + List sipless = new ArrayList<>(); + Registry.FLUID.forEach(fluid -> { + if (fluid != Fluids.EMPTY && fluid.isStill(fluid.getDefaultState())) { + FluidKey key = FluidKeys.get(fluid); + if (SippableRegistry.SIPS.containsKey(key)) { + recipeHelper.registerDisplay(new SipsREIDisplay(key)); + } else if (SipsConfig.listDullBeverages()) { + sipless.add(key); + } + } + }); + if (!sipless.isEmpty()) { + for (FluidKey key : sipless) recipeHelper.registerDisplay(new SipsREIDisplay(key)); + } + + ImmutableSet.Builder potions = ImmutableSet.builder(); + Registry.POTION.forEach(potion -> { + if (potion != Potions.EMPTY && potion != Potions.WATER) { + potions.add(potion); + } + }); + recipeHelper.registerDisplay(new SipsREIDisplay(potions.build())); + } + + @Override + public void registerOthers(RecipeHelper recipeHelper) { + recipeHelper.removeAutoCraftButton(BEVERAGES); + } +} diff --git a/src/main/java/mod/codewarrior/sips/compat/rei/SipsWidget.java b/src/main/java/mod/codewarrior/sips/compat/rei/SipsWidget.java new file mode 100644 index 0000000..192f91f --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/compat/rei/SipsWidget.java @@ -0,0 +1,25 @@ +package mod.codewarrior.sips.compat.rei; + +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.gui.widget.EntryWidget; +import net.minecraft.client.util.math.MatrixStack; + +public class SipsWidget extends EntryWidget { + + protected SipsWidget(int x, int y) { + super(x, y); + this.getBounds().setSize(80, 88); + } + + protected Rectangle getSipBounds() { + return new Rectangle(this.getBounds().x - 6, this.getBounds().y, 88, 88); + } + + @Override + protected void drawCurrentEntry(MatrixStack matrices, int mouseX, int mouseY, float delta) { + EntryStack entry = this.getCurrentEntry(); + entry.setZ(100); + entry.render(matrices, this.getSipBounds(), mouseX, mouseY, delta); + } +} diff --git a/src/main/java/mod/codewarrior/sips/config/SipsConfig.java b/src/main/java/mod/codewarrior/sips/config/SipsConfig.java new file mode 100644 index 0000000..49a7ba8 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/config/SipsConfig.java @@ -0,0 +1,200 @@ +package mod.codewarrior.sips.config; + +import com.google.common.collect.ImmutableSet; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Date; +import java.util.Map; +import java.util.Properties; + +import static mod.codewarrior.sips.SipsMod.LOGGER; + +public class SipsConfig { + static boolean isInitialized = false; + static int lilSipCapacity; + static int bigChugCapacity; + static int modelCacheSize; + static float temperatureDamagePerCelsius; + static boolean temperatureEffects; + static boolean use3DModels; + static boolean loadDefaultSippables; + static boolean liquidXpEffect; + static boolean listDullBeverages; + + public static int getLilSipCapacity() { + return lilSipCapacity; + } + + public static int getBigChugCapacity() { + return bigChugCapacity; + } + + public static int getModelCacheSize() { + return modelCacheSize; + } + + public static boolean use3DModels() { + return use3DModels; + } + + public static float getTemperatureDamagePerCelsius() { + return temperatureDamagePerCelsius; + } + + public static boolean useTemperatureEffects() { + return temperatureEffects; + } + + public static boolean loadDefaultSippables() { + return loadDefaultSippables; + } + + public static boolean liquidXpHasEffect() { + return liquidXpEffect; + } + + public static boolean listDullBeverages() { + return listDullBeverages; + } + + private static void handleConfig(Map cfg) { + lilSipCapacity = Integer.parseInt(cfg.get("lilSipCapacity")) * 250; + bigChugCapacity = Integer.parseInt(cfg.get("bigChugCapacity")) * 250; + modelCacheSize = Integer.parseInt(cfg.get("modelCacheSize")); + temperatureDamagePerCelsius = Float.parseFloat(cfg.get("temperatureDamagePerCelsius")); + temperatureEffects = Boolean.parseBoolean(cfg.get("temperatureEffects")); + use3DModels = Boolean.parseBoolean(cfg.get("use3DModels")); + loadDefaultSippables = Boolean.parseBoolean(cfg.get("loadDefaultSippables")); + liquidXpEffect = Boolean.parseBoolean(cfg.get("liquidXpEffect")); + listDullBeverages = Boolean.parseBoolean(cfg.get("listDullBeverages")); + } + + public static void tryInit() { + if (!isInitialized) init(); + } + + private static void init() { + Map cfg = new Object2ObjectOpenHashMap<>(); + ImmutableSet> entries = ImmutableSet.of( + Entry.of("lilSipCapacity", 4, + "lilSipCapacity: The amount of sips a Lil Sip can hold. [Side: BOTH | Default: 4]"), + Entry.of("bigChugCapacity", 32, + "bigChugCapacity: The amount of sips a Big Chug can hold. [Side: BOTH | Default: 32]"), + Entry.of("temperatureDamagePerCelsius", 0.1f, + "temperatureDamagePerCelsius: Unlisted fluids will deal this much damage per Celsius above 46.85 or below -13.15. [Side: SERVER | Default: 0.1]" + + "\n#(Default fluid temperature: 26.85C; Lava: 1026.85C; Cryotheum: -223.15C)."), + Entry.of("temperatureEffects", true, + "temperatureEffects: Unlisted fluids will set the player on fire or apply slowness and fatigue effects if they are too hot or cold. [Side: SERVER | Default : true]"), + Entry.of("modelCacheSize", 48, + "modelCacheSize: The amount of fluid states that can be cached for Sip rendering. [Side: CLIENT | Default: 48]"), + Entry.of("use3DModels", true, + "use3DModels: When false, reverts to a less resource-intensive renderer. [Side: CLIENT | Default: true]"), + Entry.of("loadDefaultSippables", true, + "loadDefaultSippables: Toggles the parsing of any sippables json named \"default_sippables.json\". [Side: SERVER | Default: true]"), + Entry.of("liquidXpEffect", true, + "[COMPAT] liquidXpEffect: Fluids with an id of \"liquid_xp\" give experience with each Sip. [Side: SERVER | Default: true]"), + Entry.of("listDullBeverages", true, + "[COMPAT] listEmptyBeverages: Toggles populating the Beverages Category in REI with effectless fluids. [Side: CLIENT | Default: true]") + ); + Path configPath = FabricLoader.getInstance().getConfigDir().resolve("sips.properties"); + try { + boolean changed = false; + File configurationFile = configPath.toFile(); + if (Files.notExists(configPath) && !configPath.toFile().createNewFile()) { + LOGGER.error("[Sips] Error creating config file \"" + configurationFile + "\"."); + } + Properties config = new Properties(); + StringBuilder content = new StringBuilder().append("#Sips Configuration.\n"); + content.append("#Last generated at: ").append(new Date().toString()).append("\n\n"); + FileInputStream input = new FileInputStream(configurationFile); + config.load(input); + for (Entry entry : entries) { + String key = entry.key; + Object value = entry.value; + Class cls = entry.cls; + if (!config.containsKey(key)) { + changed = true; + config.setProperty(key, value.toString()); + } + if (config.containsKey(key)) { + Object obj = config.getProperty(key); + String s = String.valueOf(obj); + if (s.equals("")) { + LOGGER.error("[Sips] Error processing configuration file \"" + configurationFile + "\"."); + LOGGER.error("[Sips] Expected configuration value for " + key + " to be present, found nothing. Using default value \"" + value + "\" instead."); + cfg.put(key, value.toString()); + } else if (cls.equals(Integer.class)) { + try { + Integer.parseInt(s); + cfg.put(key, s); + } catch (NumberFormatException e) { + LOGGER.error("[Sips] Error processing configuration file \"" + configurationFile + "\"."); + LOGGER.error("[Sips] Expected configuration value for " + key + " to be an integer, found \"" + s + "\". Using default value \"" + value + "\" instead."); + cfg.put(key, value.toString()); + } + } else if (cls.equals(Float.class)) { + try { + Float.parseFloat(s); + cfg.put(key, s); + } catch (NumberFormatException e) { + LOGGER.error("[Sips] Error processing configuration file \"" + configurationFile + "\"."); + LOGGER.error("[Sips] Expected configuration value for " + key + " to be a float, found \"" + s + "\". Using default value \"" + value + "\" instead."); + cfg.put(key, value.toString()); + } + } else if (cls.equals(Boolean.class)) { + if (!"true".equals(s.toLowerCase()) && !"false".equals(s.toLowerCase())) { + LOGGER.error("[Sips] Error processing configuration file \"" + configurationFile + "\"."); + LOGGER.error("[Sips] Expected configuration value for " + key + " to be a boolean, found \"" + s + "\". Using default value \"" + value + "\" instead."); + cfg.put(key, value.toString()); + } else cfg.put(key, s); + } + } + content.append("#").append(entry.comment.get()).append("\n"); + content.append(key).append("=").append(cfg.get(key)).append("\n"); + } + if (changed) { + FileWriter fw = new FileWriter(configurationFile, false); + fw.write(content.toString()); + fw.close(); + } + handleConfig(cfg); + isInitialized = true; + } catch (IOException e) { + LOGGER.error("[Sips] Could not read/write config! Stacktrace: " + e); + } + } + + private static class Entry { + private final String key; + private final T value; + private final WeakReference comment; + private final Class cls; + + private Entry(String key, T value, String comment, Class cls) { + this.key = key; + this.value = value; + this.comment = new WeakReference<>(comment); + this.cls = cls; + } + + public static Entry of(String key, int value, String comment) { + return new Entry<>(key, value, comment, Integer.class); + } + + public static Entry of(String key, float value, String comment) { + return new Entry<>(key, value, comment, Float.class); + } + + public static Entry of(String key, boolean value, String comment) { + return new Entry<>(key, value, comment, Boolean.class); + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/effects/LavaDigestionEffect.java b/src/main/java/mod/codewarrior/sips/effects/LavaDigestionEffect.java new file mode 100644 index 0000000..cc43931 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/effects/LavaDigestionEffect.java @@ -0,0 +1,23 @@ +package mod.codewarrior.sips.effects; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectType; + +public class LavaDigestionEffect extends StatusEffect { + public LavaDigestionEffect() { + super(StatusEffectType.HARMFUL, 12714018); + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + return true; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + if (!entity.isFireImmune() && !entity.isOnFire()) { + entity.setOnFireFor(15); + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/effects/PurgeEffect.java b/src/main/java/mod/codewarrior/sips/effects/PurgeEffect.java new file mode 100644 index 0000000..443d394 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/effects/PurgeEffect.java @@ -0,0 +1,21 @@ +package mod.codewarrior.sips.effects; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectType; + +public class PurgeEffect extends StatusEffect { + public PurgeEffect() { + super(StatusEffectType.BENEFICIAL, 16777215); + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + return true; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + entity.clearStatusEffects(); + } +} diff --git a/src/main/java/mod/codewarrior/sips/effects/ThermodynamicsEffect.java b/src/main/java/mod/codewarrior/sips/effects/ThermodynamicsEffect.java new file mode 100644 index 0000000..0285850 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/effects/ThermodynamicsEffect.java @@ -0,0 +1,35 @@ +package mod.codewarrior.sips.effects; + +import mod.codewarrior.sips.registry.SipsEffects; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectType; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; + +public class ThermodynamicsEffect extends StatusEffect { + public ThermodynamicsEffect() { + super(StatusEffectType.NEUTRAL, 4718847); + } + + @Override + public boolean canApplyUpdateEffect(int duration, int amplifier) { + return true; + } + + @Override + public void applyUpdateEffect(LivingEntity entity, int amplifier) { + if (entity instanceof ServerPlayerEntity) { + ServerPlayerEntity player = (ServerPlayerEntity) entity; + if (entity.getStatusEffect(SipsEffects.LAVA_DIGESTION) != null) { + entity.removeStatusEffect(SipsEffects.LAVA_DIGESTION); + entity.extinguish(); + entity.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 2f, player.world.random.nextFloat() * 0.1F + 0.9F); + player.dropItem(new ItemStack(Items.OBSIDIAN, 1 + amplifier), true, true); + } + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/fluids/MilkFluid.java b/src/main/java/mod/codewarrior/sips/fluids/MilkFluid.java new file mode 100644 index 0000000..ae467a5 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/fluids/MilkFluid.java @@ -0,0 +1,139 @@ +package mod.codewarrior.sips.fluids; + +import mod.codewarrior.sips.registry.SipsBlocks; +import mod.codewarrior.sips.registry.SipsFluids; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.tag.TagRegistry; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidBlock; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.particle.ParticleEffect; +import net.minecraft.particle.ParticleTypes; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.state.StateManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; + +public abstract class MilkFluid extends FlowableFluid { + @Override + public Fluid getFlowing() { + return SipsFluids.FLOWING_MILK; + } + + @Override + public Fluid getStill() { + return SipsFluids.MILK; + } + + @Override + public Item getBucketItem() { + return Items.MILK_BUCKET; + } + + @Environment(EnvType.CLIENT) + @Override + public void randomDisplayTick(World world, BlockPos pos, FluidState state, Random random) { + if (!state.isStill() && !state.get(FALLING)) { + if (random.nextInt(64) == 0) { + world.playSound((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, SoundEvents.BLOCK_WATER_AMBIENT, SoundCategory.BLOCKS, random.nextFloat() * 0.25F + 0.75F, random.nextFloat() + 0.5F, false); + } + } else if (random.nextInt(10) == 0) { + world.addParticle(ParticleTypes.UNDERWATER, (double) pos.getX() + random.nextDouble(), (double) pos.getY() + random.nextDouble(), (double) pos.getZ() + random.nextDouble(), 0.0D, 0.0D, 0.0D); + } + + } + + @Nullable + @Environment(EnvType.CLIENT) + @Override + public ParticleEffect getParticle() { + return ParticleTypes.DRIPPING_WATER; + } + + @Override + protected boolean isInfinite() { + return false; + } + + @Override + protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) { + BlockEntity blockEntity = state.getBlock().hasBlockEntity() ? world.getBlockEntity(pos) : null; + Block.dropStacks(state, world, pos, blockEntity); + } + + @Override + public int getFlowSpeed(WorldView world) { + return 4; + } + + @Override + public BlockState toBlockState(FluidState state) { + return SipsBlocks.MILK.getDefaultState().with(FluidBlock.LEVEL, method_15741(state)); + } + + @Override + public boolean matchesType(Fluid fluid) { + return fluid == getFlowing() || fluid == getStill(); + } + + @Override + public int getLevelDecreasePerBlock(WorldView world) { + return 1; + } + + @Override + public int getTickRate(WorldView world) { + return 5; + } + + @Override + public boolean canBeReplacedWith(FluidState state, BlockView world, BlockPos pos, Fluid fluid, Direction direction) { + return direction == Direction.DOWN && !fluid.isIn(TagRegistry.fluid(new Identifier("c:milk"))); + } + + @Override + protected float getBlastResistance() { + return 100.0F; + } + + public static class Flowing extends MilkFluid { + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder); + builder.add(LEVEL); + } + + public int getLevel(FluidState state) { + return state.get(LEVEL); + } + + public boolean isStill(FluidState state) { + return false; + } + } + + public static class Still extends MilkFluid { + public int getLevel(FluidState state) { + return 8; + } + + public boolean isStill(FluidState state) { + return true; + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/fluids/MushroomStewFluid.java b/src/main/java/mod/codewarrior/sips/fluids/MushroomStewFluid.java new file mode 100644 index 0000000..9aaf785 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/fluids/MushroomStewFluid.java @@ -0,0 +1,68 @@ +package mod.codewarrior.sips.fluids; + +import mod.codewarrior.sips.registry.SipsBlocks; +import mod.codewarrior.sips.registry.SipsFluids; +import net.fabricmc.fabric.api.tag.TagRegistry; +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidBlock; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.state.StateManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; + +public abstract class MushroomStewFluid extends MilkFluid { + @Override + public Fluid getFlowing() { + return SipsFluids.FLOWING_MUSHROOM_STEW; + } + + @Override + public Fluid getStill() { + return SipsFluids.MUSHROOM_STEW; + } + + @Override + public Item getBucketItem() { + return Items.MUSHROOM_STEW; + } + + @Override + public BlockState toBlockState(FluidState state) { + return SipsBlocks.MUSHROOM_STEW.getDefaultState().with(FluidBlock.LEVEL, method_15741(state)); + } + + @Override + public boolean canBeReplacedWith(FluidState state, BlockView world, BlockPos pos, Fluid fluid, Direction direction) { + return direction == Direction.DOWN && !fluid.isIn(TagRegistry.fluid(new Identifier("c:mushroom_stew"))); + } + + public static class Flowing extends MushroomStewFluid { + protected void appendProperties(StateManager.Builder builder) { + super.appendProperties(builder); + builder.add(LEVEL); + } + + public int getLevel(FluidState state) { + return state.get(LEVEL); + } + + public boolean isStill(FluidState state) { + return false; + } + } + + public static class Still extends MushroomStewFluid { + public int getLevel(FluidState state) { + return 8; + } + + public boolean isStill(FluidState state) { + return true; + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/fluids/SipsFluidBlock.java b/src/main/java/mod/codewarrior/sips/fluids/SipsFluidBlock.java new file mode 100644 index 0000000..95df553 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/fluids/SipsFluidBlock.java @@ -0,0 +1,10 @@ +package mod.codewarrior.sips.fluids; + +import net.minecraft.block.FluidBlock; +import net.minecraft.fluid.FlowableFluid; + +public class SipsFluidBlock extends FluidBlock { + public SipsFluidBlock(FlowableFluid fluid, Settings settings) { + super(fluid, settings); + } +} diff --git a/src/main/java/mod/codewarrior/sips/items/SipsItem.java b/src/main/java/mod/codewarrior/sips/items/SipsItem.java new file mode 100644 index 0000000..ae80e6d --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/items/SipsItem.java @@ -0,0 +1,230 @@ +package mod.codewarrior.sips.items; + +import alexiil.mc.lib.attributes.AttributeProviderItem; +import alexiil.mc.lib.attributes.ItemAttributeList; +import alexiil.mc.lib.attributes.fluid.amount.FluidAmount; +import alexiil.mc.lib.attributes.fluid.item.ItemBasedSingleFluidInv; +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import alexiil.mc.lib.attributes.fluid.volume.FluidVolume; +import alexiil.mc.lib.attributes.fluid.volume.PotionFluidKey; +import alexiil.mc.lib.attributes.misc.LimitedConsumer; +import alexiil.mc.lib.attributes.misc.Reference; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.registry.SipsFluids; +import mod.codewarrior.sips.utils.FluidUtil; +import mod.codewarrior.sips.utils.Sippable; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidDrainable; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.effect.StatusEffects; +import net.minecraft.entity.passive.CowEntity; +import net.minecraft.entity.passive.MooshroomEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.FoodComponent; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsage; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.tag.FluidTags; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.TypedActionResult; +import net.minecraft.util.UseAction; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.RaycastContext; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.math.RoundingMode; +import java.util.List; + +import static mod.codewarrior.sips.registry.SippableRegistry.SIPS; + +public class SipsItem extends Item implements AttributeProviderItem { + public final int maxCapacity; + public final int itemUseDuration; + + public SipsItem(Settings settings, int cap, int duration) { + super(settings.group(SipsMod.SipsGroup).maxCount(1).food(new FoodComponent.Builder().hunger(0).saturationModifier(0).alwaysEdible().build())); + this.maxCapacity = cap; + this.itemUseDuration = duration; + } + + @Override + public ItemStack finishUsing(ItemStack stack, World world, LivingEntity user) { + FluidKey fluid = FluidUtil.getFluid(stack); + if (fluid instanceof PotionFluidKey) { + ((PotionFluidKey) fluid).potion.getEffects().forEach(user::addStatusEffect); + } else if (user instanceof PlayerEntity) { + onSipped(fluid, (PlayerEntity) user); + } + FluidUtil.sip(stack); + return stack; + } + + protected void onSipped(FluidKey drank, PlayerEntity player) { + float damage = 0; + if (SIPS.containsKey(drank)) { + Sippable sippable = SIPS.get(drank); + player.getHungerManager().add(sippable.shanks, sippable.saturation); + + damage = sippable.damage; + sippable.effects.forEach(e -> player.addStatusEffect(e.getEffect())); + sippable.onSipped(drank, player.world, player); + } else { + //todo persuade someone (anyone) to use temperatures + double temp = drank.getTemperature() == null ? 26.85 : drank.getTemperature().getTemperature(drank.withAmount(FluidAmount.BUCKET)); + if (SipsConfig.getTemperatureDamagePerCelsius() != 0.0) { + if (temp > 46.85) { + damage = (float) (temp - 46.85) * SipsConfig.getTemperatureDamagePerCelsius(); + } else if (temp < -13.15) { + damage = (float) (-13.15 - temp) * SipsConfig.getTemperatureDamagePerCelsius(); + } + } + if (SipsConfig.useTemperatureEffects()) { + if (temp > 46.85) { + player.setOnFireFor(30); + } else { + player.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOWNESS, 30)); + player.addStatusEffect(new StatusEffectInstance(StatusEffects.MINING_FATIGUE, 30)); + } + } + } + if (damage < 0) { + player.heal(-damage); + } else if (damage > 0) { + player.damage(new DamageSource("sip") { + @Override + public Text getDeathMessage(LivingEntity entity) { + return new TranslatableText("death.sipped", entity.getDisplayName(), drank.name); + } + }, damage); + } + } + + @Override + public ActionResult useOnEntity(ItemStack stack, PlayerEntity user, LivingEntity entity, Hand hand) { + if (FluidUtil.getAmount(stack) < maxCapacity) { + if (entity instanceof CowEntity) { + FluidKey milked; + if (entity instanceof MooshroomEntity) milked = FluidKeys.get(SipsFluids.MUSHROOM_STEW); + else milked = FluidKeys.get(SipsFluids.MILK); + + if (FluidUtil.isEmpty(stack)) { + FluidUtil.setFluid(stack, milked); + } else if (FluidUtil.getFluid(stack) != milked) { + return ActionResult.PASS; + } + FluidUtil.addAmount(stack, 1000, maxCapacity); + user.world.playSound(null, user.getBlockPos(), SoundEvents.ENTITY_COW_MILK, SoundCategory.PLAYERS, 1f, user.world.random.nextFloat() * 0.1F + 0.9F); + return ActionResult.SUCCESS; + } + } + return ActionResult.PASS; + } + + @Override + public int getMaxUseTime(ItemStack stack) { + return itemUseDuration; + } + + @Override + public UseAction getUseAction(ItemStack stack) { + return UseAction.DRINK; + } + + @Override + public TypedActionResult use(World world, PlayerEntity user, Hand hand) { + ItemStack stack = user.getStackInHand(hand); + if (attemptFill(world, user, stack)) { + return TypedActionResult.success(stack, !world.isClient()); + } else if (FluidUtil.isEmpty(stack)) { + return TypedActionResult.pass(stack); + } else { + return ItemUsage.consumeHeldItem(world, user, hand); + } + } + + private boolean attemptFill(World world, PlayerEntity user, ItemStack stack) { + BlockHitResult rtr = raycast(world, user, RaycastContext.FluidHandling.SOURCE_ONLY); + if (rtr.getType() == HitResult.Type.BLOCK) { + BlockPos blockPos = rtr.getBlockPos(); + Direction direction = rtr.getSide(); + BlockPos blockPos2 = blockPos.offset(direction); + if (world.canPlayerModifyAt(user, blockPos) && user.canPlaceOn(blockPos2, direction, stack)) { + BlockState blockState; + blockState = world.getBlockState(blockPos); + if (blockState.getBlock() instanceof FluidDrainable) { + Fluid fluid = ((FluidDrainable) blockState.getBlock()).tryDrainFluid(world, blockPos, blockState); + if (fluid != Fluids.EMPTY) { + FluidKey key = FluidKeys.get(fluid); + if (FluidUtil.isEmpty(stack)) { + FluidUtil.setFluid(stack, FluidKeys.get(fluid)); + } + if (FluidUtil.getFluid(stack) == key) { + FluidUtil.addAmount(stack, 1000, maxCapacity); + } + user.playSound(fluid.isIn(FluidTags.LAVA) ? SoundEvents.ITEM_BUCKET_FILL_LAVA : SoundEvents.ITEM_BUCKET_FILL, 1.0F, 1.0F); + return true; + } + } + } + } + return false; + } + + @Override + public void addAllAttributes(Reference stack, LimitedConsumer excess, ItemAttributeList list) { + list.offer(new ItemBasedSingleFluidInv(stack, excess) { + @Override + protected boolean isInvalid(ItemStack stack) { + return false; + } + + @Override + protected HeldFluidInfo getInfo(ItemStack stack) { + return new HeldFluidInfo(FluidUtil.getFluid(stack).withAmount(FluidAmount.of(FluidUtil.getAmount(stack), 1000)), FluidAmount.of(maxCapacity, 1000)); + } + + @javax.annotation.Nullable + @Override + protected ItemStack writeToStack(ItemStack stack, FluidVolume volume) { + ItemStack c = stack.copy(); + FluidUtil.setFluid(c, volume.getFluidKey()); + FluidUtil.setAmount(c, volume.amount().asInt(1000, RoundingMode.FLOOR)); + return c; + } + }); + } + + @Environment(EnvType.CLIENT) + @Override + public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext context) { + FluidUtil.appendTooltip(stack, tooltip, 250, maxCapacity); + } + + @Override + public Text getName(ItemStack stack) { + if (SipsMod.isApril1st()) { + if (maxCapacity == SipsConfig.getBigChugCapacity()) return new LiteralText("Big Chungus"); + else return new LiteralText("Sipsi"); + } + return new TranslatableText(this.getTranslationKey(stack)); + } +} diff --git a/src/main/java/mod/codewarrior/sips/mixins/PlayerManagerMixin.java b/src/main/java/mod/codewarrior/sips/mixins/PlayerManagerMixin.java new file mode 100644 index 0000000..93fe476 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/mixins/PlayerManagerMixin.java @@ -0,0 +1,40 @@ +package mod.codewarrior.sips.mixins; + +import mod.codewarrior.sips.registry.SippableRegistry; +import net.fabricmc.fabric.api.network.ServerSidePacketRegistry; +import net.minecraft.network.ClientConnection; +import net.minecraft.network.packet.s2c.play.SynchronizeRecipesS2CPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.network.ServerPlayerEntity; +import org.spongepowered.asm.mixin.Final; +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 org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +import java.util.Iterator; + +@Mixin(PlayerManager.class) +public class PlayerManagerMixin { + + @Shadow + @Final + private MinecraftServer server; + + @Inject(method = "onDataPacksReloaded", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerRecipeBook;sendInitRecipesPacket(Lnet/minecraft/server/network/ServerPlayerEntity;)V", shift = At.Shift.AFTER), locals = LocalCapture.CAPTURE_FAILHARD) + public void sips_dispatchSippables(CallbackInfo ctx, SynchronizeRecipesS2CPacket w, Iterator var5, ServerPlayerEntity player) { + if (!this.server.isSinglePlayer()) { + ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, SippableRegistry.SIPPABLES_S2C, SippableRegistry.toPacket()); + } + } + + @Inject(method = "onPlayerConnect", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/PlayerManager;sendCommandTree(Lnet/minecraft/server/network/ServerPlayerEntity;)V", shift = At.Shift.BEFORE)) + public void sips_dispatchSippables(ClientConnection connection, ServerPlayerEntity player, CallbackInfo ctx) { + if (!this.server.isSinglePlayer()) { + ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, SippableRegistry.SIPPABLES_S2C, SippableRegistry.toPacket()); + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/registry/SippableRegistry.java b/src/main/java/mod/codewarrior/sips/registry/SippableRegistry.java new file mode 100644 index 0000000..e6c57cf --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/registry/SippableRegistry.java @@ -0,0 +1,99 @@ +package mod.codewarrior.sips.registry; + +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import com.google.gson.JsonObject; +import io.netty.buffer.Unpooled; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.utils.Sippable; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.SimpleResourceReloadListener; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; +import net.minecraft.world.World; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Collection; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; + +import static mod.codewarrior.sips.SipsMod.GSON; + +public class SippableRegistry { + public static Object2ObjectOpenHashMap SIPS = new Object2ObjectOpenHashMap<>(); + public static final Identifier SIPPABLES_S2C = SipsMod.getId("send_sippables_s2c"); + + public static void init() { + ResourceManagerHelper.get(ResourceType.SERVER_DATA).registerReloadListener(new SippablesResourceListener()); + } + + public static PacketByteBuf toPacket() { + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + buf.writeInt(SIPS.size()); + SIPS.forEach((k, v) -> { + k.toMcBuffer(buf); + v.toPacket(buf); + }); + return buf; + } + + public static void fromPacket(PacketByteBuf buf) { + SIPS.clear(); + int loop = buf.readInt(); + for (int i = 0; i < loop; i++) { + SIPS.put(FluidKey.fromMcBuffer(buf), Sippable.fromPacket(buf)); + } + } + + public static class SippablesResourceListener implements SimpleResourceReloadListener> { + + @Override + public Identifier getFabricId() { + return SipsMod.getId("sippables_resourcelistener"); + } + + @Override + public CompletableFuture> load(ResourceManager manager, Profiler profiler, Executor executor) { + return CompletableFuture.supplyAsync(() -> { + SIPS.clear(); + return manager.findResources("sippables", s -> SipsConfig.loadDefaultSippables() + ? s.endsWith(".json") + : s.endsWith(".json") && !s.contains("default_sippables")); + }, executor); + } + + @Override + public CompletableFuture apply(Collection collection, ResourceManager manager, Profiler profiler, Executor executor) { + return CompletableFuture.runAsync(() -> { + collection.forEach(id -> { + try { + InputStream is = manager.getResource(id).getInputStream(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + JsonObject json = GSON.fromJson(br, JsonObject.class); + json.entrySet().forEach(Sippable::fromConfig); + } catch (IOException e) { + SipsMod.LOGGER.error("Caught exception during Sippables parsing: " + e); + } + }); + + //manual + if (SipsConfig.liquidXpHasEffect()) { + Sippable.fromPredicate("liquid_xp", new Sippable() { + @Override + public void onSipped(FluidKey drank, World world, PlayerEntity player) { + player.addExperience(7 + world.random.nextInt(5)); + } + }); + } + }, executor); + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/registry/SipsBlocks.java b/src/main/java/mod/codewarrior/sips/registry/SipsBlocks.java new file mode 100644 index 0000000..c434a7e --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/registry/SipsBlocks.java @@ -0,0 +1,22 @@ +package mod.codewarrior.sips.registry; + +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.fluids.SipsFluidBlock; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.Blocks; +import net.minecraft.util.registry.Registry; + +public class SipsBlocks { + public static Block MILK = new SipsFluidBlock(SipsFluids.MILK, AbstractBlock.Settings.copy(Blocks.WATER)); + public static Block MUSHROOM_STEW = new SipsFluidBlock(SipsFluids.MUSHROOM_STEW, AbstractBlock.Settings.copy(Blocks.WATER)); + + public static void init() { + subRegister("milk", MILK); + subRegister("mushroom_stew", MUSHROOM_STEW); + } + + public static void subRegister(String id, Block block) { + Registry.register(Registry.BLOCK, SipsMod.getId(id), block); + } +} diff --git a/src/main/java/mod/codewarrior/sips/registry/SipsEffects.java b/src/main/java/mod/codewarrior/sips/registry/SipsEffects.java new file mode 100644 index 0000000..9c33be3 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/registry/SipsEffects.java @@ -0,0 +1,24 @@ +package mod.codewarrior.sips.registry; + +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.effects.LavaDigestionEffect; +import mod.codewarrior.sips.effects.PurgeEffect; +import mod.codewarrior.sips.effects.ThermodynamicsEffect; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.util.registry.Registry; + +public class SipsEffects { + public static final StatusEffect PURGE = new PurgeEffect(); + public static final StatusEffect LAVA_DIGESTION = new LavaDigestionEffect(); + public static final StatusEffect THERMODYNAMICS = new ThermodynamicsEffect(); + + public static void init() { + register("purge", PURGE); + register("lava_digestion", LAVA_DIGESTION); + register("thermodynamics", THERMODYNAMICS); + } + + private static void register(String id, StatusEffect effect) { + Registry.register(Registry.STATUS_EFFECT, SipsMod.getId(id), effect); + } +} diff --git a/src/main/java/mod/codewarrior/sips/registry/SipsEvents.java b/src/main/java/mod/codewarrior/sips/registry/SipsEvents.java new file mode 100644 index 0000000..2bb3e1b --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/registry/SipsEvents.java @@ -0,0 +1,44 @@ +package mod.codewarrior.sips.registry; + +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.block.Block; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.*; +import net.minecraft.sound.SoundCategory; +import net.minecraft.sound.SoundEvents; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class SipsEvents { + public static void init() { + UseBlockCallback.EVENT.register(((player, world, hand, rtr) -> { + ItemStack stack = player.getStackInHand(hand); + BlockPos pos = rtr.getBlockPos().offset(rtr.getSide()); + if (player.isSneaking()) { + if (stack.getItem() instanceof MilkBucketItem && world.getBlockState(pos).canBucketPlace(SipsFluids.MILK)) { + return handleFluid(player, world, hand, pos, stack, Items.BUCKET, SipsBlocks.MILK); + } else if (stack.getItem() instanceof MushroomStewItem && world.getBlockState(pos).canBucketPlace(SipsFluids.MUSHROOM_STEW)) { + return handleFluid(player, world, hand, pos, stack, Items.BOWL, SipsBlocks.MUSHROOM_STEW); + } + } + return ActionResult.PASS; + })); + } + + public static ActionResult handleFluid(PlayerEntity player, World world, Hand hand, BlockPos pos, ItemStack stack, Item empty, Block toPlace) { + if (!player.abilities.creativeMode) { + stack.decrement(1); + ItemStack e = new ItemStack(empty); + if (stack.isEmpty()) { + player.setStackInHand(hand, e); + } else { + player.inventory.offerOrDrop(world, e); + } + } + world.setBlockState(pos, toPlace.getDefaultState()); + world.playSound(null, pos, SoundEvents.ITEM_BUCKET_EMPTY, SoundCategory.BLOCKS, 1.0F, 1.0F); + return ActionResult.SUCCESS; + } +} \ No newline at end of file diff --git a/src/main/java/mod/codewarrior/sips/registry/SipsFluids.java b/src/main/java/mod/codewarrior/sips/registry/SipsFluids.java new file mode 100644 index 0000000..ca1e3c7 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/registry/SipsFluids.java @@ -0,0 +1,36 @@ +package mod.codewarrior.sips.registry; + +import alexiil.mc.lib.attributes.fluid.FluidContainerRegistry; +import alexiil.mc.lib.attributes.fluid.amount.FluidAmount; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.fluids.MilkFluid; +import mod.codewarrior.sips.fluids.MushroomStewFluid; +import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.Fluid; +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.util.registry.Registry; + +public class SipsFluids { + public static final FlowableFluid FLOWING_MILK = new MilkFluid.Flowing(); + public static final FlowableFluid MILK = new MilkFluid.Still(); + public static final FlowableFluid FLOWING_MUSHROOM_STEW = new MushroomStewFluid.Flowing(); + public static final FlowableFluid MUSHROOM_STEW = new MushroomStewFluid.Still(); + + public static void init() { + register("flowing_milk", FLOWING_MILK); + register("milk", MILK, Items.BUCKET, Items.MILK_BUCKET); + register("flowing_mushroom_stew", FLOWING_MUSHROOM_STEW); + register("mushroom_stew", MUSHROOM_STEW, Items.BOWL, Items.MUSHROOM_STEW); + } + + private static void register(String id, Fluid value) { + Registry.register(Registry.FLUID, SipsMod.getId(id), value); + } + + private static void register(String id, Fluid value, Item empty, Item full) { + register(id, value); + FluidContainerRegistry.mapContainer(empty, full, FluidKeys.get(value).withAmount(FluidAmount.BUCKET)); + } +} diff --git a/src/main/java/mod/codewarrior/sips/registry/SipsItems.java b/src/main/java/mod/codewarrior/sips/registry/SipsItems.java new file mode 100644 index 0000000..4d08a6b --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/registry/SipsItems.java @@ -0,0 +1,21 @@ +package mod.codewarrior.sips.registry; + +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.config.SipsConfig; +import mod.codewarrior.sips.items.SipsItem; +import net.minecraft.item.Item; +import net.minecraft.util.registry.Registry; + +public class SipsItems { + public static Item LIL_SIP = new SipsItem(new Item.Settings(), SipsConfig.getLilSipCapacity(), 32); + public static Item BIG_CHUG = new SipsItem(new Item.Settings(), SipsConfig.getBigChugCapacity(), 16); + + public static void init() { + register("lil_sip", LIL_SIP); + register("big_chug", BIG_CHUG); + } + + public static void register(String name, Item item) { + Registry.register(Registry.ITEM, SipsMod.getId(name), item); + } +} diff --git a/src/main/java/mod/codewarrior/sips/utils/FluidUtil.java b/src/main/java/mod/codewarrior/sips/utils/FluidUtil.java new file mode 100644 index 0000000..2e681f7 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/utils/FluidUtil.java @@ -0,0 +1,85 @@ +package mod.codewarrior.sips.utils; + +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import alexiil.mc.lib.attributes.fluid.volume.PotionFluidKey; +import mod.codewarrior.sips.items.SipsItem; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.potion.PotionUtil; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; + +import java.util.List; + +public interface FluidUtil { + + static boolean isEmpty(ItemStack stack) { + return stack.getSubTag("fluid") == null; + } + + static FluidKey getFluid(ItemStack stack) { + return isEmpty(stack) ? FluidKeys.EMPTY : FluidKey.fromTag(stack.getSubTag("fluid")); + } + + static void setFluid(ItemStack stack, FluidKey fluid) { + stack.getOrCreateTag().put("fluid", fluid.toTag()); + } + + static int getAmount(ItemStack stack) { + if (stack.getTag() != null) { + return stack.getTag().getInt("amount"); + } else { + return 0; + } + } + + static void addAmount(ItemStack stack, int amount, int max) { + setAmount(stack, Math.min(getAmount(stack) + amount, max)); + } + + static void setAmount(ItemStack stack, int amount) { + if (amount != 0) { + stack.getOrCreateTag().putInt("amount", amount); + } else { + stack.removeSubTag("amount"); + stack.removeSubTag("fluid"); + } + } + + static int getMaxCapacity(ItemStack stack) { + return stack.getItem() instanceof SipsItem ? ((SipsItem) stack.getItem()).maxCapacity : 0; + } + + static void sip(ItemStack stack) { + int amount = getAmount(stack); + if (amount > 249) { + setAmount(stack, amount - 250); + } + } + + @Environment(EnvType.CLIENT) + static void appendTooltip(ItemStack stack, List tooltip, int sip, int max) { + FluidKey fluid = getFluid(stack); + if (!fluid.isEmpty()) { + if (fluid instanceof PotionFluidKey) { + PotionFluidKey pot = (PotionFluidKey) fluid; + PotionUtil.buildTooltip(PotionUtil.setPotion(new ItemStack(Items.POTION), pot.potion), tooltip, 1f); + } else { + tooltip.add(fluid.name); + } + if (Screen.hasShiftDown()) { + tooltip.add(new TranslatableText("desc.sips.amount", getAmount(stack), max).formatted(Formatting.GRAY, Formatting.ITALIC)); + } else { + int amt = getAmount(stack) / sip; + tooltip.add(new TranslatableText("desc.sips.sips", amt).formatted(Formatting.GRAY, Formatting.ITALIC)); + } + } else { + tooltip.add(new TranslatableText("desc.sips.empty").formatted(Formatting.DARK_GRAY, Formatting.ITALIC)); + } + } +} diff --git a/src/main/java/mod/codewarrior/sips/utils/LRUCache.java b/src/main/java/mod/codewarrior/sips/utils/LRUCache.java new file mode 100644 index 0000000..1741a09 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/utils/LRUCache.java @@ -0,0 +1,95 @@ +package mod.codewarrior.sips.utils; + +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + +public class LRUCache { + LRUNode head; + LRUNode tail; + Object2ObjectOpenHashMap> map; + int cap; + + public LRUCache(int capacity) { + this.cap = capacity; + this.map = new Object2ObjectOpenHashMap<>(); + } + + public T get(R key) { + if (map.get(key) == null) { + return null; + } + + //move to tail + LRUNode t = map.get(key); + + removeNode(t); + offerNode(t); + + return t.value; + } + + public void put(R key, T value) { + if (map.containsKey(key)) { + LRUNode t = map.get(key); + t.value = value; + + //move to tail + removeNode(t); + offerNode(t); + } else { + if (map.size() >= cap) { + //delete head + map.remove(head.key); + removeNode(head); + } + + //add to tail + LRUNode node = new LRUNode<>(key, value); + offerNode(node); + map.put(key, node); + } + } + + public void remove(R key) { + map.remove(key); + } + + private void removeNode(LRUNode n) { + if (n.prev != null) { + n.prev.next = n.next; + } else { + head = n.next; + } + + if (n.next != null) { + n.next.prev = n.prev; + } else { + tail = n.prev; + } + } + + private void offerNode(LRUNode n) { + if (tail != null) { + tail.next = n; + } + + n.prev = tail; + n.next = null; + tail = n; + + if (head == null) { + head = tail; + } + } + + private static class LRUNode { + R key; + T value; + LRUNode prev; + LRUNode next; + + public LRUNode(R key, T value) { + this.key = key; + this.value = value; + } + } +} \ No newline at end of file diff --git a/src/main/java/mod/codewarrior/sips/utils/RomanConverter.java b/src/main/java/mod/codewarrior/sips/utils/RomanConverter.java new file mode 100644 index 0000000..5cc9fa3 --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/utils/RomanConverter.java @@ -0,0 +1,32 @@ +package mod.codewarrior.sips.utils; + +import java.util.TreeMap; + +public class RomanConverter { + private final static TreeMap map = new TreeMap<>(); + + static { + map.put(1000, "M"); + map.put(900, "CM"); + map.put(500, "D"); + map.put(400, "CD"); + map.put(100, "C"); + map.put(90, "XC"); + map.put(50, "L"); + map.put(40, "XL"); + map.put(10, "X"); + map.put(9, "IX"); + map.put(5, "V"); + map.put(4, "IV"); + map.put(1, "I"); + } + + public static String toRoman(int number) { + int l = map.floorKey(number); + if (number == l) { + return map.get(number); + } + return map.get(l) + toRoman(number - l); + } + +} diff --git a/src/main/java/mod/codewarrior/sips/utils/Sippable.java b/src/main/java/mod/codewarrior/sips/utils/Sippable.java new file mode 100644 index 0000000..4d09a7d --- /dev/null +++ b/src/main/java/mod/codewarrior/sips/utils/Sippable.java @@ -0,0 +1,261 @@ +package mod.codewarrior.sips.utils; + +import alexiil.mc.lib.attributes.fluid.volume.FluidKey; +import alexiil.mc.lib.attributes.fluid.volume.FluidKeys; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import mod.codewarrior.sips.SipsMod; +import mod.codewarrior.sips.registry.SippableRegistry; +import net.minecraft.entity.effect.StatusEffect; +import net.minecraft.entity.effect.StatusEffectInstance; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.tag.ServerTagManagerHolder; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class Sippable { + public static final Sippable UNDEFINED = new Sippable(0, 0, 0); + + public int shanks = 0; + public float saturation = 0f; + public float damage = 0.0f; + + public List effects = new ArrayList<>(); + + public Sippable() { /*override onSipped()*/ } + + public Sippable(int shanks, float saturation, float damage) { + this.shanks = shanks; + this.saturation = saturation; + this.damage = damage; + } + + public Sippable(int shanks, float saturation, float damage, List effects) { + this.shanks = shanks; + this.saturation = saturation; + this.damage = damage; + this.effects.addAll(effects); + } + + public static void fromConfig(Map.Entry entry) { + if (!entry.getValue().isJsonObject()) { + SipsMod.LOGGER.error(entry + " is not a JsonObject!"); + return; + } + JsonObject o = entry.getValue().getAsJsonObject(); + String sid = entry.getKey(); + boolean isTag = false; + boolean heuristics = false; + if (sid.charAt(0) == '#') { + isTag = true; + sid = sid.substring(1); + } else if (!sid.contains(":")) { + heuristics = true; + } + int shanks = 0; + float saturation = 0; + float damage = 0; + + if (o.has("hunger")) { + try { + shanks = Integer.parseInt(o.get("hunger").getAsString()); + } catch (NumberFormatException e) { + SipsMod.LOGGER.error("Could not parse hunger integer '{}' in fluid stats '{}'", o.get("hunger"), o); + return; + } + } + if (o.has("saturation")) { + try { + saturation = Float.parseFloat(o.get("saturation").getAsString()); + } catch (NumberFormatException e) { + SipsMod.LOGGER.error("Could not parse saturation float '{}' in fluid stats '{}'", o.get("saturation"), o); + return; + } + } + if (o.has("damage")) { + try { + damage = Float.parseFloat(o.get("damage").getAsString()); + } catch (NumberFormatException e) { + SipsMod.LOGGER.error("Could not parse damage float '{}' in fluid stats '{}'", o.get("damage"), o); + return; + } + } + + List effects = new ArrayList<>(); + + if (o.get("effects") != null) { + JsonObject fx = o.getAsJsonObject("effects"); + fx.entrySet().forEach(effect -> { + Effect e = parseEffect(effect); + if (e != null) effects.add(e); + }); + } + + Identifier id = new Identifier(sid); + Sippable sippable = new Sippable(shanks, saturation, damage, effects); + if (isTag) { + fromTag(id, sippable); + } else if (heuristics) { + fromPredicate(sid, sippable); + } else { + Fluid f = Registry.FLUID.get(id); + if (f != Fluids.EMPTY) { + FluidKey fluidKey = FluidKeys.get(f); + SippableRegistry.SIPS.put(fluidKey, sippable); + } + } + } + + public static void fromTag(Identifier id, Sippable sippable) { + Tag tag = ServerTagManagerHolder.getTagManager().getFluids().getTag(id); + if (tag != null && !tag.values().isEmpty()) { + tag.values().forEach(fluid -> { + if (fluid != Fluids.EMPTY) { + FluidKey key = FluidKeys.get(fluid); + SippableRegistry.SIPS.put(key, sippable); + } + }); + } + } + + public static void fromPredicate(String predicate, Sippable sippable) { + Registry.FLUID.forEach(fluid -> { + if (Registry.FLUID.getId(fluid).getPath().equals(predicate)) { + FluidKey key = FluidKeys.get(fluid); + SippableRegistry.SIPS.put(key, sippable); + } + }); + } + + public static Sippable fromPacket(PacketByteBuf buf) { + int shanks = buf.readInt(); + float saturation = buf.readFloat(); + float damage = buf.readFloat(); + int loop = buf.readInt(); + List effects = new ArrayList<>(); + for (int i = 0; i < loop; i++) { + effects.add(Effect.fromPacket(buf)); + } + return new Sippable(shanks, saturation, damage, effects); + } + + public void toPacket(PacketByteBuf buf) { + buf.writeInt(this.shanks); + buf.writeFloat(this.saturation); + buf.writeFloat(this.damage); + buf.writeInt(this.effects.size()); + this.effects.forEach(e -> e.toPacket(buf)); + } + + public static Effect parseEffect(Map.Entry effect) { + Identifier name; + int duration = 1; + int level = 0; + boolean showParticles = true; + boolean showIcon = true; + + name = new Identifier(effect.getKey()); + JsonObject o = effect.getValue().getAsJsonObject(); + if (o.has("duration")) { + try { + int mult = 1; + String durationTxt = o.get("duration").getAsString(); + if (durationTxt.endsWith("s")) { + mult = 20; + durationTxt = durationTxt.substring(0, durationTxt.length() - 1); + } else if (durationTxt.endsWith("m")) { + mult = 20 * 60; + durationTxt = durationTxt.substring(0, durationTxt.length() - 1); + } else if (durationTxt.endsWith("h")) { + mult = 20 * 60 * 60; + durationTxt = durationTxt.substring(0, durationTxt.length() - 1); + } else if (durationTxt.endsWith("t")) { /* somebody might try this */ + mult = 1; + durationTxt = durationTxt.substring(0, durationTxt.length() - 1); + } + + duration = Integer.parseInt(durationTxt) * mult; + } catch (NumberFormatException e) { + SipsMod.LOGGER.error("Could not parse potion duration integer '{}' in fluid stats '{}'", o.get("duration"), o); + return null; + } + } + + if (o.has("level")) { + try { + level = Integer.parseInt(o.get("level").getAsString()); + } catch (NumberFormatException e) { + SipsMod.LOGGER.error("Could not parse potion level integer '{}' in fluid stats '{}'", o.get("level"), o); + return null; + } + } + + if (o.has("showParticles")) { + try { + showParticles = o.get("showParticles").getAsBoolean(); + } catch (Exception e) { + SipsMod.LOGGER.error("Could not parse potion showParticles boolean '{}' in fluid stats '{}'", o.get("showParticles"), o); + } + } + + if (o.has("showIcon")) { + try { + showIcon = o.get("showIcon").getAsBoolean(); + } catch (Exception e) { + SipsMod.LOGGER.error("Could not parse potion showIcon boolean '{}' in fluid stats '{}'", o.get("showIcon"), o); + } + } + return new Effect(name, duration, level, showParticles, showIcon); + } + + public void onSipped(FluidKey drank, World world, PlayerEntity player) { + + } + + public static class Effect { + Identifier name; + int duration; + int level; + boolean showParticles; + boolean showIcon; + + public Effect(Identifier name, int duration, int level, boolean showParticles, boolean showIcon) { + this.name = name; + this.duration = duration; + this.level = level; + this.showParticles = showParticles; + this.showIcon = showIcon; + } + + public StatusEffectInstance getEffect() { + StatusEffect potion = Registry.STATUS_EFFECT.get(name); + if (potion != null) { + return new StatusEffectInstance(potion, duration, level, false, showParticles, showIcon); + } + return null; + } + + public static Effect fromPacket(@NotNull PacketByteBuf buf) { + Identifier name = buf.readIdentifier(); + int duration = buf.readInt(); + int level = buf.readInt(); + return new Effect(name, duration, level, false, false); + } + + public void toPacket(@NotNull PacketByteBuf buf) { + buf.writeIdentifier(name); + buf.writeInt(duration); + buf.writeInt(level); + } + } +} diff --git a/src/main/resources/assets/sips/blockstates/milk.json b/src/main/resources/assets/sips/blockstates/milk.json new file mode 100644 index 0000000..93b80f9 --- /dev/null +++ b/src/main/resources/assets/sips/blockstates/milk.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "sips:block/milk" + } + } +} diff --git a/src/main/resources/assets/sips/blockstates/mushroom_stew.json b/src/main/resources/assets/sips/blockstates/mushroom_stew.json new file mode 100644 index 0000000..4c9906a --- /dev/null +++ b/src/main/resources/assets/sips/blockstates/mushroom_stew.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "sips:block/mushroom_stew" + } + } +} diff --git a/src/main/resources/assets/sips/icon.png b/src/main/resources/assets/sips/icon.png new file mode 100644 index 0000000..f3c73ed Binary files /dev/null and b/src/main/resources/assets/sips/icon.png differ diff --git a/src/main/resources/assets/sips/lang/en_us.json b/src/main/resources/assets/sips/lang/en_us.json new file mode 100644 index 0000000..eea3089 --- /dev/null +++ b/src/main/resources/assets/sips/lang/en_us.json @@ -0,0 +1,64 @@ +{ + "itemGroup.sips.sips": "Sips", + "item.sips.lil_sip": "Lil Sip", + "item.sips.big_chug": "Big Chug", + "block.sips.milk": "Milk", + "block.sips.mushroom_stew": "Mushroom Stew", + "desc.sips.empty": "Empty. Right-click on an LBA Tank, fluid block, or Cow to fill.", + "desc.sips.sips": "%d sips.", + "desc.sips.amount": "%d/%d mL", + "effect.sips.purge": "Purge", + "effect.sips.lava_digestion": "Lava Digestion", + "effect.sips.thermodynamics": "Thermodynamics", + "death.sipped": "%s took a lethal sip of %s.", + "rei.sips.category": "Sippable Beverages", + "rei.sips.show_category": "Show Entire Category", + "rei.sips.quote0": "Twice as much for a nickel!", + "rei.sips.quote1": "More bounce to the ounce!", + "rei.sips.quote2": "Any weather is Sips weather!", + "rei.sips.quote3": "Say Sips, please!", + "rei.sips.quote4": "Now it's Sips for those who think young!", + "rei.sips.quote5": "Come alive, you're in the Sips generation!", + "rei.sips.quote6": "Taste that beats the others cold. Sips pours it on!", + "rei.sips.quote7": "You've got a lot to live, and Sips's got a lot to give!", + "rei.sips.quote8": "Join the Sips people feeling free!", + "rei.sips.quote9": "Catch that Sips spirit!", + "rei.sips.quote10": "Sips's got your taste for life!", + "rei.sips.quote11": "Sips now! Take the challenge!", + "rei.sips.quote12": "Sips: The choice of a new generation!", + "rei.sips.quote13": "Sips: A generation ahead!", + "rei.sips.quote14": "Gotta have it! Chill out!", + "rei.sips.quote15": "The choice is yours!", + "rei.sips.quote16": "Be young, have fun, drink Sips!", + "rei.sips.quote17": "Right now!", + "rei.sips.quote18": "Nothing else is a Sip!", + "rei.sips.quote19": "Drink Sips, get stuff!", + "rei.sips.quote20": "For those who think young: the joy of Sips!", + "rei.sips.quote21": "Something for everyone!", + "rei.sips.quote22": "Every Sip refreshes the world!", + "rei.sips.quote23": "Summertime is Sips time!", + "rei.sips.quote24": "Where there's Sips, there's music!", + "rei.sips.quote25": "Live for now!", + "rei.sips.quote26": "Change the game!", + "rei.sips.quote27": "The best drank created worldwide!", + "rei.sips.quote28": "You like it, it likes you!", + "rei.sips.quote29": "The fresh-up family Sips!", + "rei.sips.quote30": "Nothing does it like Sips!", + "rei.sips.quote31": "Crisp, refreshing Sips!", + "rei.sips.quote32": "Feelin' Sips!", + "rei.sips.quote33": "Put some Sips in your life!", + "rei.sips.quote34": "Now that's refreshing!", + "rei.sips.quote35": "It's a Sips thing!", + "rei.sips.quote36": "Several flavors in one Sip!", + "rei.sips.quote37": "Be yourself! Be refreshing! Be with Sips!", + "rei.sips.quote38": "Sips. Have fun with taste!", + "rei.sips.quote39": "Life is good when you take Sips!", + "rei.sips.quote40": "Sips. A tasteful explosion!", + "rei.sips.quote41": "Reach for the sun, reach for a Sip!", + "rei.sips.quote42": "Do you Sip? We Sip!", + "rei.sips.quote43": "Do you have a little Sip in you?", + "rei.sips.quote44": "Sip responsibly!", + "rei.sips.quote45": "Sips! It'll tickle your innards!", + "rei.sips.quote46": "There's a bang in every Sip!", + "rei.sips.quote47": "Sips. The Thirst Quencher!" +} \ No newline at end of file diff --git a/src/main/resources/assets/sips/models/block/milk.json b/src/main/resources/assets/sips/models/block/milk.json new file mode 100644 index 0000000..7ead0a4 --- /dev/null +++ b/src/main/resources/assets/sips/models/block/milk.json @@ -0,0 +1,6 @@ +{ + "textures": { + "particle": "sips:block/fluid/milk_still" + } +} + diff --git a/src/main/resources/assets/sips/models/block/mushroom_stew.json b/src/main/resources/assets/sips/models/block/mushroom_stew.json new file mode 100644 index 0000000..54f42e7 --- /dev/null +++ b/src/main/resources/assets/sips/models/block/mushroom_stew.json @@ -0,0 +1,6 @@ +{ + "textures": { + "particle": "sips:block/fluid/mushroom_stew_still" + } +} + diff --git a/src/main/resources/assets/sips/models/item/big_chug_2d.json b/src/main/resources/assets/sips/models/item/big_chug_2d.json new file mode 100644 index 0000000..ca44c2b --- /dev/null +++ b/src/main/resources/assets/sips/models/item/big_chug_2d.json @@ -0,0 +1,25 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "sips:item/big_chug" + }, + "display": { + "head": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0, + 13, + 7 + ], + "scale": [ + 1, + 1, + 1 + ] + } + } +} diff --git a/src/main/resources/assets/sips/models/item/big_chug_3d.json b/src/main/resources/assets/sips/models/item/big_chug_3d.json new file mode 100644 index 0000000..15db069 --- /dev/null +++ b/src/main/resources/assets/sips/models/item/big_chug_3d.json @@ -0,0 +1,2916 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "sips:item/big_chug_3d", + "particle": "sips:item/big_chug_3d" + }, + "elements": [ + { + "from": [ + 6, + 0.3, + 4 + ], + "to": [ + 10, + 1.3, + 12 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 10, + 0.3, + 6 + ], + "to": [ + 12, + 1.3, + 10 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 4, + 0.3, + 6 + ], + "to": [ + 6, + 1.3, + 10 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 10, + 0.3, + 4.8 + ], + "to": [ + 11.2, + 1.3, + 6 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 10, + 0.3, + 10 + ], + "to": [ + 11.2, + 1.3, + 11.2 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 4.8, + 0.3, + 10 + ], + "to": [ + 6, + 1.3, + 11.2 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 4.8, + 0.3, + 4.8 + ], + "to": [ + 6, + 1.3, + 6 + ], + "faces": { + "north": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 0.5, + 1, + 1 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9.5, + 0.5, + 10, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 0.5, + 10.5, + 1 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 6.01812, + -0.00001, + 3.518 + ], + "to": [ + 10.01812, + 1.99999, + 4.518 + ], + "faces": { + "north": { + "uv": [ + 1.5, + 14, + 6, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 1.5, + 15, + 6, + 15.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 6.01813, + 0.00021, + 11.48166 + ], + "to": [ + 10.01813, + 2.00021, + 12.48166 + ], + "faces": { + "north": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 1, + 14, + 5.5, + 16 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 2, + 15, + 6.5, + 15.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 11.50007, + 0.00026, + 5.99968 + ], + "to": [ + 12.50007, + 2.00026, + 9.99968 + ], + "faces": { + "north": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 3.5, + 14, + 8, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 2, + 15, + 6.5, + 15.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 3.53622, + 0.00007, + 5.99982 + ], + "to": [ + 4.53622, + 2.00007, + 9.99982 + ], + "faces": { + "north": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 1, + 14, + 5.5, + 16 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 2, + 15, + 6.5, + 15.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 6.27635, + 0.00001, + 3.41514 + ], + "to": [ + 9.78635, + 1.99001, + 4.41514 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.02635, + 10.99001, + 8.01514 + ] + }, + "faces": { + "north": { + "uv": [ + 0.5, + 14, + 3.2999, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 1.5, + 15, + 5.00956, + 15.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 3.43342, + 0.00015, + 6.23156 + ], + "to": [ + 4.43342, + 1.99015, + 9.74156 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.03342, + 10.99015, + 7.99156 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0.5, + 14, + 3.29947, + 16 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 2, + 15, + 4.7999, + 15.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 11.60994, + 0.00026, + 6.23442 + ], + "to": [ + 12.60994, + 1.99026, + 9.74442 + ], + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8.00994, + 10.99026, + 7.98442 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0.5, + 14, + 3.29947, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 2, + 15, + 4.7999, + 15.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 11.60283, + -0.00001, + 6.25816 + ], + "to": [ + 12.60283, + 1.98999, + 9.76816 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.00283, + 10.98999, + 8.00816 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 3, + 14, + 5.7999, + 16 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 14, + 0.5, + 16 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 0.5, + 14.5, + 3.2999, + 15.00955 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "from": [ + 6.02017, + 2, + 4.02003 + ], + "to": [ + 10.02017, + 9, + 5.02003 + ], + "faces": { + "north": { + "uv": [ + 9, + 8, + 13, + 15.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 7, + 0.5, + 7.5, + 1 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 7, + 0.5, + 7.5, + 1 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 3, + 0, + 7, + 0.5 + ], + "rotation": 180, + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 4.04029, + 2.00011, + 5.99981 + ], + "to": [ + 5.04029, + 9.00011, + 9.99981 + ], + "faces": { + "north": { + "uv": [ + 7, + 0.5, + 7.5, + 1 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 2.5, + 10.5, + 3 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 1.5, + 8, + 5.5, + 15.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 7.5, + 0, + 8, + 3 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 6.02013, + 2.00024, + 10.97963 + ], + "to": [ + 10.02013, + 9.00024, + 11.97963 + ], + "faces": { + "north": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 7, + 0.5, + 7.5, + 1 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 13, + 8, + 9, + 15.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 7, + 0.5, + 7.5, + 1 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 1.5, + 7.5, + 4.5, + 8 + ], + "rotation": 180, + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 11, + 2, + 6 + ], + "to": [ + 12, + 9, + 10 + ], + "faces": { + "north": { + "uv": [ + 10, + 2.5, + 10.5, + 3 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 1.5, + 8, + 5.5, + 15.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 7, + 0.5, + 7.5, + 1 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 8, + 0.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 6.62837, + 2.00004, + 3.76806 + ], + "to": [ + 9.42837, + 8.99804, + 4.76806 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.02837, + 11.00004, + 8.00806 + ] + }, + "faces": { + "north": { + "uv": [ + 5, + 8, + 9, + 15.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 6.5, + 0.5, + 7.79991 + ], + "rotation": 270, + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 11.25195, + 2, + 6.60815 + ], + "to": [ + 12.25195, + 8.998, + 9.40815 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.01195, + 11, + 8.00815 + ] + }, + "faces": { + "north": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 5, + 8, + 9, + 15.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 0.5, + 3.29906 + ], + "rotation": 180, + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 3.78835, + 2.00017, + 6.59158 + ], + "to": [ + 4.78835, + 8.99817, + 9.39158 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.02835, + 11.00017, + 7.99158 + ] + }, + "faces": { + "north": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 9.5, + 8, + 5.5, + 15.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 7.5, + 2.5, + 8, + 5.29992 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 6.61194, + 2.00028, + 11.23152 + ], + "to": [ + 9.41194, + 8.99828, + 12.23152 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.01194, + 11.00028, + 7.99152 + ] + }, + "faces": { + "north": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 9.5, + 8, + 5.5, + 15.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 7.5, + 3, + 8 + ], + "rotation": 180, + "texture": "#0" + }, + "down": { + "uv": [ + 10, + 1, + 12.5, + 2 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 2.75422, + 6.99422, + 7.01 + ], + "to": [ + 4.75422, + 7.99422, + 8.99 + ], + "faces": { + "north": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 0, + 2, + 1 + ], + "texture": "#missing" + }, + "south": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 0, + 2, + 1 + ], + "texture": "#missing" + }, + "up": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 1.76201, + 2.855, + 6.99996 + ], + "to": [ + 2.76201, + 4.855, + 8.99996 + ], + "rotation": { + "angle": 45, + "axis": "z", + "origin": [ + 2.70377, + 3.86813, + 7.99996 + ] + }, + "faces": { + "north": { + "uv": [ + 15, + 5, + 15.5, + 5.5 + ], + "rotation": 270, + "texture": "#0" + }, + "east": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 0, + 2, + 1 + ], + "rotation": 90, + "texture": "#missing" + } + } + }, + { + "from": [ + 1.34, + 3.9, + 7 + ], + "to": [ + 2.34, + 6.58, + 9 + ], + "faces": { + "north": { + "uv": [ + 15.5, + 3, + 16, + 3.5 + ], + "rotation": 180, + "texture": "#0" + }, + "east": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "from": [ + 2.7542, + 2.48583, + 7.01 + ], + "to": [ + 4.7542, + 3.48583, + 8.99 + ], + "faces": { + "north": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 0, + 2, + 1 + ], + "texture": "#missing" + }, + "south": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 14, + 2, + 14.5, + 2.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 5.00095, + 2.57831, + 7 + ], + "to": [ + 6.00095, + 4.57831, + 9 + ], + "rotation": { + "angle": -45, + "axis": "z", + "origin": [ + 8.00095, + 8.99831, + 8 + ] + }, + "faces": { + "north": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "east": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "south": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "west": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "up": { + "uv": [ + 14.5, + 2, + 15.5, + 2.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 0, + 2, + 1 + ], + "rotation": 270, + "texture": "#missing" + } + } + }, + { + "from": [ + 6.01806, + 8.75002, + 3.50277 + ], + "to": [ + 10.01806, + 9.25002, + 4.00277 + ], + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 6.01805, + 8.75, + 11.96648 + ], + "to": [ + 10.01805, + 9.25, + 12.46648 + ], + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 12, + 8.75, + 5.98481 + ], + "to": [ + 12.5, + 9.25, + 9.98481 + ], + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 3.53611, + 8.75, + 5.98463 + ], + "to": [ + 4.03611, + 9.25, + 9.98463 + ], + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 6.27624, + 8.7499, + 3.39993 + ], + "to": [ + 9.78624, + 9.2499, + 3.89993 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.02624, + 21.00007, + 7.99993 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 3.43331, + 8.7499, + 6.2164 + ], + "to": [ + 3.93331, + 9.2499, + 9.7264 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.03331, + 21.00016, + 7.9764 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 2, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 12.10987, + 8.7499, + 6.21956 + ], + "to": [ + 12.60987, + 9.2499, + 9.72956 + ], + "rotation": { + "angle": -45, + "axis": "y", + "origin": [ + 8.00987, + 20.99993, + 7.96956 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + }, + { + "from": [ + 12.1028, + 8.7499, + 6.2429 + ], + "to": [ + 12.6028, + 9.2489, + 9.7529 + ], + "rotation": { + "angle": 45, + "axis": "y", + "origin": [ + 8.0028, + 21.00102, + 7.9929 + ] + }, + "faces": { + "north": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 8, + 0.5, + 8.5 + ], + "texture": "#0" + } + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [ + 65, + 90, + 0 + ], + "translation": [ + 0, + 4, + 1 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + }, + "thirdperson_lefthand": { + "rotation": [ + 65, + -90, + 0 + ], + "translation": [ + 0, + 4, + 1 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + }, + "firstperson_righthand": { + "rotation": [ + -10, + 120, + -5 + ], + "translation": [ + 1, + 4.25, + -1 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + }, + "firstperson_lefthand": { + "rotation": [ + -10, + -60, + 5 + ], + "translation": [ + 1, + 4.25, + -1 + ], + "scale": [ + 0.8, + 0.8, + 0.8 + ] + }, + "ground": { + "rotation": [ + 15, + 135, + -6 + ], + "translation": [ + -0.5, + 4.5, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "gui": { + "rotation": [ + 15, + 135, + -6 + ], + "translation": [ + -0.5, + 4.5, + 0 + ], + "scale": [ + 1.3, + 1.3, + 1.3 + ] + }, + "head": { + "rotation": [ + 0, + -180, + 0 + ], + "translation": [ + 0, + 18.5, + 0 + ], + "scale": [ + 1.5, + 1.5, + 1.5 + ] + }, + "fixed": { + "rotation": [ + -15, + -28, + -6 + ], + "translation": [ + 0, + 4.5, + -6.5 + ], + "scale": [ + 1.3, + 1.3, + 1.3 + ] + } + }, + "groups": [ + { + "name": "bottom", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6 + ] + }, + { + "name": "base", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 7, + 8, + 9, + 10, + { + "name": "group", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 11, + 12, + 13, + 14 + ] + } + ] + }, + { + "name": "body", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 15, + 16, + 17, + 18, + { + "name": "group", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 19, + 20, + 21, + 22 + ] + } + ] + }, + { + "name": "handle", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 23, + 24, + 25, + 26, + 27 + ] + }, + { + "name": "rim", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 28, + 29, + 30, + 31, + { + "name": "group", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 32, + 33, + 34, + 35 + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/sips/models/item/lil_sip - Copy.json b/src/main/resources/assets/sips/models/item/lil_sip - Copy.json new file mode 100644 index 0000000..b6b6e1c --- /dev/null +++ b/src/main/resources/assets/sips/models/item/lil_sip - Copy.json @@ -0,0 +1,129 @@ +{ + "parent": "builtin/entity", + "textures": { + "particle": "sips:item/lil_sip_3d" + }, + "display": { + "thirdperson_righthand": { + "rotation": [ + 75, + 45, + 0 + ], + "translation": [ + 0, + 2.5, + 0.75 + ], + "scale": [ + 0.75, + 0.75, + 0.75 + ] + }, + "thirdperson_lefthand": { + "rotation": [ + 75, + 45, + 0 + ], + "translation": [ + 0, + 2.5, + 0.75 + ], + "scale": [ + 0.75, + 0.75, + 0.75 + ] + }, + "firstperson_righthand": { + "rotation": [ + 0, + 180, + 0 + ], + "translation": [ + 0, + 6, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "firstperson_lefthand": { + "rotation": [ + 0, + 120, + 0 + ], + "translation": [ + 0, + 6, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "ground": { + "translation": [ + 0, + 5, + 0 + ], + "scale": [ + 0.6, + 0.6, + 0.6 + ] + }, + "gui": { + "rotation": [ + 11, + -150, + 0 + ], + "translation": [ + 0, + 5.5, + 0 + ], + "scale": [ + 1.5, + 1.5, + 1.5 + ] + }, + "head": { + "translation": [ + 0, + 16, + 0 + ], + "scale": [ + 1.2, + 1.2, + 1.2 + ] + }, + "fixed": { + "rotation": [ + 0, + 45, + 0 + ], + "translation": [ + 0, + 3, + -3 + ] + } + } +} diff --git a/src/main/resources/assets/sips/models/item/lil_sip_2d.json b/src/main/resources/assets/sips/models/item/lil_sip_2d.json new file mode 100644 index 0000000..b1fa848 --- /dev/null +++ b/src/main/resources/assets/sips/models/item/lil_sip_2d.json @@ -0,0 +1,25 @@ +{ + "parent": "item/handheld", + "textures": { + "layer0": "sips:item/lil_sip" + }, + "display": { + "head": { + "rotation": [ + 0, + 0, + 0 + ], + "translation": [ + 0, + 13, + 7 + ], + "scale": [ + 1, + 1, + 1 + ] + } + } +} diff --git a/src/main/resources/assets/sips/models/item/lil_sip_3d.json b/src/main/resources/assets/sips/models/item/lil_sip_3d.json new file mode 100644 index 0000000..8b85b2e --- /dev/null +++ b/src/main/resources/assets/sips/models/item/lil_sip_3d.json @@ -0,0 +1,723 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "sips:item/lil_sip_3d", + "particle": "sips:item/lil_sip_3d" + }, + "elements": [ + { + "name": "sidew", + "from": [ + 5, + 0, + 6 + ], + "to": [ + 6, + 8, + 10 + ], + "faces": { + "north": { + "uv": [ + 4.5, + 0, + 5, + 5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 5.5, + 5.5, + 7, + 7.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 4, + 0, + 4.5, + 5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 6, + 0, + 9, + 5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 5, + 0.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 4.5, + 6, + 5 + ], + "texture": "#0" + } + } + }, + { + "name": "sidee", + "from": [ + 10, + 0, + 6 + ], + "to": [ + 11, + 8, + 10 + ], + "faces": { + "north": { + "uv": [ + 0, + 0, + 0.5, + 5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 0, + 3, + 5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 0, + 0.5, + 5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 5.5, + 5.5, + 7, + 7.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 5, + 0.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 4.5, + 5, + 5 + ], + "texture": "#0" + } + } + }, + { + "name": "pin", + "from": [ + 7, + 8.5, + 9 + ], + "to": [ + 9, + 10.5, + 9.1 + ], + "rotation": { + "angle": 45, + "axis": "x", + "origin": [ + 8, + 8, + 8 + ] + }, + "faces": { + "north": { + "uv": [ + 3, + 5, + 5, + 7.5 + ], + "rotation": 180, + "texture": "#0" + }, + "east": { + "uv": [ + 15, + 0, + 15.6, + 0.5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 3, + 5, + 5, + 7.5 + ], + "rotation": 180, + "texture": "#0" + }, + "west": { + "uv": [ + 15, + 0, + 15.6, + 0.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 15, + 0, + 15.6, + 0.5 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 15, + 0, + 15.6, + 0.5 + ], + "texture": "#0" + } + } + }, + { + "name": "siden", + "from": [ + 6, + 0, + 5 + ], + "to": [ + 10, + 8, + 6 + ], + "faces": { + "north": { + "uv": [ + 9, + 0, + 12, + 5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 0, + 0, + 0.5, + 5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 5.5, + 5.5, + 7, + 7.5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 0, + 0, + 0.5, + 5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 5, + 0.5 + ], + "rotation": 270, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 4.5, + 5, + 5 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "name": "sides", + "from": [ + 6, + 0, + 10 + ], + "to": [ + 10, + 8, + 11 + ], + "faces": { + "north": { + "uv": [ + 5.5, + 5.5, + 7, + 7.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 4, + 0, + 4.5, + 5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 2.5, + 0, + 5.5, + 5 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 4.5, + 0, + 5, + 5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 5, + 0.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 4.5, + 6, + 5 + ], + "rotation": 90, + "texture": "#0" + } + } + }, + { + "name": "sideb", + "from": [ + 6, + 0.3, + 6 + ], + "to": [ + 10, + 0.4, + 10 + ], + "faces": { + "north": { + "uv": [ + 8.5, + 1, + 9, + 1.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 2.5, + 0, + 3, + 5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 8, + 5.5, + 8.5, + 6 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 4.5, + 0, + 6.5, + 5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 9, + 5.5, + 9.5, + 6 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 9, + 5.5, + 9.5, + 6 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "name": "sidet", + "from": [ + 6, + 7.5, + 6 + ], + "to": [ + 10, + 7.6, + 10 + ], + "faces": { + "north": { + "uv": [ + 8.5, + 1, + 9, + 1.5 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 2.5, + 0, + 3, + 5 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 8, + 5.5, + 8.5, + 6 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 4.5, + 0, + 6.5, + 5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0.5, + 5.5, + 2.5, + 7.5 + ], + "rotation": 90, + "texture": "#0" + }, + "down": { + "uv": [ + 9, + 5.5, + 9.5, + 6 + ], + "rotation": 270, + "texture": "#0" + } + } + }, + { + "name": "crutchwall", + "from": [ + 6.1, + 0, + 5 + ], + "to": [ + 6.1, + 8, + 6 + ], + "faces": { + "north": { + "uv": [ + 3.5, + 0, + 3.5, + 8 + ], + "texture": "#0" + }, + "east": { + "uv": [ + 7, + 5.5, + 7.5, + 6 + ], + "texture": "#0" + }, + "south": { + "uv": [ + 0, + 0, + 0, + 8 + ], + "texture": "#0" + }, + "west": { + "uv": [ + 8.5, + 1, + 9, + 1.5 + ], + "texture": "#0" + }, + "up": { + "uv": [ + 0, + 0, + 0, + 1 + ], + "texture": "#0" + }, + "down": { + "uv": [ + 0, + 0, + 0, + 1 + ], + "texture": "#0" + } + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [ + 75, + 45, + 0 + ], + "translation": [ + 0, + 2.5, + 0.75 + ], + "scale": [ + 0.75, + 0.75, + 0.75 + ] + }, + "thirdperson_lefthand": { + "rotation": [ + 75, + 45, + 0 + ], + "translation": [ + 0, + 2.5, + 0.75 + ], + "scale": [ + 0.75, + 0.75, + 0.75 + ] + }, + "firstperson_righthand": { + "rotation": [ + -5, + 175, + 0 + ], + "translation": [ + 0, + 6.25, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "firstperson_lefthand": { + "rotation": [ + -5, + 175, + 0 + ], + "translation": [ + 0, + 6.25, + 0 + ], + "scale": [ + 0.7, + 0.7, + 0.7 + ] + }, + "ground": { + "translation": [ + 0, + 5, + 0 + ], + "scale": [ + 0.6, + 0.6, + 0.6 + ] + }, + "gui": { + "rotation": [ + 15, + 135, + -6 + ], + "translation": [ + -0.5, + 6.25, + 0 + ], + "scale": [ + 1.66, + 1.66, + 1.66 + ] + }, + "head": { + "rotation": [ + 0, + 45, + 0 + ], + "translation": [ + 0, + 16, + 0 + ], + "scale": [ + 1.2, + 1.2, + 1.2 + ] + }, + "fixed": { + "translation": [ + 0, + 3, + -3 + ] + } + }, + "groups": [ + { + "name": "group", + "origin": [ + 8, + 8, + 8 + ], + "children": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/sips/textures/block/fluid/milk_flow.png b/src/main/resources/assets/sips/textures/block/fluid/milk_flow.png new file mode 100644 index 0000000..347b021 Binary files /dev/null and b/src/main/resources/assets/sips/textures/block/fluid/milk_flow.png differ diff --git a/src/main/resources/assets/sips/textures/block/fluid/milk_flow.png.mcmeta b/src/main/resources/assets/sips/textures/block/fluid/milk_flow.png.mcmeta new file mode 100644 index 0000000..c81b662 --- /dev/null +++ b/src/main/resources/assets/sips/textures/block/fluid/milk_flow.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/sips/textures/block/fluid/milk_still.png b/src/main/resources/assets/sips/textures/block/fluid/milk_still.png new file mode 100644 index 0000000..3af932b Binary files /dev/null and b/src/main/resources/assets/sips/textures/block/fluid/milk_still.png differ diff --git a/src/main/resources/assets/sips/textures/block/fluid/milk_still.png.mcmeta b/src/main/resources/assets/sips/textures/block/fluid/milk_still.png.mcmeta new file mode 100644 index 0000000..c81b662 --- /dev/null +++ b/src/main/resources/assets/sips/textures/block/fluid/milk_still.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 4 + } +} \ No newline at end of file diff --git a/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_flow.png b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_flow.png new file mode 100644 index 0000000..f542f90 Binary files /dev/null and b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_flow.png differ diff --git a/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_flow.png.mcmeta b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_flow.png.mcmeta new file mode 100644 index 0000000..0645f48 --- /dev/null +++ b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_flow.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 2 + } +} diff --git a/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_still.png b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_still.png new file mode 100644 index 0000000..dbcf80a Binary files /dev/null and b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_still.png differ diff --git a/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_still.png.mcmeta b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_still.png.mcmeta new file mode 100644 index 0000000..0645f48 --- /dev/null +++ b/src/main/resources/assets/sips/textures/block/fluid/mushroom_stew_still.png.mcmeta @@ -0,0 +1,5 @@ +{ + "animation": { + "frametime": 2 + } +} diff --git a/src/main/resources/assets/sips/textures/gui/background.png b/src/main/resources/assets/sips/textures/gui/background.png new file mode 100644 index 0000000..84a67ac Binary files /dev/null and b/src/main/resources/assets/sips/textures/gui/background.png differ diff --git a/src/main/resources/assets/sips/textures/item/big_chug.png b/src/main/resources/assets/sips/textures/item/big_chug.png new file mode 100644 index 0000000..31dae73 Binary files /dev/null and b/src/main/resources/assets/sips/textures/item/big_chug.png differ diff --git a/src/main/resources/assets/sips/textures/item/big_chug_3d.png b/src/main/resources/assets/sips/textures/item/big_chug_3d.png new file mode 100644 index 0000000..b0d7c9c Binary files /dev/null and b/src/main/resources/assets/sips/textures/item/big_chug_3d.png differ diff --git a/src/main/resources/assets/sips/textures/item/lil_sip.png b/src/main/resources/assets/sips/textures/item/lil_sip.png new file mode 100644 index 0000000..d3f6269 Binary files /dev/null and b/src/main/resources/assets/sips/textures/item/lil_sip.png differ diff --git a/src/main/resources/assets/sips/textures/item/lil_sip_3d.png b/src/main/resources/assets/sips/textures/item/lil_sip_3d.png new file mode 100644 index 0000000..ff4c443 Binary files /dev/null and b/src/main/resources/assets/sips/textures/item/lil_sip_3d.png differ diff --git a/src/main/resources/assets/sips/textures/mob_effect/lava_digestion.png b/src/main/resources/assets/sips/textures/mob_effect/lava_digestion.png new file mode 100644 index 0000000..f43a8cb Binary files /dev/null and b/src/main/resources/assets/sips/textures/mob_effect/lava_digestion.png differ diff --git a/src/main/resources/assets/sips/textures/mob_effect/purge.png b/src/main/resources/assets/sips/textures/mob_effect/purge.png new file mode 100644 index 0000000..4b6867b Binary files /dev/null and b/src/main/resources/assets/sips/textures/mob_effect/purge.png differ diff --git a/src/main/resources/assets/sips/textures/mob_effect/thermodynamics.png b/src/main/resources/assets/sips/textures/mob_effect/thermodynamics.png new file mode 100644 index 0000000..8dfb8a2 Binary files /dev/null and b/src/main/resources/assets/sips/textures/mob_effect/thermodynamics.png differ diff --git a/src/main/resources/data/c/tags/fluids/milk.json b/src/main/resources/data/c/tags/fluids/milk.json new file mode 100644 index 0000000..a00098a --- /dev/null +++ b/src/main/resources/data/c/tags/fluids/milk.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "sips:milk", + "sips:flowing_milk" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/c/tags/fluids/mushroom_stew.json b/src/main/resources/data/c/tags/fluids/mushroom_stew.json new file mode 100644 index 0000000..34c5c0c --- /dev/null +++ b/src/main/resources/data/c/tags/fluids/mushroom_stew.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "sips:mushroom_stew", + "sips:flowing_mushroom_stew" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/minecraft/tags/fluids/water.json b/src/main/resources/data/minecraft/tags/fluids/water.json new file mode 100644 index 0000000..ad6c427 --- /dev/null +++ b/src/main/resources/data/minecraft/tags/fluids/water.json @@ -0,0 +1,9 @@ +{ + "replace": false, + "values": [ + "sips:milk", + "sips:flowing_milk", + "sips:mushroom_stew", + "sips:flowing_mushroom_stew" + ] +} \ No newline at end of file diff --git a/src/main/resources/data/sips/recipes/big_chug.json b/src/main/resources/data/sips/recipes/big_chug.json new file mode 100644 index 0000000..e318e98 --- /dev/null +++ b/src/main/resources/data/sips/recipes/big_chug.json @@ -0,0 +1,25 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SGS", + "NDN", + "NNN" + ], + "key": { + "S": { + "item": "minecraft:iron_ingot" + }, + "N": { + "item": "minecraft:bucket" + }, + "D": { + "item": "minecraft:diamond" + }, + "G": { + "item": "minecraft:gray_dye" + } + }, + "result": { + "item": "sips:big_chug" + } +} \ No newline at end of file diff --git a/src/main/resources/data/sips/recipes/lil_sip.json b/src/main/resources/data/sips/recipes/lil_sip.json new file mode 100644 index 0000000..84d56f2 --- /dev/null +++ b/src/main/resources/data/sips/recipes/lil_sip.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + " ", + "SNS", + " S " + ], + "key": { + "S": { + "item": "minecraft:lapis_lazuli" + }, + "N": { + "item": "minecraft:bucket" + } + }, + "result": { + "item": "sips:lil_sip" + } +} \ No newline at end of file diff --git a/src/main/resources/data/sips/sippables/default_sippables.json b/src/main/resources/data/sips/sippables/default_sippables.json new file mode 100644 index 0000000..c8f2383 --- /dev/null +++ b/src/main/resources/data/sips/sippables/default_sippables.json @@ -0,0 +1,296 @@ +{ + "minecraft:water": { + "effects": { + "sips:thermodynamics": { + "duration": "1t", + "showParticles": false, + "showIcon": false + } + } + }, + "minecraft:lava": { + "damage": 4, + "effects": { + "sips:lava_digestion": { + "duration": "1m" + } + } + }, + "#c:milk": { + "damage": -1, + "effects": { + "sips:purge": { + "duration": "1t", + "showParticles": false, + "showIcon": false + } + } + }, + "#c:mushroom_stew": { + "hunger": 6, + "saturation": 0.3 + }, + "techreborn:helium": { + "damage": 1, + "effects": { + "levitation": { + "duration": "10s", + "level": 4 + } + } + }, + "techreborn:nitro_diesel": { + "damage": 5, + "effects": { + "speed": { + "duration": "30s", + "level": 1 + }, + "haste": { + "duration": "30s", + "level": 1 + } + } + }, + "techreborn:nitrofuel": { + "damage": 4, + "effects": { + "speed": { + "duration": "30s" + }, + "haste": { + "duration": "30s" + } + } + }, + "techreborn:mercury": { + "effects": { + "poison": { + "duration": "1h" + }, + "luck": { + "duration": "10s" + } + } + }, + "techreborn:biofuel": { + "damage": -1, + "effects": { + "slowness": { + "duration": "20s", + "level": 4 + }, + "resistance": { + "duration": "20s", + "level": 3 + } + } + }, + "techreborn:electrolyzed_water": { + "effects": { + "haste": { + "duration": "5s", + "level": 5 + }, + "weakness": { + "duration": "15s", + "level": 2 + }, + "unluck": { + "duration": "15s" + } + } + }, + "techreborn:methane": { + "effects": { + "strength": { + "duration": "20s", + "level": 4 + }, + "speed": { + "duration": "20s", + "level": 4 + }, + "night_vision": { + "duration": "20s", + "level": 1 + }, + "weakness": { + "duration": "2m" + }, + "slowness": { + "duration": "2m" + }, + "blindness": { + "duration": "2m" + } + } + }, + "techreborn:oil": { + "hunger": 1, + "saturation": 0.1, + "damage": 1, + "effects": { + "slowness": { + "duration": "20s", + "level": 1 + }, + "mining_fatigue": { + "duration": "20s", + "level": 1 + }, + "hunger": { + "duration": "5s", + "level": 1 + }, + "luck": { + "duration": "3s", + "level": 3 + } + } + }, + "techreborn:calcium": { + "effects": { + "absorption": { + "duration": "1m" + }, + "resistance": { + "duration": "1m" + }, + "hunger": { + "duration": "5s", + "level": 1 + } + } + }, + "techreborn:compressed_air": { + "effects": { + "water_breathing": { + "duration": "20s", + "level": 4 + }, + "mining_fatigue": { + "duration": "5s" + } + } + }, + "modern_industrialization:raw_rubber": { + "effects": { + "resistance": { + "duration": "20s", + "level": 2 + }, + "absorption": { + "duration": "20s" + }, + "weakness": { + "duration": "20s" + }, + "hunger": { + "duration": "5s", + "level": 1 + } + } + }, + "modern_industrialization:chlorine": { + "damage": 5, + "effects": { + "blindness": { + "duration": "30s" + }, + "nausea": { + "duration": "10s" + }, + "slowness": { + "duration": "10s" + }, + "strength": { + "duration": "10s" + } + } + }, + "modern_industrialization:air": { + "effects": { + "water_breathing": { + "duration": "20s" + } + } + }, + "astromine:gasoline": { + "damage": 3, + "effects": { + "strength": { + "duration": "15s", + "level": 1 + }, + "nausea": { + "duration": "4s", + "level": 3 + } + } + }, + "crude_oil": { + "hunger": 1, + "saturation": 0.1, + "damage": 1, + "effects": { + "slowness": { + "duration": "20s", + "level": 1 + }, + "mining_fatigue": { + "duration": "20s", + "level": 1 + }, + "hunger": { + "duration": "5s", + "level": 1 + }, + "luck": { + "duration": "3s", + "level": 3 + } + } + }, + "diesel": { + "damage": 3, + "effects": { + "strength": { + "duration": "15s", + "level": 1 + }, + "nausea": { + "duration": "4s", + "level": 3 + } + } + }, + "sulfuric_acid": { + "damage": 10, + "effects": { + "poison": { + "duration": "1m", + "level": 10 + }, + "slowness": { + "duration": "10s", + "level": 10 + }, + "luck": { + "duration": "19t", + "level": 10 + } + } + }, + "oxygen": { + "effects": { + "water_breathing": { + "duration": "20s", + "level": 4 + }, + "mining_fatigue": { + "duration": "5s" + } + } + } +} \ 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..0265777 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,41 @@ +{ + "schemaVersion": 1, + "id": "sips", + "version": "${version}", + "name": "Sips", + "description": "Drink.", + "authors": [ + "codewarrior0", + "Yoghurt4C" + ], + "contact": { + "homepage": "https://www.curseforge.com/minecraft/mc-mods/sips", + "sources": "https://github.com/codewarrior0/sips" + }, + "license": "MMPL-J 1.0", + "icon": "assets/sips/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "mod.codewarrior.sips.SipsMod" + ], + "client": [ + "mod.codewarrior.sips.client.SipsClient" + ], + "rei_plugins_v0": [ + "mod.codewarrior.sips.compat.rei.SipsREIPlugin" + ] + }, + "mixins": [ + "sips.mixins.json" + ], + "depends": { + "fabricloader": ">=0.7.4", + "fabric": "*", + "libblockattributes": ">=0.8.4", + "minecraft": "1.16.x" + }, + "suggests": { + "flamingo": "*" + } +} diff --git a/src/main/resources/sips.mixins.json b/src/main/resources/sips.mixins.json new file mode 100644 index 0000000..bd67234 --- /dev/null +++ b/src/main/resources/sips.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "mod.codewarrior.sips.mixins", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "PlayerManagerMixin" + ], + "client": [ + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +}