Initial source import
33
.editorconfig
Normal file
|
@ -0,0 +1,33 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.gradle]
|
||||
indent_style = tab
|
||||
|
||||
[*.java]
|
||||
indent_style = tab
|
||||
|
||||
[*.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[quilt.mod.json]
|
||||
indent_style = tab
|
||||
tab_width = 2
|
||||
|
||||
[*.toml]
|
||||
indent_style = tab
|
||||
tab_width = 2
|
||||
|
||||
[*.properties]
|
||||
indent_style = space
|
||||
indent_size = 2
|
30
.gitattributes
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
*.java text eol=lf diff=java
|
||||
*.gradle text eol=lf diff=java
|
||||
*.kt text eol=lf diff=kotlin
|
||||
*.kts text eol=lf diff=kotlin
|
||||
gradlew text eol=lf
|
||||
*.bat text eol=crlf
|
||||
|
||||
*.md text eol=lf diff=markdown
|
||||
|
||||
.editorconfig text eol=lf
|
||||
|
||||
*.json text eol=lf
|
||||
*.json5 text eol=lf
|
||||
*.properties text eol=lf
|
||||
*.toml text eol=lf
|
||||
*.xml text eol=lf diff=html
|
||||
|
||||
# Modding specific
|
||||
*.accesswidener text eol=lf
|
||||
|
||||
# These files are binary and should be left untouched
|
||||
# (binary is a macro for -text -diff)
|
||||
*.class binary
|
||||
*.dll binary
|
||||
*.ear binary
|
||||
*.jar binary
|
||||
*.jks binary
|
||||
*.png binary
|
||||
*.so binary
|
||||
*.war binary
|
34
.gitignore
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
# Gradle
|
||||
.gradle/
|
||||
build/
|
||||
out/
|
||||
classes/
|
||||
|
||||
# Quilt Loom
|
||||
remappedSrc/
|
||||
run/
|
||||
|
||||
# Eclipse
|
||||
*.launch
|
||||
|
||||
# IntelliJ Idea
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
# Fleet
|
||||
.fleet/
|
||||
|
||||
# Visual Studio Code
|
||||
.settings/
|
||||
.vscode/
|
||||
bin/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# Eclipse JDT LS
|
||||
workspace/
|
||||
|
||||
# macOS
|
||||
*.DS_Store
|
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2022-2024 Cynthia Foxwell
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
83
build.gradle
Normal file
|
@ -0,0 +1,83 @@
|
|||
plugins {
|
||||
alias libs.plugins.quilt.loom
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName = project.archives_base_name
|
||||
}
|
||||
|
||||
version = "$project.version+${libs.versions.minecraft.get()}"
|
||||
group = project.maven_group
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
name = "TerraformersMC"
|
||||
url = "https://maven.terraformersmc.com/"
|
||||
}
|
||||
maven {
|
||||
name = "Ladysnake Libs"
|
||||
url = "https://maven.ladysnake.org/releases"
|
||||
}
|
||||
maven {
|
||||
name = "Sleeping Town"
|
||||
url = "https://repo.sleeping.town"
|
||||
content {
|
||||
includeGroup "com.unascribed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loom {
|
||||
// Loom and Loader both use this block in order to gather more information about your mod.
|
||||
mods {
|
||||
// This should match your mod id.
|
||||
"scout" {
|
||||
// Tell Loom about each source set used by your mod here. This ensures that your mod's classes are properly transformed by Loader.
|
||||
sourceSet("main")
|
||||
// If you shade (directly include classes, not JiJ) a dependency into your mod, include it here using one of these methods:
|
||||
// dependency("com.example.shadowedmod:1.2.3")
|
||||
// configuration("exampleShadedConfigurationName")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
minecraft libs.minecraft
|
||||
mappings variantOf(libs.quilt.mappings) { classifier 'intermediary-v2' }
|
||||
modImplementation libs.quilt.loader
|
||||
|
||||
modImplementation libs.quilted.fabric.api
|
||||
|
||||
modApi include("dev.emi:trinkets:${libs.versions.trinkets.get()}")
|
||||
modApi include("com.unascribed:lib39-core:${libs.versions.lib39.get()}+${libs.versions.minecraft.get()}")
|
||||
modApi include("com.unascribed:lib39-dessicant:${libs.versions.lib39.get()}+${libs.versions.minecraft.get()}")
|
||||
|
||||
modCompileOnly "dev.emi:emi-fabric:${libs.versions.emi.get()}+${libs.versions.minecraft.get()}:api"
|
||||
modLocalRuntime "dev.emi:emi-fabric:${libs.versions.emi.get()}+${libs.versions.minecraft.get()}"
|
||||
}
|
||||
|
||||
processResources {
|
||||
inputs.properties 'version': version, 'group': project.group
|
||||
|
||||
filesMatching('quilt.mod.json') {
|
||||
expand 'version': version, 'group': project.group
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
it.options.encoding = 'UTF-8'
|
||||
// Minecraft 1.18 (1.18-pre2) upwards uses Java 17.
|
||||
it.options.release = 17
|
||||
}
|
||||
|
||||
java {
|
||||
// Still required by IDEs such as Eclipse and Visual Studio Code
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
jar {
|
||||
from('LICENSE') {
|
||||
rename { "${it}_${base.archivesName.get()}" }
|
||||
}
|
||||
}
|
10
gradle.properties
Normal file
|
@ -0,0 +1,10 @@
|
|||
# Gradle Properties
|
||||
org.gradle.jvmargs = -Xmx1G
|
||||
org.gradle.parallel = true
|
||||
|
||||
# Mod Properties
|
||||
version = 2.0.0
|
||||
maven_group = pm.c7.scout
|
||||
archives_base_name = Scout
|
||||
|
||||
# Dependencies are managed at gradle/libs.versions.toml
|
28
gradle/libs.versions.toml
Normal file
|
@ -0,0 +1,28 @@
|
|||
[versions]
|
||||
# The latest versions are available at https://lambdaurora.dev/tools/import_quilt.html
|
||||
minecraft = "1.20.1"
|
||||
loom = "1.4.1"
|
||||
|
||||
quilt_mappings = "1.20.1+build.23"
|
||||
quilt_loader = "0.21.0"
|
||||
|
||||
quilted_fabric_api = "7.4.0+0.90.0-1.20.1"
|
||||
|
||||
trinkets = "3.7.2"
|
||||
lib39 = "1.5.0-experimental6.1"
|
||||
emi = "1.1.3"
|
||||
|
||||
[libraries]
|
||||
minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" }
|
||||
quilt_mappings = { module = "org.quiltmc:quilt-mappings", version.ref = "quilt_mappings" }
|
||||
quilt_loader = { module = "org.quiltmc:quilt-loader", version.ref = "quilt_loader" }
|
||||
|
||||
quilted_fabric_api = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api", version.ref = "quilted_fabric_api" }
|
||||
quilted_fabric_api_deprecated = { module = "org.quiltmc.quilted-fabric-api:quilted-fabric-api-deprecated", version.ref = "quilted_fabric_api" }
|
||||
|
||||
# If you have multiple similar dependencies, you can declare a dependency bundle and reference it on the build script with "libs.bundles.example".
|
||||
[bundles]
|
||||
quilted_fabric_api = ["quilted_fabric_api", "quilted_fabric_api_deprecated"]
|
||||
|
||||
[plugins]
|
||||
quilt_loom = { id = "org.quiltmc.loom", version.ref = "loom" }
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
249
gradlew
vendored
Normal file
|
@ -0,0 +1,249 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
92
gradlew.bat
vendored
Normal file
|
@ -0,0 +1,92 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
14
settings.gradle
Normal file
|
@ -0,0 +1,14 @@
|
|||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
name = 'Quilt'
|
||||
url = 'https://maven.quiltmc.org/repository/release'
|
||||
}
|
||||
// Currently needed for Intermediary and other temporary dependencies
|
||||
maven {
|
||||
name = 'Fabric'
|
||||
url = 'https://maven.fabricmc.net/'
|
||||
}
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
22
src/main/java/pm/c7/scout/Scout.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package pm.c7.scout;
|
||||
|
||||
import com.unascribed.lib39.core.api.AutoRegistry;
|
||||
import net.minecraft.item.ItemGroup;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.Identifier;
|
||||
import org.quiltmc.loader.api.ModContainer;
|
||||
import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
|
||||
import org.quiltmc.qsl.item.group.api.QuiltItemGroup;
|
||||
import pm.c7.scout.config.ScoutConfigHandler;
|
||||
import pm.c7.scout.registry.ScoutItems;
|
||||
|
||||
public class Scout implements ModInitializer {
|
||||
public static final AutoRegistry AUTOREGISTRY = AutoRegistry.of(ScoutUtil.MOD_ID);
|
||||
public static final ItemGroup ITEM_GROUP = QuiltItemGroup.createWithIcon(new Identifier("scout", "itemgroup"), () -> new ItemStack(ScoutItems.SATCHEL));
|
||||
|
||||
@Override
|
||||
public void onInitialize(ModContainer mod) {
|
||||
new ScoutConfigHandler();
|
||||
ScoutItems.init();
|
||||
}
|
||||
}
|
53
src/main/java/pm/c7/scout/ScoutMixin.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
package pm.c7.scout;
|
||||
|
||||
import com.unascribed.lib39.core.api.AutoMixin;
|
||||
import org.objectweb.asm.Type;
|
||||
import org.objectweb.asm.tree.AnnotationNode;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
import pm.c7.scout.mixinsupport.ClassNodeTransformer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// "you could also embrace chaos" --Una
|
||||
// https://git.sleeping.town/unascribed/Yttr/src/branch/1.19.2/src/main/java/com/unascribed/yttr/YttrMixin.java
|
||||
public class ScoutMixin extends AutoMixin {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Scout:MixinPlugin");
|
||||
|
||||
public @interface Transformer {
|
||||
Class<? extends ClassNodeTransformer> value();
|
||||
}
|
||||
|
||||
private final Map<String, ClassNodeTransformer> transformers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
protected boolean shouldMixinBeSkipped(String name, ClassNode node) {
|
||||
if (name.endsWith("Transformer")) {
|
||||
return true;
|
||||
}
|
||||
return super.shouldMixinBeSkipped(name, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldAnnotationSkipMixin(String name, AnnotationNode an) {
|
||||
if (an.desc.equals("Lpm/c7/scout/ScoutMixin$Transformer;")) {
|
||||
var params = decodeAnnotationParams(an);
|
||||
Type type = (Type)params.get("value");
|
||||
try {
|
||||
transformers.put(name, (ClassNodeTransformer) Class.forName(type.getClassName()).newInstance());
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Transformer class for mixin {} not found", name, e);
|
||||
}
|
||||
}
|
||||
return super.shouldAnnotationSkipMixin(name, an);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
transformers.getOrDefault(mixinClassName, (s, cn) -> {}).transform(targetClassName, targetClass);
|
||||
super.postApply(targetClassName, targetClass, mixinClassName, mixinInfo);
|
||||
}
|
||||
}
|
7
src/main/java/pm/c7/scout/ScoutNetworking.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package pm.c7.scout;
|
||||
|
||||
import net.minecraft.util.Identifier;
|
||||
|
||||
public class ScoutNetworking {
|
||||
public static final Identifier ENABLE_SLOTS = new Identifier(ScoutUtil.MOD_ID, "enable_slots");
|
||||
}
|
10
src/main/java/pm/c7/scout/ScoutScreenHandler.java
Normal file
|
@ -0,0 +1,10 @@
|
|||
package pm.c7.scout;
|
||||
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
public interface ScoutScreenHandler {
|
||||
DefaultedList<BagSlot> scout$getSatchelSlots();
|
||||
DefaultedList<BagSlot> scout$getLeftPouchSlots();
|
||||
DefaultedList<BagSlot> scout$getRightPouchSlots();
|
||||
}
|
151
src/main/java/pm/c7/scout/ScoutUtil.java
Normal file
|
@ -0,0 +1,151 @@
|
|||
package pm.c7.scout;
|
||||
|
||||
import dev.emi.trinkets.api.SlotReference;
|
||||
import dev.emi.trinkets.api.TrinketComponent;
|
||||
import dev.emi.trinkets.api.TrinketsApi;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.ingame.BeaconScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.CreativeInventoryScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.MerchantScreen;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtList;
|
||||
import net.minecraft.screen.PlayerScreenHandler;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.Pair;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.item.BaseBagItem.BagType;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ScoutUtil {
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("Scout");
|
||||
public static final String MOD_ID = "scout";
|
||||
public static final Identifier SLOT_TEXTURE = new Identifier("scout", "textures/gui/slots.png");
|
||||
|
||||
public static final int MAX_SATCHEL_SLOTS = 18;
|
||||
public static final int MAX_POUCH_SLOTS = 6;
|
||||
public static final int TOTAL_SLOTS = MAX_SATCHEL_SLOTS + MAX_POUCH_SLOTS + MAX_POUCH_SLOTS;
|
||||
|
||||
public static final int SATCHEL_SLOT_START = -1100;
|
||||
public static final int LEFT_POUCH_SLOT_START = SATCHEL_SLOT_START - MAX_SATCHEL_SLOTS;
|
||||
public static final int RIGHT_POUCH_SLOT_START = LEFT_POUCH_SLOT_START - MAX_POUCH_SLOTS;
|
||||
public static final int BAG_SLOTS_END = RIGHT_POUCH_SLOT_START - MAX_POUCH_SLOTS;
|
||||
|
||||
public static ItemStack findBagItem(PlayerEntity player, BaseBagItem.BagType type, boolean right) {
|
||||
ItemStack targetStack = ItemStack.EMPTY;
|
||||
|
||||
boolean hasFirstPouch = false;
|
||||
Optional<TrinketComponent> _component = TrinketsApi.getTrinketComponent(player);
|
||||
if (_component.isPresent()) {
|
||||
TrinketComponent component = _component.get();
|
||||
for (Pair<SlotReference, ItemStack> pair : component.getAllEquipped()) {
|
||||
ItemStack slotStack = pair.getRight();
|
||||
|
||||
if (slotStack.getItem() instanceof BaseBagItem bagItem) {
|
||||
if (bagItem.getType() == type) {
|
||||
if (type == BagType.POUCH) {
|
||||
if (right && !hasFirstPouch) {
|
||||
hasFirstPouch = true;
|
||||
} else {
|
||||
targetStack = slotStack;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
targetStack = slotStack;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetStack;
|
||||
}
|
||||
|
||||
public static NbtList inventoryToTag(Inventory inventory) {
|
||||
NbtList tag = new NbtList();
|
||||
|
||||
for(int i = 0; i < inventory.size(); i++) {
|
||||
NbtCompound stackTag = new NbtCompound();
|
||||
stackTag.putInt("Slot", i);
|
||||
stackTag.put("Stack", inventory.getStack(i).writeNbt(new NbtCompound()));
|
||||
tag.add(stackTag);
|
||||
}
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static void inventoryFromTag(NbtList tag, Inventory inventory) {
|
||||
inventory.clear();
|
||||
|
||||
tag.forEach(element -> {
|
||||
NbtCompound stackTag = (NbtCompound) element;
|
||||
int slot = stackTag.getInt("Slot");
|
||||
ItemStack stack = ItemStack.fromNbt(stackTag.getCompound("Stack"));
|
||||
inventory.setStack(slot, stack);
|
||||
});
|
||||
}
|
||||
|
||||
public static boolean isBagSlot(int slot) {
|
||||
return slot <= SATCHEL_SLOT_START && slot > BAG_SLOTS_END;
|
||||
}
|
||||
|
||||
public static @Nullable Slot getBagSlot(int slot, PlayerScreenHandler playerScreenHandler) {
|
||||
var scoutScreenHandler = (ScoutScreenHandler) playerScreenHandler;
|
||||
if (slot <= SATCHEL_SLOT_START && slot > LEFT_POUCH_SLOT_START) {
|
||||
int realSlot = MathHelper.abs(slot - SATCHEL_SLOT_START);
|
||||
var slots = scoutScreenHandler.scout$getSatchelSlots();
|
||||
|
||||
return slots.get(realSlot);
|
||||
} else if (slot <= LEFT_POUCH_SLOT_START && slot > RIGHT_POUCH_SLOT_START) {
|
||||
int realSlot = MathHelper.abs(slot - LEFT_POUCH_SLOT_START);
|
||||
var slots = scoutScreenHandler.scout$getLeftPouchSlots();
|
||||
|
||||
return slots.get(realSlot);
|
||||
} else if (slot <= RIGHT_POUCH_SLOT_START && slot > BAG_SLOTS_END) {
|
||||
int realSlot = MathHelper.abs(slot - RIGHT_POUCH_SLOT_START);
|
||||
var slots = scoutScreenHandler.scout$getRightPouchSlots();
|
||||
|
||||
return slots.get(realSlot);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static DefaultedList<Slot> getAllBagSlots(PlayerScreenHandler playerScreenHandler) {
|
||||
var scoutScreenHandler = (ScoutScreenHandler) playerScreenHandler;
|
||||
DefaultedList<Slot> out = DefaultedList.ofSize(TOTAL_SLOTS);
|
||||
out.addAll(scoutScreenHandler.scout$getSatchelSlots());
|
||||
out.addAll(scoutScreenHandler.scout$getLeftPouchSlots());
|
||||
out.addAll(scoutScreenHandler.scout$getRightPouchSlots());
|
||||
return out;
|
||||
}
|
||||
|
||||
public static @Nullable PlayerScreenHandler getPlayerScreenHandler() {
|
||||
var client = MinecraftClient.getInstance();
|
||||
if (client != null && client.player != null) {
|
||||
return client.player.playerScreenHandler;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// FIXME: registry system for mods to register their own blacklisted screens
|
||||
public static boolean isScreenBlacklisted(Screen screen) {
|
||||
return screen instanceof CreativeInventoryScreen
|
||||
|| screen instanceof MerchantScreen // FIXME: needs repositioning
|
||||
|| screen instanceof BeaconScreen; // FIXME: needs repositioning
|
||||
}
|
||||
}
|
204
src/main/java/pm/c7/scout/client/ScoutClient.java
Normal file
|
@ -0,0 +1,204 @@
|
|||
package pm.c7.scout.client;
|
||||
|
||||
import net.fabricmc.fabric.api.client.rendering.v1.LivingEntityFeatureRendererRegistrationCallback;
|
||||
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.ShulkerBoxScreen;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import org.quiltmc.loader.api.ModContainer;
|
||||
import org.quiltmc.qsl.base.api.entrypoint.client.ClientModInitializer;
|
||||
import org.quiltmc.qsl.networking.api.client.ClientPlayNetworking;
|
||||
import org.quiltmc.qsl.screen.api.client.ScreenEvents;
|
||||
import org.quiltmc.qsl.tooltip.api.client.TooltipComponentCallback;
|
||||
import pm.c7.scout.ScoutNetworking;
|
||||
import pm.c7.scout.ScoutScreenHandler;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.client.gui.BagTooltipComponent;
|
||||
import pm.c7.scout.client.render.SatchelFeatureRenderer;
|
||||
import pm.c7.scout.item.BagTooltipData;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.item.BaseBagItem.BagType;
|
||||
import pm.c7.scout.client.render.PouchFeatureRenderer;
|
||||
import pm.c7.scout.mixin.client.HandledScreenAccessor;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
public class ScoutClient implements ClientModInitializer {
|
||||
@Override
|
||||
public void onInitializeClient(ModContainer mod) {
|
||||
ClientPlayNetworking.registerGlobalReceiver(ScoutNetworking.ENABLE_SLOTS, (client, handler, packet, sender) -> {
|
||||
client.execute(() -> {
|
||||
assert client.player != null;
|
||||
ScoutScreenHandler screenHandler = (ScoutScreenHandler) client.player.playerScreenHandler;
|
||||
|
||||
ItemStack satchelStack = ScoutUtil.findBagItem(client.player, BagType.SATCHEL, false);
|
||||
DefaultedList<BagSlot> satchelSlots = screenHandler.scout$getSatchelSlots();
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_SATCHEL_SLOTS; i++) {
|
||||
BagSlot slot = satchelSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
if (!satchelStack.isEmpty()) {
|
||||
BaseBagItem satchelItem = (BaseBagItem) satchelStack.getItem();
|
||||
Inventory satchelInv = satchelItem.getInventory(satchelStack);
|
||||
|
||||
for (int i = 0; i < satchelItem.getSlotCount(); i++) {
|
||||
BagSlot slot = satchelSlots.get(i);
|
||||
slot.setInventory(satchelInv);
|
||||
slot.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(client.player, BagType.POUCH, false);
|
||||
DefaultedList<BagSlot> leftPouchSlots = screenHandler.scout$getLeftPouchSlots();
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
BagSlot slot = leftPouchSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem leftPouchItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
Inventory leftPouchInv = leftPouchItem.getInventory(leftPouchStack);
|
||||
|
||||
for (int i = 0; i < leftPouchItem.getSlotCount(); i++) {
|
||||
BagSlot slot = leftPouchSlots.get(i);
|
||||
slot.setInventory(leftPouchInv);
|
||||
slot.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(client.player, BagType.POUCH, true);
|
||||
DefaultedList<BagSlot> rightPouchSlots = screenHandler.scout$getRightPouchSlots();
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
BagSlot slot = rightPouchSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem rightPouchItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
Inventory rightPouchInv = rightPouchItem.getInventory(rightPouchStack);
|
||||
|
||||
for (int i = 0; i < rightPouchItem.getSlotCount(); i++) {
|
||||
BagSlot slot = rightPouchSlots.get(i);
|
||||
slot.setInventory(rightPouchInv);
|
||||
slot.setEnabled(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
TooltipComponentCallback.EVENT.register(data -> {
|
||||
if (data instanceof BagTooltipData d) {
|
||||
return new BagTooltipComponent(d);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
|
||||
LivingEntityFeatureRendererRegistrationCallback.EVENT.register((entityType, entityRenderer, registrationHelper, context) -> {
|
||||
if (entityType == EntityType.PLAYER) {
|
||||
registrationHelper.register(new PouchFeatureRenderer<>(entityRenderer, context.getHeldItemRenderer()));
|
||||
registrationHelper.register(new SatchelFeatureRenderer<>(entityRenderer));
|
||||
}
|
||||
});
|
||||
|
||||
ScreenEvents.AFTER_INIT.register((screen, client, scaledWidth, scaledHeight) -> {
|
||||
if (screen instanceof HandledScreen<?> handledScreen && client.player != null) {
|
||||
if (ScoutUtil.isScreenBlacklisted(screen)) {
|
||||
// realistically no one is going to have a screen bigger than 2147483647 pixels
|
||||
for (Slot slot : ScoutUtil.getAllBagSlots(client.player.playerScreenHandler)) {
|
||||
BagSlot bagSlot = (BagSlot) slot;
|
||||
bagSlot.setX(Integer.MAX_VALUE);
|
||||
bagSlot.setY(Integer.MAX_VALUE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var handledScreenAccessor = (HandledScreenAccessor) handledScreen;
|
||||
|
||||
var sx = handledScreenAccessor.getX();
|
||||
var sy = handledScreenAccessor.getY();
|
||||
var sw = handledScreenAccessor.getBackgroundWidth();
|
||||
var sh = handledScreenAccessor.getBackgroundHeight();
|
||||
|
||||
// satchel
|
||||
int x = sx;
|
||||
int y = sy + sh + 2;
|
||||
|
||||
if (screen instanceof GenericContainerScreen || screen instanceof ShulkerBoxScreen) {
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_SATCHEL_SLOTS; i++) {
|
||||
if (i % 9 == 0) {
|
||||
x = sx + 8;
|
||||
}
|
||||
|
||||
BagSlot slot = (BagSlot) ScoutUtil.getBagSlot(ScoutUtil.SATCHEL_SLOT_START - i, client.player.playerScreenHandler);
|
||||
if (slot != null) {
|
||||
slot.setX(x - sx);
|
||||
slot.setY(y - sy);
|
||||
}
|
||||
|
||||
x += 18;
|
||||
|
||||
if ((i + 1) % 9 == 0) {
|
||||
y += 18;
|
||||
}
|
||||
}
|
||||
|
||||
// left pouch
|
||||
x = sx + 8;
|
||||
y = (sy + sh) - 100;
|
||||
|
||||
if (screen instanceof GenericContainerScreen || screen instanceof ShulkerBoxScreen) {
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
if (i % 3 == 0) {
|
||||
x -= 18;
|
||||
y += 54;
|
||||
}
|
||||
|
||||
BagSlot slot = (BagSlot) ScoutUtil.getBagSlot(ScoutUtil.LEFT_POUCH_SLOT_START - i, client.player.playerScreenHandler);
|
||||
if (slot != null) {
|
||||
slot.setX(x - sx);
|
||||
slot.setY(y - sy);
|
||||
}
|
||||
|
||||
y -= 18;
|
||||
}
|
||||
|
||||
// right pouch
|
||||
x = sx + sw - 24;
|
||||
y = (sy + sh) - 100;
|
||||
|
||||
if (screen instanceof GenericContainerScreen || screen instanceof ShulkerBoxScreen) {
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
if (i % 3 == 0) {
|
||||
x += 18;
|
||||
y += 54;
|
||||
}
|
||||
|
||||
BagSlot slot = (BagSlot) ScoutUtil.getBagSlot(ScoutUtil.RIGHT_POUCH_SLOT_START - i, client.player.playerScreenHandler);
|
||||
if (slot != null) {
|
||||
slot.setX(x - sx);
|
||||
slot.setY(y - sy);
|
||||
}
|
||||
|
||||
y -= 18;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
45
src/main/java/pm/c7/scout/client/compat/ScoutEmiPlugin.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
package pm.c7.scout.client.compat;
|
||||
|
||||
import dev.emi.emi.api.EmiPlugin;
|
||||
import dev.emi.emi.api.EmiRegistry;
|
||||
import dev.emi.emi.api.widget.Bounds;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.item.BaseBagItem.BagType;
|
||||
import pm.c7.scout.mixin.client.HandledScreenAccessor;
|
||||
|
||||
public class ScoutEmiPlugin implements EmiPlugin {
|
||||
@Override
|
||||
public void register(EmiRegistry registry) {
|
||||
registry.addExclusionArea(InventoryScreen.class, (screen, consumer) -> {
|
||||
MinecraftClient client = MinecraftClient.getInstance();
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(client.player, BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
int x = ((HandledScreenAccessor) screen).getX() - (columns * 18);
|
||||
int y = ((HandledScreenAccessor) screen).getY() + 76;
|
||||
|
||||
consumer.accept(new Bounds(x, y, columns * 18, 68));
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(client.player, BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
int x = ((HandledScreenAccessor) screen).getX() + 176;
|
||||
int y = ((HandledScreenAccessor) screen).getY() + 76;
|
||||
|
||||
consumer.accept(new Bounds(x, y, columns * 18, 68));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package pm.c7.scout.client.gui;
|
||||
|
||||
import com.google.common.math.IntMath;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.font.TextRenderer;
|
||||
import net.minecraft.client.gui.DrawableHelper;
|
||||
import net.minecraft.client.gui.tooltip.TooltipComponent;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BagTooltipData;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
|
||||
public class BagTooltipComponent implements TooltipComponent {
|
||||
private final DefaultedList<ItemStack> inventory;
|
||||
private final int slotCount;
|
||||
|
||||
public BagTooltipComponent(BagTooltipData data) {
|
||||
this.inventory = data.getInventory();
|
||||
this.slotCount = data.getSlotCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return (18 * IntMath.divide(slotCount, 6, RoundingMode.UP)) + 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWidth(TextRenderer textRenderer) {
|
||||
return 18 * (Math.min(slotCount, 6));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawItems(TextRenderer textRenderer, int x, int y, MatrixStack matrices, ItemRenderer itemRenderer, int z) {
|
||||
int originalX = x;
|
||||
|
||||
for (int i = 0; i < slotCount; i++) {
|
||||
ItemStack itemStack = this.inventory.get(i);
|
||||
this.drawSlot(matrices, x, y, z);
|
||||
itemRenderer.renderInGuiWithOverrides(itemStack, x + 1, y + 1, i);
|
||||
itemRenderer.renderGuiItemOverlay(textRenderer, itemStack, x + 1, y + 1);
|
||||
|
||||
x += 18;
|
||||
if ((i + 1) % 6 == 0) {
|
||||
y += 18;
|
||||
x = originalX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void drawSlot(MatrixStack matrices, int x, int y, int z) {
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||
RenderSystem.setShaderTexture(0, ScoutUtil.SLOT_TEXTURE);
|
||||
DrawableHelper.drawTexture(matrices, x, y, z, 46, 7, 18, 18, 256, 256);
|
||||
}
|
||||
|
||||
}
|
45
src/main/java/pm/c7/scout/client/model/SatchelModel.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
package pm.c7.scout.client.model;
|
||||
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.*;
|
||||
import net.minecraft.client.render.entity.model.SinglePartEntityModel;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
|
||||
public class SatchelModel<T extends LivingEntity> extends SinglePartEntityModel<T> {
|
||||
private final ModelPart root;
|
||||
private final ModelPart satchel;
|
||||
private final ModelPart strap;
|
||||
|
||||
public SatchelModel(ModelPart root) {
|
||||
super();
|
||||
this.root = root;
|
||||
this.satchel = root.getChild("satchel");
|
||||
this.strap = this.satchel.getChild("strap");
|
||||
}
|
||||
|
||||
public static TexturedModelData getTexturedModelData() {
|
||||
ModelData modelData = new ModelData();
|
||||
ModelPartData root = modelData.getRoot();
|
||||
|
||||
ModelPartData satchel = root.addChild("satchel", ModelPartBuilder.create().uv(10, 0).cuboid(-6.0F, -12.0F, -2.5F, 2.0F, 3.0F, 5.0F, new Dilation(0.275F)), ModelTransform.pivot(0.0F, 24.0F, 0.0F));
|
||||
ModelPartData strap = satchel.addChild("strap", ModelPartBuilder.create().uv(0, 0).cuboid(-1.0F, -13.0F, -2.0F, 1.0F, 14.0F, 4.0F, new Dilation(0.275F)), ModelTransform.of(-3.0F, -13.0F, 0.0F, 0.0F, 0.0F, 0.5672F));
|
||||
|
||||
return TexturedModelData.of(modelData, 32, 32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumer vertices, int light, int overlay, float red, float green, float blue, float alpha) {
|
||||
satchel.render(matrices, vertices, light, overlay, red, green, blue, alpha);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getPart() {
|
||||
return this.root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAngles(T entity, float limbAngle, float limbDistance, float animationProgress, float headYaw, float headPitch) {
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package pm.c7.scout.client.render;
|
||||
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||
import net.minecraft.client.render.entity.model.EntityModel;
|
||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.render.item.HeldItemRenderer;
|
||||
import net.minecraft.client.render.model.json.ModelTransformation;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.Vec3f;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
public class PouchFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
|
||||
private final HeldItemRenderer heldItemRenderer;
|
||||
|
||||
public PouchFeatureRenderer(FeatureRendererContext<T, M> context, HeldItemRenderer heldItemRenderer) {
|
||||
super(context);
|
||||
this.heldItemRenderer = heldItemRenderer;
|
||||
}
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
|
||||
var leftPouch = ScoutUtil.findBagItem((PlayerEntity) entity, BaseBagItem.BagType.POUCH, false);
|
||||
var rightPouch = ScoutUtil.findBagItem((PlayerEntity) entity, BaseBagItem.BagType.POUCH, true);
|
||||
|
||||
if (!leftPouch.isEmpty()) {
|
||||
matrices.push();
|
||||
((PlayerEntityModel<?>) this.getContextModel()).leftLeg.rotate(matrices);
|
||||
matrices.multiply(Vec3f.POSITIVE_X.getDegreesQuaternion(180.0F));
|
||||
matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion(-90.0F));
|
||||
matrices.scale(0.325F, 0.325F, 0.325F);
|
||||
matrices.translate(0F, -0.325F, -0.475F);
|
||||
this.heldItemRenderer.renderItem(entity, leftPouch, ModelTransformation.Mode.FIXED, false, matrices, vertexConsumers, light);
|
||||
matrices.pop();
|
||||
}
|
||||
if (!rightPouch.isEmpty()) {
|
||||
matrices.push();
|
||||
((PlayerEntityModel<?>) this.getContextModel()).rightLeg.rotate(matrices);
|
||||
matrices.multiply(Vec3f.POSITIVE_X.getDegreesQuaternion(180.0F));
|
||||
matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion(-90.0F));
|
||||
matrices.scale(0.325F, 0.325F, 0.325F);
|
||||
matrices.translate(0F, -0.325F, 0.475F);
|
||||
this.heldItemRenderer.renderItem(entity, rightPouch, ModelTransformation.Mode.FIXED, false, matrices, vertexConsumers, light);
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package pm.c7.scout.client.render;
|
||||
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import net.minecraft.client.model.TexturedModelData;
|
||||
import net.minecraft.client.render.OverlayTexture;
|
||||
import net.minecraft.client.render.RenderLayer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||
import net.minecraft.client.render.entity.model.EntityModel;
|
||||
import net.minecraft.client.render.entity.model.PlayerEntityModel;
|
||||
import net.minecraft.client.render.item.ItemRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Identifier;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.client.model.SatchelModel;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
public class SatchelFeatureRenderer<T extends LivingEntity, M extends EntityModel<T>> extends FeatureRenderer<T, M> {
|
||||
private static final Identifier SATCHEL_TEXTURE = new Identifier(ScoutUtil.MOD_ID, "textures/entity/satchel.png");
|
||||
private static final Identifier UPGRADED_SATCHEL_TEXTURE = new Identifier(ScoutUtil.MOD_ID, "textures/entity/upgraded_satchel.png");
|
||||
|
||||
private final SatchelModel<T> satchel;
|
||||
|
||||
public SatchelFeatureRenderer(FeatureRendererContext<T, M> context) {
|
||||
super(context);
|
||||
TexturedModelData modelData = SatchelModel.getTexturedModelData();
|
||||
this.satchel = new SatchelModel<>(modelData.createModel());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) {
|
||||
var satchel = ScoutUtil.findBagItem((PlayerEntity) entity, BaseBagItem.BagType.SATCHEL, false);
|
||||
|
||||
if (!satchel.isEmpty()) {
|
||||
BaseBagItem satchelItem = (BaseBagItem) satchel.getItem();
|
||||
var texture = SATCHEL_TEXTURE;
|
||||
if (satchelItem.getSlotCount() == ScoutUtil.MAX_SATCHEL_SLOTS)
|
||||
texture = UPGRADED_SATCHEL_TEXTURE;
|
||||
|
||||
matrices.push();
|
||||
((PlayerEntityModel<?>) this.getContextModel()).body.rotate(matrices);
|
||||
this.getContextModel().copyStateTo(this.satchel);
|
||||
VertexConsumer vertexConsumer = ItemRenderer.getArmorGlintConsumer(
|
||||
vertexConsumers, RenderLayer.getArmorCutoutNoCull(texture), false, satchel.hasGlint()
|
||||
);
|
||||
this.satchel.render(matrices, vertexConsumer, light, OverlayTexture.DEFAULT_UV, 1.0F, 1.0F, 1.0F, 1.0F);
|
||||
matrices.pop();
|
||||
}
|
||||
}
|
||||
}
|
12
src/main/java/pm/c7/scout/config/ScoutConfig.java
Normal file
|
@ -0,0 +1,12 @@
|
|||
package pm.c7.scout.config;
|
||||
|
||||
import org.quiltmc.config.api.WrappedConfig;
|
||||
import org.quiltmc.config.api.annotations.Comment;
|
||||
|
||||
public class ScoutConfig extends WrappedConfig {
|
||||
@Comment("Allow shulker boxes to be placed in bags. Bags are already blacklisted from shulker boxes with no toggle.")
|
||||
public final boolean allowShulkers = true;
|
||||
|
||||
@Comment("Allow bags to act as a quiver and pull arrows.")
|
||||
public final boolean useArrows = true;
|
||||
}
|
17
src/main/java/pm/c7/scout/config/ScoutConfigHandler.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package pm.c7.scout.config;
|
||||
|
||||
import org.quiltmc.config.api.values.TrackedValue;
|
||||
import org.quiltmc.loader.api.config.QuiltConfig;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ScoutConfigHandler {
|
||||
public static final ScoutConfig CONFIG = QuiltConfig.create("", ScoutUtil.MOD_ID, ScoutConfig.class);
|
||||
|
||||
public ScoutConfigHandler() {}
|
||||
|
||||
public static TrackedValue<?> getConfigValue(String key) {
|
||||
return CONFIG.getValue(List.of(key));
|
||||
}
|
||||
}
|
23
src/main/java/pm/c7/scout/item/BagTooltipData.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package pm.c7.scout.item;
|
||||
|
||||
import net.minecraft.client.item.TooltipData;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
|
||||
public class BagTooltipData implements TooltipData {
|
||||
private final DefaultedList<ItemStack> inventory;
|
||||
private final int slotCount;
|
||||
|
||||
public BagTooltipData(DefaultedList<ItemStack> inventory, int slots) {
|
||||
this.inventory = inventory;
|
||||
this.slotCount = slots;
|
||||
}
|
||||
|
||||
public DefaultedList<ItemStack> getInventory() {
|
||||
return this.inventory;
|
||||
}
|
||||
|
||||
public int getSlotCount() {
|
||||
return this.slotCount;
|
||||
}
|
||||
}
|
226
src/main/java/pm/c7/scout/item/BaseBagItem.java
Normal file
|
@ -0,0 +1,226 @@
|
|||
package pm.c7.scout.item;
|
||||
|
||||
import dev.emi.trinkets.api.SlotReference;
|
||||
import dev.emi.trinkets.api.TrinketItem;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.client.item.TooltipContext;
|
||||
import net.minecraft.client.item.TooltipData;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.inventory.SimpleInventory;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtList;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.text.Text;
|
||||
import net.minecraft.util.Formatting;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.world.World;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.quiltmc.qsl.networking.api.ServerPlayNetworking;
|
||||
import pm.c7.scout.ScoutNetworking;
|
||||
import pm.c7.scout.ScoutScreenHandler;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class BaseBagItem extends TrinketItem {
|
||||
private static final String ITEMS_KEY = "Items";
|
||||
|
||||
private final int slots;
|
||||
private final BagType type;
|
||||
|
||||
public BaseBagItem(Settings settings, int slots, BagType type) {
|
||||
super(settings);
|
||||
|
||||
if (type == BagType.SATCHEL && slots > ScoutUtil.MAX_SATCHEL_SLOTS) {
|
||||
throw new IllegalArgumentException("Satchel has too many slots.");
|
||||
}
|
||||
if (type == BagType.POUCH && slots > ScoutUtil.MAX_POUCH_SLOTS) {
|
||||
throw new IllegalArgumentException("Pouch has too many slots.");
|
||||
}
|
||||
|
||||
this.slots = slots;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getSlotCount() {
|
||||
return this.slots;
|
||||
}
|
||||
|
||||
public BagType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTooltip(ItemStack stack, @Nullable World world, List<Text> tooltip, TooltipContext context) {
|
||||
super.appendTooltip(stack, world, tooltip, context);
|
||||
tooltip.add(Text.translatable("tooltip.scout.slots", Text.literal(String.valueOf(this.slots)).formatted(Formatting.BLUE)).formatted(Formatting.GRAY));
|
||||
}
|
||||
|
||||
public Inventory getInventory(ItemStack stack) {
|
||||
SimpleInventory inventory = new SimpleInventory(this.slots) {
|
||||
@Override
|
||||
public void markDirty() {
|
||||
stack.getOrCreateNbt().put(ITEMS_KEY, ScoutUtil.inventoryToTag(this));
|
||||
super.markDirty();
|
||||
}
|
||||
};
|
||||
|
||||
NbtCompound compound = stack.getOrCreateNbt();
|
||||
if (!compound.contains(ITEMS_KEY)) {
|
||||
compound.put(ITEMS_KEY, new NbtList());
|
||||
}
|
||||
|
||||
NbtList items = compound.getList(ITEMS_KEY, 10);
|
||||
|
||||
ScoutUtil.inventoryFromTag(items, inventory);
|
||||
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<TooltipData> getTooltipData(ItemStack stack) {
|
||||
DefaultedList<ItemStack> stacks = DefaultedList.of();
|
||||
Inventory inventory = getInventory(stack);
|
||||
|
||||
for (int i = 0; i < slots; i++) {
|
||||
stacks.add(inventory.getStack(i));
|
||||
}
|
||||
|
||||
if (stacks.stream().allMatch(ItemStack::isEmpty)) return Optional.empty();
|
||||
|
||||
return Optional.of(new BagTooltipData(stacks, slots));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEquip(ItemStack stack, SlotReference slotRef, LivingEntity entity) {
|
||||
if (entity instanceof PlayerEntity player)
|
||||
updateSlots(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnequip(ItemStack stack, SlotReference slotRef, LivingEntity entity) {
|
||||
if (entity instanceof PlayerEntity player)
|
||||
updateSlots(player);
|
||||
}
|
||||
|
||||
private void updateSlots(PlayerEntity player) {
|
||||
ScoutScreenHandler handler = (ScoutScreenHandler) player.playerScreenHandler;
|
||||
|
||||
ItemStack satchelStack = ScoutUtil.findBagItem(player, BagType.SATCHEL, false);
|
||||
DefaultedList<BagSlot> satchelSlots = handler.scout$getSatchelSlots();
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_SATCHEL_SLOTS; i++) {
|
||||
BagSlot slot = satchelSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
if (!satchelStack.isEmpty()) {
|
||||
BaseBagItem satchelItem = (BaseBagItem) satchelStack.getItem();
|
||||
Inventory satchelInv = satchelItem.getInventory(satchelStack);
|
||||
|
||||
for (int i = 0; i < satchelItem.getSlotCount(); i++) {
|
||||
BagSlot slot = satchelSlots.get(i);
|
||||
slot.setInventory(satchelInv);
|
||||
slot.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(player, BagType.POUCH, false);
|
||||
DefaultedList<BagSlot> leftPouchSlots = handler.scout$getLeftPouchSlots();
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
BagSlot slot = leftPouchSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem leftPouchItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
Inventory leftPouchInv = leftPouchItem.getInventory(leftPouchStack);
|
||||
|
||||
for (int i = 0; i < leftPouchItem.getSlotCount(); i++) {
|
||||
BagSlot slot = leftPouchSlots.get(i);
|
||||
slot.setInventory(leftPouchInv);
|
||||
slot.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(player, BagType.POUCH, true);
|
||||
DefaultedList<BagSlot> rightPouchSlots = handler.scout$getRightPouchSlots();
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
BagSlot slot = rightPouchSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem rightPouchItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
Inventory rightPouchInv = rightPouchItem.getInventory(rightPouchStack);
|
||||
|
||||
for (int i = 0; i < rightPouchItem.getSlotCount(); i++) {
|
||||
BagSlot slot = rightPouchSlots.get(i);
|
||||
slot.setInventory(rightPouchInv);
|
||||
slot.setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
PacketByteBuf packet = new PacketByteBuf(Unpooled.buffer());
|
||||
if (player instanceof ServerPlayerEntity serverPlayer) {
|
||||
ServerPlayNetworking.send(serverPlayer, ScoutNetworking.ENABLE_SLOTS, packet);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canEquip(ItemStack stack, SlotReference slot, LivingEntity entity) {
|
||||
Item item = stack.getItem();
|
||||
|
||||
ItemStack slotStack = slot.inventory().getStack(slot.index());
|
||||
Item slotItem = slotStack.getItem();
|
||||
|
||||
if (slotItem instanceof BaseBagItem) {
|
||||
if (((BaseBagItem) item).getType() == BagType.SATCHEL) {
|
||||
if (((BaseBagItem) slotItem).getType() == BagType.SATCHEL) {
|
||||
return true;
|
||||
} else {
|
||||
return ScoutUtil.findBagItem((PlayerEntity) entity, BagType.SATCHEL, false).isEmpty();
|
||||
}
|
||||
} else if (((BaseBagItem) item).getType() == BagType.POUCH) {
|
||||
if (((BaseBagItem) slotItem).getType() == BagType.POUCH) {
|
||||
return true;
|
||||
} else {
|
||||
return ScoutUtil.findBagItem((PlayerEntity) entity, BagType.POUCH, true).isEmpty();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (((BaseBagItem) item).getType() == BagType.SATCHEL) {
|
||||
return ScoutUtil.findBagItem((PlayerEntity) entity, BagType.SATCHEL, false).isEmpty();
|
||||
} else if (((BaseBagItem) item).getType() == BagType.POUCH) {
|
||||
return ScoutUtil.findBagItem((PlayerEntity) entity, BagType.POUCH, true).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inventoryTick(ItemStack stack, World world, Entity entity, int slot, boolean selected) {
|
||||
var inv = getInventory(stack);
|
||||
|
||||
for (int i = 0; i < inv.size(); i++) {
|
||||
var invStack = inv.getStack(i);
|
||||
invStack.inventoryTick(world, entity, i, false);
|
||||
}
|
||||
}
|
||||
|
||||
public enum BagType {
|
||||
SATCHEL,
|
||||
POUCH
|
||||
}
|
||||
}
|
85
src/main/java/pm/c7/scout/mixin/BowItemMixin.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.BowItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.Items;
|
||||
import net.minecraft.world.World;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.config.ScoutConfigHandler;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
@Mixin(BowItem.class)
|
||||
public class BowItemMixin {
|
||||
@Inject(method = "onStoppedUsing", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;playSound(Lnet/minecraft/entity/player/PlayerEntity;DDDLnet/minecraft/sound/SoundEvent;Lnet/minecraft/sound/SoundCategory;FF)V"), locals = LocalCapture.CAPTURE_FAILHARD)
|
||||
public void scout$arrowsFromBags(ItemStack stack, World world, LivingEntity user, int remainingUseTicks, CallbackInfo ci, PlayerEntity playerEntity, boolean bl, ItemStack itemStack, int maxTime, float f) {
|
||||
if ((boolean) ScoutConfigHandler.getConfigValue("useArrows").value()) {
|
||||
boolean infinity = bl && itemStack.isOf(Items.ARROW);
|
||||
boolean hasRan = false;
|
||||
|
||||
if (!infinity && !playerEntity.getAbilities().creativeMode) {
|
||||
var leftPouch = ScoutUtil.findBagItem(playerEntity, BaseBagItem.BagType.POUCH, false);
|
||||
var rightPouch = ScoutUtil.findBagItem(playerEntity, BaseBagItem.BagType.POUCH, true);
|
||||
var satchel = ScoutUtil.findBagItem(playerEntity, BaseBagItem.BagType.SATCHEL, false);
|
||||
|
||||
if (!leftPouch.isEmpty()) {
|
||||
BaseBagItem item = (BaseBagItem) leftPouch.getItem();
|
||||
var inv = item.getInventory(leftPouch);
|
||||
|
||||
for(int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack invStack = inv.getStack(i);
|
||||
if (ItemStack.areEqual(invStack, itemStack)) {
|
||||
invStack.decrement(1);
|
||||
if (invStack.isEmpty()) {
|
||||
inv.setStack(i, ItemStack.EMPTY);
|
||||
}
|
||||
inv.markDirty();
|
||||
hasRan = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rightPouch.isEmpty() && !hasRan) {
|
||||
BaseBagItem item = (BaseBagItem) rightPouch.getItem();
|
||||
var inv = item.getInventory(rightPouch);
|
||||
|
||||
for(int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack invStack = inv.getStack(i);
|
||||
if (ItemStack.areEqual(invStack, itemStack)) {
|
||||
invStack.decrement(1);
|
||||
if (invStack.isEmpty()) {
|
||||
inv.setStack(i, ItemStack.EMPTY);
|
||||
}
|
||||
inv.markDirty();
|
||||
hasRan = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!satchel.isEmpty() && !hasRan) {
|
||||
BaseBagItem item = (BaseBagItem) satchel.getItem();
|
||||
var inv = item.getInventory(satchel);
|
||||
|
||||
for(int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack invStack = inv.getStack(i);
|
||||
if (ItemStack.areEqual(invStack, itemStack)) {
|
||||
invStack.decrement(1);
|
||||
if (invStack.isEmpty()) {
|
||||
inv.setStack(i, ItemStack.EMPTY);
|
||||
}
|
||||
inv.markDirty();
|
||||
hasRan = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
23
src/main/java/pm/c7/scout/mixin/ItemStackMixin.java
Normal file
|
@ -0,0 +1,23 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
@Mixin(ItemStack.class)
|
||||
public class ItemStackMixin {
|
||||
|
||||
// Trinkets calls isItemEqual to check whether it should unequip old and equip new (https://github.com/emilyploszaj/trinkets/blob/37ee13d6/src/main/java/dev/emi/trinkets/mixin/LivingEntityMixin.java#L196-L199)
|
||||
// Excluding ourselves from this check to force unequip/equip when switching bag items fixes a duplication bug (GH-12)
|
||||
// Gross and hacky but oh well, can't mixin mixins.
|
||||
@Inject(method = "isItemEqual", at = @At("HEAD"), cancellable = true)
|
||||
private void scout$grossTrinketsEquipFix(ItemStack newStack, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
ItemStack self = (ItemStack) (Object) this;
|
||||
if (self.getItem() instanceof BaseBagItem && newStack.getItem() instanceof BaseBagItem) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
61
src/main/java/pm/c7/scout/mixin/PlayerEntityMixin.java
Normal file
|
@ -0,0 +1,61 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.config.ScoutConfigHandler;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(PlayerEntity.class)
|
||||
public class PlayerEntityMixin {
|
||||
@Inject(method = "getArrowType", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/item/RangedWeaponItem;getProjectiles()Ljava/util/function/Predicate;"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
public void scout$arrowsFromBags(ItemStack stack, CallbackInfoReturnable<ItemStack> cir, Predicate<ItemStack> predicate, ItemStack itemStack) {
|
||||
if ((boolean) ScoutConfigHandler.getConfigValue("useArrows").value()) {
|
||||
var self = (PlayerEntity) (Object) this;
|
||||
var leftPouch = ScoutUtil.findBagItem(self, BaseBagItem.BagType.POUCH, false);
|
||||
var rightPouch = ScoutUtil.findBagItem(self, BaseBagItem.BagType.POUCH, true);
|
||||
var satchel = ScoutUtil.findBagItem(self, BaseBagItem.BagType.SATCHEL, false);
|
||||
|
||||
if (!leftPouch.isEmpty()) {
|
||||
BaseBagItem item = (BaseBagItem) leftPouch.getItem();
|
||||
var inv = item.getInventory(leftPouch);
|
||||
|
||||
for(int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack invStack = inv.getStack(i);
|
||||
if (predicate.test(invStack)) {
|
||||
cir.setReturnValue(invStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rightPouch.isEmpty()) {
|
||||
BaseBagItem item = (BaseBagItem) rightPouch.getItem();
|
||||
var inv = item.getInventory(rightPouch);
|
||||
|
||||
for(int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack invStack = inv.getStack(i);
|
||||
if (predicate.test(invStack)) {
|
||||
cir.setReturnValue(invStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!satchel.isEmpty()) {
|
||||
BaseBagItem item = (BaseBagItem) satchel.getItem();
|
||||
var inv = item.getInventory(satchel);
|
||||
|
||||
for(int i = 0; i < inv.size(); ++i) {
|
||||
ItemStack invStack = inv.getStack(i);
|
||||
if (predicate.test(invStack)) {
|
||||
cir.setReturnValue(invStack);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.screen.PlayerScreenHandler;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import pm.c7.scout.ScoutScreenHandler;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
@Mixin(value = PlayerScreenHandler.class, priority = 950)
|
||||
public abstract class PlayerScreenHandlerMixin extends ScreenHandler implements ScoutScreenHandler {
|
||||
protected PlayerScreenHandlerMixin() {
|
||||
super(null, 0);
|
||||
}
|
||||
|
||||
@Unique
|
||||
public final DefaultedList<BagSlot> scout$satchelSlots = DefaultedList.ofSize(ScoutUtil.MAX_SATCHEL_SLOTS);
|
||||
@Unique
|
||||
public final DefaultedList<BagSlot> scout$leftPouchSlots = DefaultedList.ofSize(ScoutUtil.MAX_POUCH_SLOTS);
|
||||
@Unique
|
||||
public final DefaultedList<BagSlot> scout$rightPouchSlots = DefaultedList.ofSize(ScoutUtil.MAX_POUCH_SLOTS);
|
||||
|
||||
@Inject(method = "<init>", at = @At("RETURN"))
|
||||
private void scout$addSlots(PlayerInventory inventory, boolean onServer, PlayerEntity owner, CallbackInfo callbackInfo) {
|
||||
// satchel
|
||||
int x = 8;
|
||||
int y = 168;
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_SATCHEL_SLOTS; i++) {
|
||||
if (i % 9 == 0) {
|
||||
x = 8;
|
||||
}
|
||||
|
||||
BagSlot slot = new BagSlot(i, x, y);
|
||||
slot.id = ScoutUtil.SATCHEL_SLOT_START - i;
|
||||
scout$satchelSlots.add(slot);
|
||||
|
||||
x += 18;
|
||||
|
||||
if ((i + 1) % 9 == 0) {
|
||||
y += 18;
|
||||
}
|
||||
}
|
||||
|
||||
// left pouch
|
||||
x = 8;
|
||||
y = 66;
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
if (i % 3 == 0) {
|
||||
x -= 18;
|
||||
y += 54;
|
||||
}
|
||||
|
||||
BagSlot slot = new BagSlot(i, x, y);
|
||||
slot.id = ScoutUtil.LEFT_POUCH_SLOT_START - i;
|
||||
scout$leftPouchSlots.add(slot);
|
||||
|
||||
y -= 18;
|
||||
}
|
||||
|
||||
// right pouch
|
||||
x = 152;
|
||||
y = 66;
|
||||
|
||||
for (int i = 0; i < ScoutUtil.MAX_POUCH_SLOTS; i++) {
|
||||
if (i % 3 == 0) {
|
||||
x += 18;
|
||||
y += 54;
|
||||
}
|
||||
|
||||
BagSlot slot = new BagSlot(i, x, y);
|
||||
slot.id = ScoutUtil.RIGHT_POUCH_SLOT_START - i;
|
||||
scout$rightPouchSlots.add(slot);
|
||||
|
||||
y -= 18;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final DefaultedList<BagSlot> scout$getSatchelSlots() {
|
||||
return scout$satchelSlots;
|
||||
}
|
||||
@Override
|
||||
public final DefaultedList<BagSlot> scout$getLeftPouchSlots() {
|
||||
return scout$leftPouchSlots;
|
||||
}
|
||||
@Override
|
||||
public final DefaultedList<BagSlot> scout$getRightPouchSlots() {
|
||||
return scout$rightPouchSlots;
|
||||
}
|
||||
}
|
68
src/main/java/pm/c7/scout/mixin/ScreenHandlerMixin.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import net.minecraft.screen.slot.SlotActionType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
import pm.c7.scout.ScoutMixin.Transformer;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
|
||||
@Mixin(ScreenHandler.class)
|
||||
@Transformer(ScreenHandlerTransformer.class)
|
||||
public abstract class ScreenHandlerMixin {
|
||||
@Inject(method = "getSlot", at = @At("HEAD"), cancellable = true)
|
||||
public void scout$fixGetSlot(int index, CallbackInfoReturnable<Slot> cir) {
|
||||
var playerScreenHandler = ScoutUtil.getPlayerScreenHandler();
|
||||
if (ScoutUtil.isBagSlot(index)) {
|
||||
if (playerScreenHandler != null) {
|
||||
cir.setReturnValue(ScoutUtil.getBagSlot(index, playerScreenHandler));
|
||||
} else {
|
||||
cir.setReturnValue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "internalOnSlotClick", at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/screen/ScreenHandler;getCursorStack()Lnet/minecraft/item/ItemStack;", ordinal = 11), locals = LocalCapture.CAPTURE_FAILEXCEPTION)
|
||||
public void scout$fixDoubleClick(int slotIndex, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci, PlayerInventory playerInventory, Slot slot3) {
|
||||
var cursorStack = this.getCursorStack();
|
||||
if (!cursorStack.isEmpty() && (!slot3.hasStack() || !slot3.canTakeItems(player))) {
|
||||
var slots = ScoutUtil.getAllBagSlots(player.playerScreenHandler);
|
||||
var k = button == 0 ? 0 : ScoutUtil.TOTAL_SLOTS - 1;
|
||||
var o = button == 0 ? 1 : -1;
|
||||
|
||||
for (int n = 0; n < 2; ++n) {
|
||||
for (int p = k; p >= 0 && p < slots.size() && cursorStack.getCount() < cursorStack.getMaxCount(); p += o) {
|
||||
Slot slot4 = slots.get(p);
|
||||
if (slot4.hasStack() && canInsertItemIntoSlot(slot4, cursorStack, true) && slot4.canTakeItems(player) && this.canInsertIntoSlot(cursorStack, slot4)) {
|
||||
ItemStack itemStack6 = slot4.getStack();
|
||||
if (n != 0 || itemStack6.getCount() != itemStack6.getMaxCount()) {
|
||||
ItemStack itemStack7 = slot4.takeStackRange(itemStack6.getCount(), cursorStack.getMaxCount() - cursorStack.getCount(), player);
|
||||
cursorStack.increment(itemStack7.getCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public static boolean canInsertItemIntoSlot(@Nullable Slot slot, ItemStack stack, boolean allowOverflow) {
|
||||
return false;
|
||||
}
|
||||
@Shadow
|
||||
public boolean canInsertIntoSlot(ItemStack stack, Slot slot) {
|
||||
return true;
|
||||
}
|
||||
@Shadow
|
||||
public abstract ItemStack getCursorStack();
|
||||
}
|
155
src/main/java/pm/c7/scout/mixin/ScreenHandlerTransformer.java
Normal file
|
@ -0,0 +1,155 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import org.objectweb.asm.tree.*;
|
||||
import org.quiltmc.loader.api.QuiltLoader;
|
||||
import pm.c7.scout.mixinsupport.ClassNodeTransformer;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class ScreenHandlerTransformer implements ClassNodeTransformer {
|
||||
@Override
|
||||
public void transform(String name, ClassNode node) {
|
||||
var internalOnSlotClick = "m_nqfgpzfl";
|
||||
var insertItem = "m_jpjdgbxy";
|
||||
|
||||
var PlayerEntity = "net/minecraft/unmapped/C_jzrpycqo";
|
||||
var playerScreenHandler = "f_xvlfpipb";
|
||||
|
||||
var PlayerScreenHandler = "net/minecraft/unmapped/C_wgehrbdx";
|
||||
var Slot = "net/minecraft/unmapped/C_nhvqfffd";
|
||||
var DefaultedList = "net/minecraft/unmapped/C_rnrfftze";
|
||||
|
||||
if (QuiltLoader.isDevelopmentEnvironment()) {
|
||||
internalOnSlotClick = "internalOnSlotClick";
|
||||
insertItem = "insertItem";
|
||||
|
||||
PlayerEntity = "net/minecraft/entity/player/PlayerEntity";
|
||||
playerScreenHandler = "playerScreenHandler";
|
||||
|
||||
PlayerScreenHandler = "net/minecraft/screen/PlayerScreenHandler";
|
||||
Slot = "net/minecraft/screen/slot/Slot";
|
||||
DefaultedList = "net/minecraft/util/collection/DefaultedList";
|
||||
}
|
||||
|
||||
var LPlayerScreenHandler = L(PlayerScreenHandler);
|
||||
var LSlot = L(Slot);
|
||||
|
||||
for (var mn : node.methods) {
|
||||
if (mn.name.equals(internalOnSlotClick)) {
|
||||
for (var insn : mn.instructions) {
|
||||
if (insn instanceof VarInsnNode vin) {
|
||||
if (vin.getOpcode() == ILOAD && vin.var == 1) {
|
||||
if (insn.getNext() instanceof JumpInsnNode nextInsn && nextInsn.getOpcode() == IFGE) {
|
||||
var jumpTo = nextInsn.label;
|
||||
mn.instructions.insert(nextInsn, insns(
|
||||
ILOAD(1),
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "isBagSlot", "(I)Z"),
|
||||
IFNE(jumpTo)
|
||||
));
|
||||
}
|
||||
} else if (vin.getOpcode() == ASTORE && (vin.var == 6 || vin.var == 7)) {
|
||||
if (vin.getPrevious() instanceof TypeInsnNode prevInsn && prevInsn.getOpcode() == CHECKCAST && prevInsn.desc.equals(Slot)) {
|
||||
if (prevInsn.getPrevious() instanceof MethodInsnNode prevPrevInsn && prevPrevInsn.getOpcode() == INVOKEVIRTUAL) {
|
||||
if(prevPrevInsn.owner.equals(DefaultedList)) {
|
||||
LabelNode LnotBag = new LabelNode();
|
||||
LabelNode Lend = new LabelNode();
|
||||
mn.instructions.insertBefore(prevPrevInsn.getPrevious().getPrevious().getPrevious(), insns(
|
||||
ILOAD(1),
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "isBagSlot", "(I)Z"),
|
||||
IFEQ(LnotBag),
|
||||
ILOAD(1),
|
||||
ALOAD(4),
|
||||
GETFIELD(PlayerEntity, playerScreenHandler, LPlayerScreenHandler),
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "getBagSlot", "(I" + LPlayerScreenHandler + ")" + LSlot),
|
||||
CHECKCAST(Slot),
|
||||
ASTORE(vin.var),
|
||||
GOTO(Lend),
|
||||
LnotBag
|
||||
));
|
||||
mn.instructions.insert(vin, insns(
|
||||
Lend
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}/* else if (mn.name.equals(insertItem)) {
|
||||
for (var insn : mn.instructions) {
|
||||
if (insn instanceof VarInsnNode vin && vin.getOpcode() == ASTORE && vin.var == 7) {
|
||||
if (vin.getPrevious() instanceof TypeInsnNode prevInsn && prevInsn.getOpcode() == CHECKCAST && prevInsn.desc.equals(Slot)) {
|
||||
if (prevInsn.getPrevious() instanceof MethodInsnNode prevPrevInsn && prevPrevInsn.getOpcode() == INVOKEVIRTUAL) {
|
||||
if(prevPrevInsn.owner.equals(DefaultedList)) {
|
||||
LabelNode LnotBag = new LabelNode();
|
||||
LabelNode LpastSlot = new LabelNode();
|
||||
mn.instructions.insertBefore(prevPrevInsn.getPrevious().getPrevious().getPrevious(), insns(
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "getPlayerScreenHandler", "()" + LPlayerScreenHandler),
|
||||
ASTORE(20),
|
||||
ALOAD(20),
|
||||
IFNULL(LpastSlot),
|
||||
ILOAD(6),
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "isBagSlot", "(I)Z"),
|
||||
IFEQ(LnotBag),
|
||||
ILOAD(6),
|
||||
ALOAD(20),
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "getBagSlot", "(I" + LPlayerScreenHandler + ")" + LSlot),
|
||||
CHECKCAST(Slot),
|
||||
ASTORE(vin.var),
|
||||
LnotBag,
|
||||
ILOAD(6),
|
||||
INVOKESTATIC("pm/c7/scout/ScoutUtil", "isBagSlot", "(I)Z"),
|
||||
IFNE(LpastSlot)
|
||||
));
|
||||
mn.instructions.insert(vin, insns(
|
||||
LpastSlot
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
private String L(String clazz) {
|
||||
return "L" + clazz + ";";
|
||||
}
|
||||
|
||||
private InsnList insns(AbstractInsnNode... insns) {
|
||||
var li = new InsnList();
|
||||
for (var i : insns) li.add(i);
|
||||
return li;
|
||||
}
|
||||
private static VarInsnNode ILOAD(int var) {
|
||||
return new VarInsnNode(ILOAD, var);
|
||||
}
|
||||
private static MethodInsnNode INVOKESTATIC(String owner, String name, String desc) {
|
||||
return new MethodInsnNode(INVOKESTATIC, owner, name, desc);
|
||||
}
|
||||
private static JumpInsnNode IFNE(LabelNode var) {
|
||||
return new JumpInsnNode(IFNE, var);
|
||||
}
|
||||
private static JumpInsnNode IFEQ(LabelNode var) {
|
||||
return new JumpInsnNode(IFEQ, var);
|
||||
}
|
||||
private static VarInsnNode ALOAD(int var) {
|
||||
return new VarInsnNode(ALOAD, var);
|
||||
}
|
||||
private static VarInsnNode ASTORE(int var) {
|
||||
return new VarInsnNode(ASTORE, var);
|
||||
}
|
||||
private static FieldInsnNode GETFIELD(String owner, String name, String desc) {
|
||||
return new FieldInsnNode(GETFIELD, owner, name, desc);
|
||||
}
|
||||
private static JumpInsnNode IFNULL(LabelNode var) {
|
||||
return new JumpInsnNode(IFNULL, var);
|
||||
}
|
||||
private static TypeInsnNode CHECKCAST(String desc) {
|
||||
return new TypeInsnNode(CHECKCAST, desc);
|
||||
}
|
||||
private static JumpInsnNode GOTO(LabelNode var) {
|
||||
return new JumpInsnNode(GOTO, var);
|
||||
}
|
||||
}
|
94
src/main/java/pm/c7/scout/mixin/ServerPlayerEntityMixin.java
Normal file
|
@ -0,0 +1,94 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.entity.damage.DamageSource;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketByteBuf;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.util.collection.DefaultedList;
|
||||
import net.minecraft.world.GameRules;
|
||||
import org.quiltmc.qsl.networking.api.ServerPlayNetworking;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import pm.c7.scout.ScoutNetworking;
|
||||
import pm.c7.scout.ScoutScreenHandler;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.item.BaseBagItem.BagType;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
@Mixin(ServerPlayerEntity.class)
|
||||
public class ServerPlayerEntityMixin {
|
||||
@Inject(method = "onDeath", at = @At("HEAD"))
|
||||
private void scout$attemptFixGraveMods(DamageSource source, CallbackInfo callbackInfo) {
|
||||
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
|
||||
ScoutScreenHandler handler = (ScoutScreenHandler) player.playerScreenHandler;
|
||||
|
||||
if (!player.world.getGameRules().getBoolean(GameRules.KEEP_INVENTORY)) {
|
||||
ItemStack backStack = ScoutUtil.findBagItem(player, BagType.SATCHEL, false);
|
||||
if (!backStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) backStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
|
||||
DefaultedList<BagSlot> bagSlots = handler.scout$getSatchelSlots();
|
||||
|
||||
for (int i = 0; i < slots; i++) {
|
||||
BagSlot slot = bagSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
|
||||
PacketByteBuf packet = new PacketByteBuf(Unpooled.buffer());
|
||||
packet.writeBoolean(false);
|
||||
packet.writeInt(0);
|
||||
packet.writeItemStack(backStack);
|
||||
|
||||
ServerPlayNetworking.send(player, ScoutNetworking.ENABLE_SLOTS, packet);
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(player, BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
|
||||
DefaultedList<BagSlot> bagSlots = handler.scout$getLeftPouchSlots();
|
||||
|
||||
for (int i = 0; i < slots; i++) {
|
||||
BagSlot slot = bagSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
|
||||
PacketByteBuf packet = new PacketByteBuf(Unpooled.buffer());
|
||||
packet.writeBoolean(false);
|
||||
packet.writeInt(0);
|
||||
packet.writeItemStack(leftPouchStack);
|
||||
|
||||
ServerPlayNetworking.send(player, ScoutNetworking.ENABLE_SLOTS, packet);
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(player, BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
|
||||
DefaultedList<BagSlot> bagSlots = handler.scout$getRightPouchSlots();
|
||||
|
||||
for (int i = 0; i < slots; i++) {
|
||||
BagSlot slot = bagSlots.get(i);
|
||||
slot.setInventory(null);
|
||||
slot.setEnabled(false);
|
||||
}
|
||||
|
||||
PacketByteBuf packet = new PacketByteBuf(Unpooled.buffer());
|
||||
packet.writeBoolean(false);
|
||||
packet.writeInt(1);
|
||||
packet.writeItemStack(rightPouchStack);
|
||||
|
||||
ServerPlayNetworking.send(player, ScoutNetworking.ENABLE_SLOTS, packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
19
src/main/java/pm/c7/scout/mixin/ShulkerBoxSlotMixin.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
package pm.c7.scout.mixin;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.ShulkerBoxSlot;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
@Mixin(ShulkerBoxSlot.class)
|
||||
public class ShulkerBoxSlotMixin {
|
||||
@Inject(method = "canInsert", at = @At("HEAD"), cancellable = true)
|
||||
public void scout$noNBTOverflow(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (stack.getItem() instanceof BaseBagItem) {
|
||||
cir.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screen.ingame.AbstractFurnaceScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.AbstractFurnaceScreenHandler;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(AbstractFurnaceScreen.class)
|
||||
public abstract class AbstractFurnaceScreenMixin<T extends AbstractFurnaceScreenHandler> extends HandledScreen<T> implements RecipeBookProvider {
|
||||
public AbstractFurnaceScreenMixin() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
@Inject(method = "isClickOutsideBounds", at = @At("TAIL"), cancellable = true)
|
||||
private void scout$adjustOutsideBounds(double mouseX, double mouseY, int left, int top, int button, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
if (this.client != null && this.client.player != null) {
|
||||
ItemStack backStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.SATCHEL, false);
|
||||
if (!backStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) backStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int rows = (int) Math.ceil(slots / 9);
|
||||
|
||||
if (mouseY < (top + this.backgroundHeight) + 8 + (18 * rows) && mouseY >= (top + this.backgroundHeight) && mouseX >= left && mouseY < (left + this.backgroundWidth)) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= left - (columns * 18) && mouseX < left && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= (left + this.backgroundWidth) && mouseX < (left + this.backgroundWidth) + (columns * 18) && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screen.ingame.CraftingScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.CraftingScreenHandler;
|
||||
import net.minecraft.text.Text;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(CraftingScreen.class)
|
||||
public abstract class CraftingScreenMixin extends HandledScreen<CraftingScreenHandler> implements RecipeBookProvider {
|
||||
public CraftingScreenMixin() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
@Inject(method = "isClickOutsideBounds", at = @At("TAIL"), cancellable = true)
|
||||
private void scout$adjustOutsideBounds(double mouseX, double mouseY, int left, int top, int button, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
if (this.client != null && this.client.player != null) {
|
||||
ItemStack backStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.SATCHEL, false);
|
||||
if (!backStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) backStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int rows = (int) Math.ceil(slots / 9);
|
||||
|
||||
if (mouseY < (top + this.backgroundHeight) + 8 + (18 * rows) && mouseY >= (top + this.backgroundHeight) && mouseX >= left && mouseY < (left + this.backgroundWidth)) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= left - (columns * 18) && mouseX < left && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= (left + this.backgroundWidth) && mouseX < (left + this.backgroundWidth) + (columns * 18) && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(HandledScreen.class)
|
||||
public interface HandledScreenAccessor {
|
||||
@Accessor("x")
|
||||
int getX();
|
||||
@Accessor("y")
|
||||
int getY();
|
||||
@Accessor("backgroundWidth")
|
||||
int getBackgroundWidth();
|
||||
@Accessor("backgroundHeight")
|
||||
int getBackgroundHeight();
|
||||
}
|
328
src/main/java/pm/c7/scout/mixin/client/HandledScreenMixin.java
Normal file
|
@ -0,0 +1,328 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.Screen;
|
||||
import net.minecraft.client.gui.screen.ingame.GenericContainerScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.HandledScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider;
|
||||
import net.minecraft.client.gui.screen.ingame.ShulkerBoxScreen;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.ScreenHandler;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
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.CallbackInfoReturnable;
|
||||
import pm.c7.scout.ScoutMixin;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.screen.BagSlot;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@ScoutMixin.Transformer(HandledScreenTransformer.class)
|
||||
@Mixin(value = HandledScreen.class, priority = 950)
|
||||
public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen implements ScreenHandlerProvider<T> {
|
||||
protected HandledScreenMixin() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Shadow
|
||||
@Nullable
|
||||
protected Slot focusedSlot;
|
||||
@Shadow
|
||||
protected int x;
|
||||
@Shadow
|
||||
protected int y;
|
||||
@Shadow
|
||||
protected int backgroundWidth;
|
||||
@Shadow
|
||||
protected int backgroundHeight;
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawBackground(Lnet/minecraft/client/util/math/MatrixStack;FII)V"))
|
||||
private void scout$drawSatchelRow(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
|
||||
if (this.client != null && this.client.player != null && !ScoutUtil.isScreenBlacklisted(this)) {
|
||||
ItemStack backStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.SATCHEL, false);
|
||||
if (!backStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) backStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, ScoutUtil.SLOT_TEXTURE);
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
int x = this.x;
|
||||
int y = this.y + this.backgroundHeight - 3;
|
||||
|
||||
if ((Object) this instanceof GenericContainerScreen || (Object) this instanceof ShulkerBoxScreen) {
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
this.drawTexture(matrices, x, y, 0, 32, 176, 4);
|
||||
y += 4;
|
||||
|
||||
int u = 0;
|
||||
int v = 36;
|
||||
|
||||
for (int slot = 0; slot < slots; slot++) {
|
||||
if (slot % 9 == 0) {
|
||||
x = this.x;
|
||||
u = 0;
|
||||
this.drawTexture(matrices, x, y, u, v, 7, 18);
|
||||
x += 7;
|
||||
u += 7;
|
||||
}
|
||||
|
||||
this.drawTexture(matrices, x, y, u, v, 18, 18);
|
||||
|
||||
x += 18;
|
||||
u += 18;
|
||||
|
||||
if ((slot + 1) % 9 == 0) {
|
||||
this.drawTexture(matrices, x, y, u, v, 7, 18);
|
||||
y += 18;
|
||||
}
|
||||
}
|
||||
|
||||
x = this.x;
|
||||
this.drawTexture(matrices, x, y, 0, 54, 176, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/systems/RenderSystem;disableDepthTest()V"))
|
||||
private void scout$drawPouchSlots(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
|
||||
if (this.client != null && this.client.player != null && !ScoutUtil.isScreenBlacklisted(this)) {
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
int x = this.x;
|
||||
int y = (this.y + this.backgroundHeight) - 29;
|
||||
|
||||
if ((Object) this instanceof GenericContainerScreen || (Object) this instanceof ShulkerBoxScreen) {
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
RenderSystem.setShaderTexture(0, ScoutUtil.SLOT_TEXTURE);
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
this.drawTexture(matrices, x, y, 18, 25, 7, 7);
|
||||
for (int i = 0; i < columns; i++) {
|
||||
x -= 11;
|
||||
this.drawTexture(matrices, x, y, 7, 25, 11, 7);
|
||||
}
|
||||
if (columns > 1) {
|
||||
for (int i = 0; i < columns - 1; i++) {
|
||||
x -= 7;
|
||||
this.drawTexture(matrices, x, y, 7, 25, 7, 7);
|
||||
}
|
||||
}
|
||||
x -= 7;
|
||||
this.drawTexture(matrices, x, y, 0, 25, 7, 7);
|
||||
|
||||
x = this.x + 7;
|
||||
y -= 54;
|
||||
for (int slot = 0; slot < slots; slot++) {
|
||||
if (slot % 3 == 0) {
|
||||
x -= 18;
|
||||
y += 54;
|
||||
}
|
||||
y -= 18;
|
||||
this.drawTexture(matrices, x, y, 7, 7, 18, 18);
|
||||
}
|
||||
|
||||
x -= 7;
|
||||
y += 54;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
y -= 18;
|
||||
this.drawTexture(matrices, x, y, 0, 7, 7, 18);
|
||||
}
|
||||
|
||||
x = this.x;
|
||||
y -= 7;
|
||||
this.drawTexture(matrices, x, y, 18, 0, 7, 7);
|
||||
for (int i = 0; i < columns; i++) {
|
||||
x -= 11;
|
||||
this.drawTexture(matrices, x, y, 7, 0, 11, 7);
|
||||
}
|
||||
if (columns > 1) {
|
||||
for (int i = 0; i < columns - 1; i++) {
|
||||
x -= 7;
|
||||
this.drawTexture(matrices, x, y, 7, 0, 7, 7);
|
||||
}
|
||||
}
|
||||
x -= 7;
|
||||
this.drawTexture(matrices, x, y, 0, 0, 7, 7);
|
||||
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
int x = this.x + this.backgroundWidth - 7;
|
||||
int y = (this.y + this.backgroundHeight) - 29;
|
||||
|
||||
if ((Object) this instanceof GenericContainerScreen || (Object) this instanceof ShulkerBoxScreen) {
|
||||
y -= 1;
|
||||
}
|
||||
|
||||
RenderSystem.setShaderTexture(0, ScoutUtil.SLOT_TEXTURE);
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
|
||||
this.drawTexture(matrices, x, y, 25, 25, 7, 7);
|
||||
x += 7;
|
||||
for (int i = 0; i < columns; i++) {
|
||||
this.drawTexture(matrices, x, y, 7, 25, 11, 7);
|
||||
x += 11;
|
||||
}
|
||||
if (columns > 1) {
|
||||
for (int i = 0; i < columns - 1; i++) {
|
||||
this.drawTexture(matrices, x, y, 7, 25, 7, 7);
|
||||
x += 7;
|
||||
}
|
||||
}
|
||||
this.drawTexture(matrices, x, y, 32, 25, 7, 7);
|
||||
|
||||
x = this.x + this.backgroundWidth - 25;
|
||||
y -= 54;
|
||||
for (int slot = 0; slot < slots; slot++) {
|
||||
if (slot % 3 == 0) {
|
||||
x += 18;
|
||||
y += 54;
|
||||
}
|
||||
y -= 18;
|
||||
this.drawTexture(matrices, x, y, 7, 7, 18, 18);
|
||||
}
|
||||
|
||||
x += 18;
|
||||
y += 54;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
y -= 18;
|
||||
this.drawTexture(matrices, x, y, 32, 7, 7, 18);
|
||||
}
|
||||
|
||||
x = this.x + this.backgroundWidth - 7;
|
||||
y -= 7;
|
||||
this.drawTexture(matrices, x, y, 25, 0, 7, 7);
|
||||
x += 7;
|
||||
for (int i = 0; i < columns; i++) {
|
||||
this.drawTexture(matrices, x, y, 7, 0, 11, 7);
|
||||
x += 11;
|
||||
}
|
||||
if (columns > 1) {
|
||||
for (int i = 0; i < columns - 1; i++) {
|
||||
this.drawTexture(matrices, x, y, 7, 0, 7, 7);
|
||||
x += 7;
|
||||
}
|
||||
}
|
||||
this.drawTexture(matrices, x, y, 32, 0, 7, 7);
|
||||
|
||||
RenderSystem.setShaderColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "isClickOutsideBounds", at = @At("TAIL"), cancellable = true)
|
||||
private void scout$adjustOutsideBounds(double mouseX, double mouseY, int left, int top, int button, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
if (this.client != null && this.client.player != null && !ScoutUtil.isScreenBlacklisted(this)) {
|
||||
ItemStack backStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.SATCHEL, false);
|
||||
if (!backStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) backStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int rows = (int) Math.ceil(slots / 9);
|
||||
|
||||
if (mouseY < (top + this.backgroundHeight) + 8 + (18 * rows) && mouseY >= (top + this.backgroundHeight) && mouseX >= left && mouseY < (left + this.backgroundWidth)) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= left - (columns * 18) && mouseX < left && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(this.client.player, BaseBagItem.BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= (left + this.backgroundWidth) && mouseX < (left + this.backgroundWidth) + (columns * 18) && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;drawForeground(Lnet/minecraft/client/util/math/MatrixStack;II)V"))
|
||||
public void scout$drawOurSlots(MatrixStack matrices, int mouseX, int mouseY, float delta, CallbackInfo ci) {
|
||||
if (this.client != null && this.client.player != null && !ScoutUtil.isScreenBlacklisted(this)) {
|
||||
for (int i = ScoutUtil.SATCHEL_SLOT_START; i > ScoutUtil.BAG_SLOTS_END; i--) {
|
||||
BagSlot slot = (BagSlot) ScoutUtil.getBagSlot(i, this.client.player.playerScreenHandler);
|
||||
if (slot != null && slot.isEnabled()) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
this.drawSlot(matrices, slot);
|
||||
}
|
||||
|
||||
if (this.isPointOverSlot(slot, mouseX, mouseY) && slot != null && slot.isEnabled()) {
|
||||
this.focusedSlot = slot;
|
||||
int slotX = slot.getX();
|
||||
int slotY = slot.getY();
|
||||
drawSlotHighlight(matrices, slotX, slotY, this.getZOffset());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "isPointOverSlot", at = @At("HEAD"), cancellable = true)
|
||||
public void scout$fixSlotPos(Slot slot, double pointX, double pointY, CallbackInfoReturnable<Boolean> cir) {
|
||||
if (slot instanceof BagSlot bagSlot) {
|
||||
cir.setReturnValue(this.isPointWithinBounds(bagSlot.getX(), bagSlot.getY(), 16, 16, pointX, pointY));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "getSlotAt", at = @At("RETURN"), cancellable = true)
|
||||
public void scout$addSlots(double x, double y, CallbackInfoReturnable<Slot> cir) {
|
||||
if (this.client != null && this.client.player != null && !ScoutUtil.isScreenBlacklisted(this)) {
|
||||
for (int i = ScoutUtil.SATCHEL_SLOT_START; i > ScoutUtil.BAG_SLOTS_END; i--) {
|
||||
BagSlot slot = (BagSlot) ScoutUtil.getBagSlot(i, this.client.player.playerScreenHandler);
|
||||
if (this.isPointOverSlot(slot, x, y) && slot != null && slot.isEnabled()) {
|
||||
cir.setReturnValue(slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
private void drawSlot(MatrixStack matrices, Slot slot) {}
|
||||
@Shadow
|
||||
public static void drawSlotHighlight(MatrixStack matrices, int x, int y, int z) {}
|
||||
@Shadow
|
||||
private boolean isPointOverSlot(Slot slot, double pointX, double pointY) {
|
||||
return false;
|
||||
}
|
||||
@Shadow
|
||||
protected boolean isPointWithinBounds(int x, int y, int width, int height, double pointX, double pointY) {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import org.objectweb.asm.tree.*;
|
||||
import org.quiltmc.loader.api.QuiltLoader;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import pm.c7.scout.mixinsupport.ClassNodeTransformer;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
public class HandledScreenTransformer implements ClassNodeTransformer {
|
||||
private static Logger LOGGER = LoggerFactory.getLogger("Scout:HandledScreenTransformer");
|
||||
@Override
|
||||
public void transform(String name, ClassNode node) {
|
||||
var drawSlot = "m_zioswvnu";
|
||||
var Slot = "net/minecraft/unmapped/C_nhvqfffd";
|
||||
var y = "f_tttqoodj";
|
||||
|
||||
if (QuiltLoader.isDevelopmentEnvironment()) {
|
||||
drawSlot = "drawSlot";
|
||||
Slot = "net/minecraft/screen/slot/Slot";
|
||||
y = "y";
|
||||
}
|
||||
|
||||
for (var mn : node.methods) {
|
||||
if (mn.name.equals(drawSlot)) {
|
||||
for (var insn : mn.instructions) {
|
||||
if (insn instanceof FieldInsnNode fin) {
|
||||
if (fin.getOpcode() == GETFIELD) {
|
||||
if(fin.owner.equals(Slot) && fin.name.equals(y)) {
|
||||
if (fin.getNext() instanceof VarInsnNode vin && vin.getOpcode() == ISTORE) {
|
||||
LabelNode LnotBag = new LabelNode();
|
||||
int SAFE_REGISTER = 20;
|
||||
mn.instructions.insert(vin, insns(
|
||||
ALOAD(2),
|
||||
INSTANCEOF("pm/c7/scout/screen/BagSlot"),
|
||||
IFEQ(LnotBag),
|
||||
ALOAD(2),
|
||||
CHECKCAST("pm/c7/scout/screen/BagSlot"),
|
||||
ASTORE(SAFE_REGISTER),
|
||||
ALOAD(SAFE_REGISTER),
|
||||
INVOKEVIRTUAL("pm/c7/scout/screen/BagSlot", "getX", "()I"),
|
||||
ISTORE(vin.var - 1),
|
||||
ALOAD(SAFE_REGISTER),
|
||||
INVOKEVIRTUAL("pm/c7/scout/screen/BagSlot", "getY", "()I"),
|
||||
ISTORE(vin.var),
|
||||
LnotBag
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private InsnList insns(AbstractInsnNode... insns) {
|
||||
var li = new InsnList();
|
||||
for (var i : insns) li.add(i);
|
||||
return li;
|
||||
}
|
||||
private static JumpInsnNode IFEQ(LabelNode var) {
|
||||
return new JumpInsnNode(IFEQ, var);
|
||||
}
|
||||
private static VarInsnNode ALOAD(int var) {
|
||||
return new VarInsnNode(ALOAD, var);
|
||||
}
|
||||
private static VarInsnNode ASTORE(int var) {
|
||||
return new VarInsnNode(ASTORE, var);
|
||||
}
|
||||
private static TypeInsnNode INSTANCEOF(String desc) {
|
||||
return new TypeInsnNode(INSTANCEOF, desc);
|
||||
}
|
||||
private static TypeInsnNode CHECKCAST(String desc) {
|
||||
return new TypeInsnNode(CHECKCAST, desc);
|
||||
}
|
||||
private static MethodInsnNode INVOKEVIRTUAL(String owner, String name, String desc) {
|
||||
return new MethodInsnNode(INVOKEVIRTUAL, owner, name, desc);
|
||||
}
|
||||
private static VarInsnNode ISTORE(int var) {
|
||||
return new VarInsnNode(ISTORE, var);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.gui.screen.ingame.AbstractInventoryScreen;
|
||||
import net.minecraft.client.gui.screen.ingame.InventoryScreen;
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeBookProvider;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.PlayerScreenHandler;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.item.BaseBagItem.BagType;
|
||||
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(InventoryScreen.class)
|
||||
public abstract class InventoryScreenMixin extends AbstractInventoryScreen<PlayerScreenHandler> implements RecipeBookProvider {
|
||||
private InventoryScreenMixin() {
|
||||
super(null, null, null);
|
||||
}
|
||||
|
||||
@Inject(method = "isClickOutsideBounds", at = @At("TAIL"), cancellable = true)
|
||||
private void scout$adjustOutsideBounds(double mouseX, double mouseY, int left, int top, int button, CallbackInfoReturnable<Boolean> callbackInfo) {
|
||||
if (this.client != null && this.client.player != null) {
|
||||
ItemStack backStack = ScoutUtil.findBagItem(this.client.player, BagType.SATCHEL, false);
|
||||
if (!backStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) backStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int rows = (int) Math.ceil(slots / 9);
|
||||
|
||||
if (mouseY < (top + this.backgroundHeight) + 8 + (18 * rows) && mouseY >= (top + this.backgroundHeight) && mouseX >= left && mouseY < (left + this.backgroundWidth)) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(this.client.player, BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= left - (columns * 18) && mouseX < left && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack rightPouchStack = ScoutUtil.findBagItem(this.client.player, BagType.POUCH, true);
|
||||
if (!rightPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) rightPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
if (mouseX >= (left + this.backgroundWidth) && mouseX < (left + this.backgroundWidth) + (columns * 18) && mouseY >= (top + this.backgroundHeight) - 90 && mouseY < (top + this.backgroundHeight) - 22) {
|
||||
callbackInfo.setReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package pm.c7.scout.mixin.client;
|
||||
|
||||
import net.fabricmc.api.EnvType;
|
||||
import net.fabricmc.api.Environment;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.screen.recipebook.RecipeBookWidget;
|
||||
import net.minecraft.item.ItemStack;
|
||||
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.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
import pm.c7.scout.item.BaseBagItem.BagType;
|
||||
|
||||
// Lower priority to take priority over Better Recipe Book
|
||||
@Environment(EnvType.CLIENT)
|
||||
@Mixin(value = RecipeBookWidget.class, priority = 950)
|
||||
public class RecipeBookWidgetMixin {
|
||||
@Shadow
|
||||
protected MinecraftClient client;
|
||||
@Shadow
|
||||
private int leftOffset;
|
||||
|
||||
@Inject(method = "findLeftEdge", at = @At("RETURN"), locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true)
|
||||
private void scout$modifyRecipeBookPosition(int width, int backgroundWidth, CallbackInfoReturnable<Integer> callbackInfo, int x) {
|
||||
if (this.client != null && this.client.player != null && this.isOpen()) {
|
||||
ItemStack leftPouchStack = ScoutUtil.findBagItem(this.client.player, BagType.POUCH, false);
|
||||
if (!leftPouchStack.isEmpty()) {
|
||||
BaseBagItem bagItem = (BaseBagItem) leftPouchStack.getItem();
|
||||
int slots = bagItem.getSlotCount();
|
||||
|
||||
int columns = (int) Math.ceil(slots / 3);
|
||||
|
||||
// Realign as best we can when "Keep crafting screens centered" is enabled in Better Recipe Book
|
||||
if (this.leftOffset != 86) {
|
||||
int diff = this.leftOffset - 86;
|
||||
x -= diff;
|
||||
}
|
||||
|
||||
x += 18 * columns;
|
||||
|
||||
callbackInfo.setReturnValue(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Shadow
|
||||
public boolean isOpen() {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package pm.c7.scout.mixinsupport;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
public interface ClassNodeTransformer {
|
||||
void transform(String name, ClassNode node);
|
||||
}
|
||||
|
22
src/main/java/pm/c7/scout/registry/ScoutItems.java
Normal file
|
@ -0,0 +1,22 @@
|
|||
package pm.c7.scout.registry;
|
||||
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.Rarity;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import org.quiltmc.qsl.item.setting.api.QuiltItemSettings;
|
||||
import pm.c7.scout.Scout;
|
||||
import pm.c7.scout.ScoutUtil;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
public class ScoutItems {
|
||||
public static final Item TANNED_LEATHER = new Item(new QuiltItemSettings().group(Scout.ITEM_GROUP));
|
||||
public static final Item SATCHEL_STRAP = new Item(new QuiltItemSettings().group(Scout.ITEM_GROUP));
|
||||
public static final BaseBagItem SATCHEL = new BaseBagItem(new QuiltItemSettings().group(Scout.ITEM_GROUP).maxCount(1), ScoutUtil.MAX_SATCHEL_SLOTS / 2, BaseBagItem.BagType.SATCHEL);
|
||||
public static final BaseBagItem UPGRADED_SATCHEL = new BaseBagItem(new QuiltItemSettings().group(Scout.ITEM_GROUP).maxCount(1).rarity(Rarity.RARE), ScoutUtil.MAX_SATCHEL_SLOTS, BaseBagItem.BagType.SATCHEL);
|
||||
public static final BaseBagItem POUCH = new BaseBagItem(new QuiltItemSettings().group(Scout.ITEM_GROUP).maxCount(1), ScoutUtil.MAX_POUCH_SLOTS / 2, BaseBagItem.BagType.POUCH);
|
||||
public static final BaseBagItem UPGRADED_POUCH = new BaseBagItem(new QuiltItemSettings().group(Scout.ITEM_GROUP).maxCount(1).rarity(Rarity.RARE), ScoutUtil.MAX_POUCH_SLOTS, BaseBagItem.BagType.POUCH);
|
||||
|
||||
public static void init() {
|
||||
Scout.AUTOREGISTRY.autoRegister(Registry.ITEM, ScoutItems.class, Item.class);
|
||||
}
|
||||
}
|
107
src/main/java/pm/c7/scout/screen/BagSlot.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
package pm.c7.scout.screen;
|
||||
|
||||
import net.minecraft.block.ShulkerBoxBlock;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.inventory.Inventory;
|
||||
import net.minecraft.item.BlockItem;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.screen.slot.Slot;
|
||||
import pm.c7.scout.config.ScoutConfigHandler;
|
||||
import pm.c7.scout.item.BaseBagItem;
|
||||
|
||||
public class BagSlot extends Slot {
|
||||
private final int index;
|
||||
public Inventory inventory;
|
||||
private boolean enabled = false;
|
||||
private int realX;
|
||||
private int realY;
|
||||
|
||||
public BagSlot(int index, int x, int y) {
|
||||
super(null, index, x, y);
|
||||
this.index = index;
|
||||
this.realX = x;
|
||||
this.realY = y;
|
||||
}
|
||||
|
||||
public void setInventory(Inventory inventory) {
|
||||
this.inventory = inventory;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean state) {
|
||||
enabled = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canInsert(ItemStack stack) {
|
||||
if (stack.getItem() instanceof BaseBagItem)
|
||||
return false;
|
||||
|
||||
if (stack.getItem() instanceof BlockItem blockItem) {
|
||||
if (blockItem.getBlock() instanceof ShulkerBoxBlock)
|
||||
return (boolean) ScoutConfigHandler.getConfigValue("allowShulkers").value();
|
||||
}
|
||||
|
||||
return enabled && inventory != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canTakeItems(PlayerEntity playerEntity) {
|
||||
return enabled && inventory != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return enabled && inventory != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getStack() {
|
||||
return enabled && this.inventory != null ? this.inventory.getStack(this.index) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStack(ItemStack stack) {
|
||||
if (enabled && this.inventory != null) {
|
||||
this.inventory.setStack(this.index, stack);
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void m_tfmituvd(ItemStack stack) {
|
||||
if (enabled && this.inventory != null) {
|
||||
this.inventory.setStack(this.index, stack);
|
||||
this.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markDirty() {
|
||||
if (enabled && this.inventory != null) {
|
||||
this.inventory.markDirty();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack takeStack(int amount) {
|
||||
return enabled && this.inventory != null ? this.inventory.removeStack(this.index, amount) : ItemStack.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxItemCount() {
|
||||
return enabled && this.inventory != null ? this.inventory.getMaxCountPerStack() : 0;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return this.realX;
|
||||
}
|
||||
public int getY() {
|
||||
return this.realY;
|
||||
}
|
||||
public void setX(int x) {
|
||||
this.realX = x;
|
||||
}
|
||||
public void setY(int y) {
|
||||
this.realY = y;
|
||||
}
|
||||
}
|
10
src/main/resources/assets/emi/recipe/defaults/scout.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"recipes": [
|
||||
"scout:tanned_leather",
|
||||
"scout:pouch",
|
||||
"scout:satchel_strap",
|
||||
"scout:upgraded_pouch",
|
||||
"scout:upgraded_satchel",
|
||||
"scout:satchel"
|
||||
]
|
||||
}
|
BIN
src/main/resources/assets/scout/icon.png
Normal file
After Width: | Height: | Size: 678 B |
14
src/main/resources/assets/scout/lang/en_us.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"lib39:enable_enhanced_lang": true,
|
||||
"itemGroup.scout.itemgroup": "Scout",
|
||||
"item.scout": {
|
||||
"tanned_leather": "Tanned Leather",
|
||||
"satchel_strap": "Satchel Strap",
|
||||
"satchel": "Satchel",
|
||||
"upgraded_satchel": "Upgraded Satchel",
|
||||
"pouch": "Pouch",
|
||||
"upgraded_pouch": "Upgraded Pouch"
|
||||
},
|
||||
"trinkets.slot.legs.pouch": "Pouch",
|
||||
"tooltip.scout.slots": "Holds {} items"
|
||||
}
|
6
src/main/resources/assets/scout/models/item/pouch.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "scout:item/pouch"
|
||||
}
|
||||
}
|
6
src/main/resources/assets/scout/models/item/satchel.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "scout:item/satchel"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "scout:item/satchel_strap"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "scout:item/tanned_leather"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "scout:item/upgraded_pouch"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "scout:item/upgraded_satchel"
|
||||
}
|
||||
}
|
BIN
src/main/resources/assets/scout/textures/entity/satchel.png
Normal file
After Width: | Height: | Size: 279 B |
After Width: | Height: | Size: 5.3 KiB |
BIN
src/main/resources/assets/scout/textures/gui/pouch_slot.png
Normal file
After Width: | Height: | Size: 229 B |
BIN
src/main/resources/assets/scout/textures/gui/slots.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
src/main/resources/assets/scout/textures/item/pouch.png
Normal file
After Width: | Height: | Size: 479 B |
BIN
src/main/resources/assets/scout/textures/item/satchel.png
Normal file
After Width: | Height: | Size: 326 B |
BIN
src/main/resources/assets/scout/textures/item/satchel_strap.png
Normal file
After Width: | Height: | Size: 193 B |
BIN
src/main/resources/assets/scout/textures/item/tanned_leather.png
Normal file
After Width: | Height: | Size: 377 B |
BIN
src/main/resources/assets/scout/textures/item/upgraded_pouch.png
Normal file
After Width: | Height: | Size: 473 B |
After Width: | Height: | Size: 323 B |
6
src/main/resources/data/c/tags/items/leather.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:leather"
|
||||
]
|
||||
}
|
6
src/main/resources/data/c/tags/items/string.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"minecraft:string"
|
||||
]
|
||||
}
|
19
src/main/resources/data/scout/recipes/pouch.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"lib39:discovered_via": "minecraft:leather",
|
||||
"pattern": ["sls", "lbl", "sls"],
|
||||
"key": {
|
||||
"l": {
|
||||
"tag": "c:leather"
|
||||
},
|
||||
"s": {
|
||||
"tag": "c:string"
|
||||
},
|
||||
"b": {
|
||||
"item": "minecraft:stone_button"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "scout:pouch"
|
||||
}
|
||||
}
|
22
src/main/resources/data/scout/recipes/satchel.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shaped",
|
||||
"lib39:discovered_via": "scout:satchel_strap",
|
||||
"pattern": ["SlS", "lbl", "sls"],
|
||||
"key": {
|
||||
"l": {
|
||||
"item": "scout:tanned_leather"
|
||||
},
|
||||
"s": {
|
||||
"tag": "c:string"
|
||||
},
|
||||
"b": {
|
||||
"item": "minecraft:stone_button"
|
||||
},
|
||||
"S": {
|
||||
"item": "scout:satchel_strap"
|
||||
}
|
||||
},
|
||||
"result": {
|
||||
"item": "scout:satchel"
|
||||
}
|
||||
}
|
18
src/main/resources/data/scout/recipes/satchel_strap.json
Normal file
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"lib39:discovered_via": "scout:tanned_leather",
|
||||
"ingredients": [
|
||||
{
|
||||
"item": "scout:tanned_leather"
|
||||
},
|
||||
{
|
||||
"tag": "c:string"
|
||||
},
|
||||
{
|
||||
"item": "scout:tanned_leather"
|
||||
}
|
||||
],
|
||||
"result": {
|
||||
"item": "scout:satchel_strap"
|
||||
}
|
||||
}
|
10
src/main/resources/data/scout/recipes/tanned_leather.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"type": "minecraft:campfire_cooking",
|
||||
"lib39:discovered_via": "minecraft:leather",
|
||||
"ingredient": {
|
||||
"tag": "c:leather"
|
||||
},
|
||||
"result": "scout:tanned_leather",
|
||||
"experience": 0,
|
||||
"cookingtime": 600
|
||||
}
|
13
src/main/resources/data/scout/recipes/upgraded_pouch.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"type": "minecraft:smithing",
|
||||
"lib39:discovered_via": "minecraft:diamond",
|
||||
"base": {
|
||||
"item": "scout:pouch"
|
||||
},
|
||||
"addition": {
|
||||
"item": "minecraft:diamond"
|
||||
},
|
||||
"result": {
|
||||
"item": "scout:upgraded_pouch"
|
||||
}
|
||||
}
|
13
src/main/resources/data/scout/recipes/upgraded_satchel.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"type": "minecraft:smithing",
|
||||
"lib39:discovered_via": "minecraft:diamond",
|
||||
"base": {
|
||||
"item": "scout:satchel"
|
||||
},
|
||||
"addition": {
|
||||
"item": "minecraft:diamond"
|
||||
},
|
||||
"result": {
|
||||
"item": "scout:upgraded_satchel"
|
||||
}
|
||||
}
|
7
src/main/resources/data/trinkets/entities/scout.json
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"entities": ["player"],
|
||||
"slots": [
|
||||
"chest/back",
|
||||
"legs/pouch"
|
||||
]
|
||||
}
|
5
src/main/resources/data/trinkets/slots/legs/pouch.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"replace": false,
|
||||
"amount": 2,
|
||||
"icon": "scout:gui/pouch_slot"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"scout:satchel",
|
||||
"scout:upgraded_satchel"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"replace": false,
|
||||
"values": [
|
||||
"scout:pouch",
|
||||
"scout:upgraded_pouch"
|
||||
]
|
||||
}
|
91
src/main/resources/quilt.mod.json
Normal file
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
"schema_version": 1,
|
||||
"quilt_loader": {
|
||||
"group": "pm.c7.scout",
|
||||
"id": "scout",
|
||||
"version": "${version}",
|
||||
"metadata": {
|
||||
"name": "Scout",
|
||||
"description": "A mod focused on \"physically\" extending the inventory (adding slots) through wearing various types of bags.",
|
||||
"contributors": {
|
||||
"Cynosphere": "Owner, Developer",
|
||||
"Kat": "Original pouch texture",
|
||||
"makamys": "Original idea"
|
||||
},
|
||||
"contact": {
|
||||
"sources": "https://gitdab.com/Cynosphere-mc/Scout"
|
||||
},
|
||||
"icon": "assets/scout/icon.png"
|
||||
},
|
||||
"intermediate_mappings": "net.fabricmc:intermediary",
|
||||
"entrypoints": {
|
||||
"init": "pm.c7.scout.Scout",
|
||||
"client_init": "pm.c7.scout.client.ScoutClient",
|
||||
"emi": "pm.c7.scout.client.compat.ScoutEmiPlugin"
|
||||
},
|
||||
"depends": [
|
||||
{
|
||||
"id": "quilt_loader",
|
||||
"versions": ">=0.17.0-"
|
||||
},
|
||||
{
|
||||
"id": "quilted_fabric_api",
|
||||
"versions": ">=4.0.0-"
|
||||
},
|
||||
{
|
||||
"id": "minecraft",
|
||||
"versions": ">=${minecraft_version}"
|
||||
},
|
||||
{
|
||||
"id": "trinkets",
|
||||
"versions": ">=${trinkets_version}"
|
||||
},
|
||||
{
|
||||
"id": "lib39-core",
|
||||
"versions": ">=${lib39_version}"
|
||||
},
|
||||
{
|
||||
"id": "lib39-dessicant",
|
||||
"versions": ">=${lib39_version}"
|
||||
},
|
||||
{
|
||||
"id": "emi",
|
||||
"versions": ">=${emi_version}",
|
||||
"optional": true
|
||||
}
|
||||
],
|
||||
"breaks": [
|
||||
{
|
||||
"id": "roughlyenoughitems",
|
||||
"versions": "*",
|
||||
"reason": "API constantly rewritten for no reason, arrogant mod author, features stolen from EMI."
|
||||
},
|
||||
{
|
||||
"id": "inventoryprofilesnext",
|
||||
"versions": "*",
|
||||
"reason": "Crashes with no intent to fix on their end."
|
||||
},
|
||||
{
|
||||
"id": "infinitory",
|
||||
"versions": "*",
|
||||
"reason": "Infinite/Incompatible inventory mod."
|
||||
},
|
||||
{
|
||||
"id": "biginv",
|
||||
"versions": "*",
|
||||
"reason": "Infinite/Incompatible inventory mod."
|
||||
},
|
||||
{
|
||||
"id": "extrainv",
|
||||
"versions": "*",
|
||||
"reason": "Infinite/Incompatible inventory mod."
|
||||
},
|
||||
{
|
||||
"id": "inventory_backpack",
|
||||
"versions": "*",
|
||||
"reason": "Infinite/Incompatible inventory mod."
|
||||
}
|
||||
]
|
||||
},
|
||||
"mixin": "scout.mixins.json"
|
||||
}
|
10
src/main/resources/scout.mixins.json
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"required": true,
|
||||
"minVersion": "0.8",
|
||||
"package": "pm.c7.scout.mixin",
|
||||
"compatibilityLevel": "JAVA_17",
|
||||
"plugin": "pm.c7.scout.ScoutMixin",
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|