1.20.4 compatibility
This commit is contained in:
parent
c5132221ae
commit
27627e8404
83
build.gradle
Normal file
83
build.gradle
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
plugins {
|
||||||
|
id 'fabric-loom' version '1.6-SNAPSHOT'
|
||||||
|
id 'maven-publish'
|
||||||
|
}
|
||||||
|
|
||||||
|
version = project.mod_version
|
||||||
|
group = project.maven_group
|
||||||
|
|
||||||
|
base {
|
||||||
|
archivesName = project.archives_base_name
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
// Add repositories to retrieve artifacts from in here.
|
||||||
|
// You should only use this when depending on other mods because
|
||||||
|
// Loom adds the essential maven repositories to download Minecraft and libraries from automatically.
|
||||||
|
// See https://docs.gradle.org/current/userguide/declaring_repositories.html
|
||||||
|
// for more information about repositories.
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compileOnly 'org.projectlombok:lombok:1.18.24'
|
||||||
|
annotationProcessor 'org.projectlombok:lombok:1.18.24'
|
||||||
|
|
||||||
|
//add joml
|
||||||
|
modImplementation 'org.joml:joml:1.10.4'
|
||||||
|
include 'org.joml:joml:1.10.4'
|
||||||
|
|
||||||
|
// To change the versions see the gradle.properties file
|
||||||
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
|
mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2"
|
||||||
|
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||||
|
|
||||||
|
// Fabric API. This is technically optional, but you probably want it anyway.
|
||||||
|
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
processResources {
|
||||||
|
inputs.property "version", project.version
|
||||||
|
|
||||||
|
filesMatching("fabric.mod.json") {
|
||||||
|
expand "version": project.version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType(JavaCompile).configureEach {
|
||||||
|
it.options.release = 17
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
// Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task
|
||||||
|
// if it is present.
|
||||||
|
// If you remove this line, sources will not be generated.
|
||||||
|
withSourcesJar()
|
||||||
|
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
from("LICENSE") {
|
||||||
|
rename { "${it}_${project.base.archivesName.get()}"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure the maven publication
|
||||||
|
publishing {
|
||||||
|
publications {
|
||||||
|
create("mavenJava", MavenPublication) {
|
||||||
|
artifactId = project.archives_base_name
|
||||||
|
from components.java
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||||
|
repositories {
|
||||||
|
// Add repositories to publish to here.
|
||||||
|
// Notice: This block does NOT have the same function as the block in the top level.
|
||||||
|
// The repositories here will be used for publishing your artifact, not for
|
||||||
|
// retrieving dependencies.
|
||||||
|
}
|
||||||
|
}
|
@ -4,14 +4,14 @@ org.gradle.parallel=true
|
|||||||
|
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://fabricmc.net/develop
|
# check these on https://fabricmc.net/develop
|
||||||
minecraft_version=1.20.1
|
minecraft_version=1.20.4
|
||||||
yarn_mappings=1.20.1+build.10
|
yarn_mappings=1.20.4+build.3
|
||||||
loader_version=0.15.10
|
loader_version=0.15.10
|
||||||
|
|
||||||
#Fabric api
|
#Fabric api
|
||||||
fabric_version=0.92.1+1.20.1
|
fabric_version=0.97.0+1.20.4
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version = 1.1.0
|
mod_version = 1.1.0+1.20.4
|
||||||
maven_group = themixray.repeating.mod
|
maven_group = themixray.repeating.mod
|
||||||
archives_base_name = repeating-mod
|
archives_base_name = repeating-mod
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
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.7-bin.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
249
gradlew
vendored
Normal file
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
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. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
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
|
103
remappedSrc/themixray/repeating/mod/EasyConfig.java
Normal file
103
remappedSrc/themixray/repeating/mod/EasyConfig.java
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
public class EasyConfig {
|
||||||
|
public final Path path;
|
||||||
|
public final File file;
|
||||||
|
public Map<String,String> data;
|
||||||
|
|
||||||
|
public EasyConfig(File f, Map<String,String> def) {
|
||||||
|
this.path = f.toPath();
|
||||||
|
this.file = f;
|
||||||
|
this.data = new HashMap<>();
|
||||||
|
|
||||||
|
if (!file.exists()) {
|
||||||
|
try {
|
||||||
|
file.createNewFile();
|
||||||
|
write(def);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reload();
|
||||||
|
|
||||||
|
for (Map.Entry<String,String> m:def.entrySet())
|
||||||
|
if (!data.containsKey(m.getKey()))
|
||||||
|
data.put(m.getKey(),m.getValue());
|
||||||
|
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
public EasyConfig(Path f, Map<String,String> def) {
|
||||||
|
this(f.toFile(),def);
|
||||||
|
}
|
||||||
|
public EasyConfig(String parent,String child,Map<String,String> def) {
|
||||||
|
this(new File(parent,child),def);
|
||||||
|
}
|
||||||
|
public EasyConfig(File parent,String child,Map<String,String> def) {
|
||||||
|
this(new File(parent,child),def);
|
||||||
|
}
|
||||||
|
public EasyConfig(Path parent,String child,Map<String,String> def) {
|
||||||
|
this(new File(parent.toFile(),child),def);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EasyConfig(File f) {
|
||||||
|
this(f,new HashMap<>());
|
||||||
|
}
|
||||||
|
public EasyConfig(Path path) {
|
||||||
|
this(path.toFile(),new HashMap<>());
|
||||||
|
}
|
||||||
|
public EasyConfig(String parent,String child) {
|
||||||
|
this(new File(parent,child),new HashMap<>());
|
||||||
|
}
|
||||||
|
public EasyConfig(File parent,String child) {
|
||||||
|
this(new File(parent,child),new HashMap<>());
|
||||||
|
}
|
||||||
|
public EasyConfig(Path parent,String child) {
|
||||||
|
this(new File(parent.toFile(),child),new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
data = read();
|
||||||
|
}
|
||||||
|
public void save() {
|
||||||
|
write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toText(Map<String,String> p) {
|
||||||
|
StringBuilder t = new StringBuilder();
|
||||||
|
for (Map.Entry<String,String> e:p.entrySet())
|
||||||
|
t.append(e.getKey()).append("=").append(e.getValue()).append("\n");
|
||||||
|
return t.toString();
|
||||||
|
}
|
||||||
|
private Map<String,String> toMap(String j) {
|
||||||
|
Map<String,String> m = new HashMap<>();
|
||||||
|
for (String l:j.split("\n")) {
|
||||||
|
String s[] = l.split("=");
|
||||||
|
m.put(s[0],s[1]);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String,String> read() {
|
||||||
|
try {
|
||||||
|
return toMap(Files.readString(path));
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
private void write(Map<String,String> p) {
|
||||||
|
try {
|
||||||
|
Files.write(path, toText(p).getBytes());
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
325
remappedSrc/themixray/repeating/mod/Main.java
Normal file
325
remappedSrc/themixray/repeating/mod/Main.java
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import net.fabricmc.api.ClientModInitializer;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
|
||||||
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.option.KeyBinding;
|
||||||
|
import net.minecraft.client.util.InputUtil;
|
||||||
|
import net.minecraft.text.MutableText;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import net.minecraft.util.Formatting;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.lwjgl.glfw.GLFW;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import themixray.repeating.mod.event.RecordDelayEvent;
|
||||||
|
import themixray.repeating.mod.event.RecordEvent;
|
||||||
|
import themixray.repeating.mod.event.RecordInputEvent;
|
||||||
|
import themixray.repeating.mod.event.RecordMoveEvent;
|
||||||
|
import themixray.repeating.mod.render.RenderHelper;
|
||||||
|
import themixray.repeating.mod.render.RenderSystem;
|
||||||
|
import themixray.repeating.mod.render.buffer.WorldBuffer;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class Main implements ClientModInitializer {
|
||||||
|
public static final Logger LOGGER = LoggerFactory.getLogger("repeating-mod");
|
||||||
|
public static final MinecraftClient client = MinecraftClient.getInstance();
|
||||||
|
public static final FabricLoader loader = FabricLoader.getInstance();
|
||||||
|
public static Main me;
|
||||||
|
|
||||||
|
public RecordList record_list;
|
||||||
|
public RecordState now_record;
|
||||||
|
|
||||||
|
public boolean is_recording = false;
|
||||||
|
public long last_record = -1;
|
||||||
|
public TickTask move_tick = null;
|
||||||
|
|
||||||
|
public TickTask replay_tick = null;
|
||||||
|
public boolean is_replaying = false;
|
||||||
|
public boolean loop_replay = false;
|
||||||
|
public static RecordInputEvent input_replay = null;
|
||||||
|
|
||||||
|
public long living_ticks = 0;
|
||||||
|
|
||||||
|
public static RepeatingScreen menu;
|
||||||
|
private static KeyBinding menu_key;
|
||||||
|
private static KeyBinding toggle_replay_key;
|
||||||
|
private static KeyBinding toggle_record_key;
|
||||||
|
|
||||||
|
public long record_pos_delay = 20;
|
||||||
|
|
||||||
|
public static Random rand = new Random();
|
||||||
|
|
||||||
|
public EasyConfig conf;
|
||||||
|
public File records_folder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onInitializeClient() {
|
||||||
|
LOGGER.info("Repeating mod initialized");
|
||||||
|
me = this;
|
||||||
|
|
||||||
|
now_record = null;
|
||||||
|
|
||||||
|
records_folder = new File(FabricLoader.getInstance().getGameDir().toFile(),"repeating_mod_records");
|
||||||
|
if (!records_folder.exists()) records_folder.mkdir();
|
||||||
|
|
||||||
|
record_list = new RecordList(records_folder);
|
||||||
|
record_list.loadRecords();
|
||||||
|
|
||||||
|
RenderSystem.init();
|
||||||
|
WorldRenderEvents.LAST.register(context -> {
|
||||||
|
WorldBuffer buffer = RenderHelper.startTri(context);
|
||||||
|
if (now_record != null) {
|
||||||
|
Vec3d start_pos = now_record.getStartRecordPos();
|
||||||
|
Vec3d finish_pos = now_record.getFinishRecordPos();
|
||||||
|
|
||||||
|
if (start_pos != null) drawRecordPos(buffer, start_pos, new Color(70, 230, 70, 128));
|
||||||
|
if (finish_pos != null) drawRecordPos(buffer, finish_pos, new Color(230, 70, 70, 128));
|
||||||
|
}
|
||||||
|
RenderHelper.endTri(buffer);
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String,String> def = new HashMap<>();
|
||||||
|
def.put("record_pos_delay", String.valueOf(record_pos_delay));
|
||||||
|
|
||||||
|
conf = new EasyConfig(loader.getConfigDir(),"repeating-mod",def);
|
||||||
|
|
||||||
|
record_pos_delay = Long.parseLong(conf.data.get("record_pos_delay"));
|
||||||
|
|
||||||
|
menu_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.menu",InputUtil.Type.KEYSYM,
|
||||||
|
GLFW.GLFW_KEY_J,"text.repeating-mod.name"));
|
||||||
|
toggle_replay_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.toggle_replay",InputUtil.Type.KEYSYM,
|
||||||
|
-1,"text.repeating-mod.name"));
|
||||||
|
toggle_record_key = KeyBindingHelper.registerKeyBinding(new KeyBinding(
|
||||||
|
"key.repeating-mod.toggle_record",InputUtil.Type.KEYSYM,
|
||||||
|
-1,"text.repeating-mod.name"));
|
||||||
|
|
||||||
|
menu = new RepeatingScreen();
|
||||||
|
ClientTickEvents.END_CLIENT_TICK.register(client -> {
|
||||||
|
if (menu_key.wasPressed())
|
||||||
|
client.setScreen(menu);
|
||||||
|
if (toggle_replay_key.wasPressed()) {
|
||||||
|
if (now_record != null) {
|
||||||
|
if (!is_recording) {
|
||||||
|
if (is_replaying)
|
||||||
|
stopReplay();
|
||||||
|
else startReplay();
|
||||||
|
menu.updateButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (toggle_record_key.wasPressed()) {
|
||||||
|
if (!is_replaying) {
|
||||||
|
if (is_recording)
|
||||||
|
stopRecording();
|
||||||
|
else startRecording();
|
||||||
|
menu.updateButtons();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
new TickTask(0,0) {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
living_ticks++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
System.setProperty("java.awt.headless", "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNowRecord(RecordState record) {
|
||||||
|
now_record = record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRecordPos(WorldBuffer buffer, Vec3d pos, Color color) {
|
||||||
|
RenderHelper.drawRectFromTri(buffer,
|
||||||
|
(float) pos.getX() - 0.25F,
|
||||||
|
(float) pos.getY() + 0.01F,
|
||||||
|
(float) pos.getZ() - 0.25F,
|
||||||
|
|
||||||
|
(float) pos.getX() + 0.25F,
|
||||||
|
(float) pos.getY() + 0.01F,
|
||||||
|
(float) pos.getZ() - 0.25F,
|
||||||
|
|
||||||
|
(float) pos.getX() + 0.25F,
|
||||||
|
(float) pos.getY() + 0.01F,
|
||||||
|
(float) pos.getZ() + 0.25F,
|
||||||
|
|
||||||
|
(float) pos.getX() - 0.25F,
|
||||||
|
(float) pos.getY() + 0.01F,
|
||||||
|
(float) pos.getZ() + 0.25F,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void startRecording() {
|
||||||
|
is_recording = true;
|
||||||
|
menu.updateButtons();
|
||||||
|
|
||||||
|
now_record = record_list.newRecord();
|
||||||
|
|
||||||
|
Vec3d start_pos = client.player.getPos();
|
||||||
|
now_record.addEvent(new RecordMoveEvent(start_pos,client.player.getHeadYaw(),client.player.getPitch()));
|
||||||
|
now_record.setStartRecordPos(start_pos);
|
||||||
|
|
||||||
|
if (record_pos_delay > 0) {
|
||||||
|
move_tick = new TickTask(
|
||||||
|
record_pos_delay,
|
||||||
|
record_pos_delay) {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
now_record.addEvent(new RecordMoveEvent(client.player.getPos(),
|
||||||
|
client.player.getHeadYaw(), client.player.getPitch()));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.record_start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordTick(RecordEvent e) {
|
||||||
|
if (is_recording) {
|
||||||
|
long now = living_ticks;
|
||||||
|
if (last_record != -1) {
|
||||||
|
long diff = now - last_record - 2;
|
||||||
|
if (diff > 0) now_record.addEvent(new RecordDelayEvent(diff));
|
||||||
|
}
|
||||||
|
now_record.addEvent(e);
|
||||||
|
last_record = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordAllInput() {
|
||||||
|
if (client.player == null) {
|
||||||
|
stopRecording();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecordInputEvent l = ((RecordInputEvent) now_record.getLastEvent("input"));
|
||||||
|
if (l == null) {
|
||||||
|
RecordInputEvent e = new RecordInputEvent(
|
||||||
|
client.player.input.sneaking,
|
||||||
|
client.player.input.jumping,
|
||||||
|
client.player.input.movementSideways,
|
||||||
|
client.player.input.movementForward,
|
||||||
|
client.player.input.pressingForward,
|
||||||
|
client.player.input.pressingBack,
|
||||||
|
client.player.input.pressingLeft,
|
||||||
|
client.player.input.pressingRight,
|
||||||
|
client.player.getHeadYaw(),
|
||||||
|
client.player.getBodyYaw(),
|
||||||
|
client.player.getPitch(),
|
||||||
|
client.player.isSprinting(),
|
||||||
|
client.player.getYaw(),
|
||||||
|
client.player.getMovementSpeed());
|
||||||
|
recordTick(e);
|
||||||
|
} else {
|
||||||
|
RecordInputEvent e = new RecordInputEvent(
|
||||||
|
((Boolean) client.player.input.sneaking == l.sneaking) ? null : client.player.input.sneaking,
|
||||||
|
((Boolean) client.player.input.jumping == l.jumping) ? null : client.player.input.jumping,
|
||||||
|
(((Float) client.player.input.movementSideways).equals(l.movementSideways)) ? null : client.player.input.movementSideways,
|
||||||
|
(((Float) client.player.input.movementForward).equals(l.movementForward)) ? null : client.player.input.movementForward,
|
||||||
|
((Boolean) client.player.input.pressingForward == l.pressingForward) ? null : client.player.input.pressingForward,
|
||||||
|
((Boolean) client.player.input.pressingBack == l.pressingBack) ? null : client.player.input.pressingBack,
|
||||||
|
((Boolean) client.player.input.pressingLeft == l.pressingLeft) ? null : client.player.input.pressingLeft,
|
||||||
|
((Boolean) client.player.input.pressingRight == l.pressingRight) ? null : client.player.input.pressingRight,
|
||||||
|
client.player.getHeadYaw(), Main.client.player.getBodyYaw(),client.player.getPitch(),
|
||||||
|
((Boolean) client.player.isSprinting() == l.sprinting) ? null : client.player.isSprinting(),
|
||||||
|
client.player.getYaw(),client.player.getMovementSpeed());
|
||||||
|
|
||||||
|
if (!(e.isEmpty() &&
|
||||||
|
e.yaw == l.yaw &&
|
||||||
|
e.head_yaw == l.head_yaw &&
|
||||||
|
e.pitch == l.pitch &&
|
||||||
|
e.body_yaw == l.body_yaw)) {
|
||||||
|
e.fillEmpty(l);
|
||||||
|
recordTick(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopRecording() {
|
||||||
|
is_recording = false;
|
||||||
|
now_record.setFinishRecordPos(client.player.getPos());
|
||||||
|
try {
|
||||||
|
now_record.save();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
if (move_tick != null) {
|
||||||
|
move_tick.cancel();
|
||||||
|
move_tick = null;
|
||||||
|
}
|
||||||
|
menu.updateButtons();
|
||||||
|
last_record = -1;
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.record_stop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void startReplay() {
|
||||||
|
is_recording = false;
|
||||||
|
is_replaying = true;
|
||||||
|
menu.updateButtons();
|
||||||
|
|
||||||
|
List<RecordEvent> events = now_record.getEvents();
|
||||||
|
|
||||||
|
replay_tick = new TickTask(0,0, TickTask.TickAt.CLIENT_TAIL) {
|
||||||
|
public int replay_index = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!is_replaying) cancel();
|
||||||
|
RecordEvent e = events.get(replay_index);
|
||||||
|
if (e instanceof RecordDelayEvent) {
|
||||||
|
setDelay(((RecordDelayEvent) e).delay);
|
||||||
|
} else {
|
||||||
|
e.replay();
|
||||||
|
}
|
||||||
|
|
||||||
|
replay_index++;
|
||||||
|
if (!loop_replay) {
|
||||||
|
if (replay_index == events.size()) {
|
||||||
|
stopReplay();
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
} else if (replay_index == events.size()) {
|
||||||
|
replay_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.replay_start"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopReplay() {
|
||||||
|
is_recording = false;
|
||||||
|
is_replaying = false;
|
||||||
|
if (replay_tick != null) {
|
||||||
|
replay_tick.cancel();
|
||||||
|
replay_tick = null;
|
||||||
|
}
|
||||||
|
menu.updateButtons();
|
||||||
|
record_list.getWidget().getWidget(now_record).getChildren().get(3).setMessage(Text.translatable("text.repeating-mod.start"));
|
||||||
|
sendMessage(Text.translatable("message.repeating-mod.replay_stop"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendMessage(MutableText text) {
|
||||||
|
client.player.sendMessage(Text.literal("[")
|
||||||
|
.append(Text.translatable("text.repeating-mod.name"))
|
||||||
|
.append("] ").formatted(Formatting.BOLD,Formatting.DARK_GRAY)
|
||||||
|
.append(text.formatted(Formatting.RESET).formatted(Formatting.GRAY)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void sendDebug(String s) {
|
||||||
|
client.player.sendMessage(Text.literal("[DEBUG] ").append(Text.of(s)));
|
||||||
|
}
|
||||||
|
}
|
77
remappedSrc/themixray/repeating/mod/RecordList.java
Normal file
77
remappedSrc/themixray/repeating/mod/RecordList.java
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import themixray.repeating.mod.widget.RecordListWidget;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RecordList {
|
||||||
|
private final File folder;
|
||||||
|
private List<RecordState> records;
|
||||||
|
private RecordListWidget widget;
|
||||||
|
|
||||||
|
public RecordList(File folder) {
|
||||||
|
this.folder = folder;
|
||||||
|
this.records = new ArrayList<>();
|
||||||
|
this.widget = new RecordListWidget(0, 0, 180, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RecordState> getRecords() {
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFolder() {
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordListWidget getWidget() {
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void loadRecords() {
|
||||||
|
for (File file : folder.listFiles()) {
|
||||||
|
try {
|
||||||
|
addRecord(file);
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRecord(File file) throws Exception {
|
||||||
|
addRecord(RecordState.load(file));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addRecord(RecordState record) {
|
||||||
|
records.add(record);
|
||||||
|
widget.addWidget(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRecord(RecordState record) {
|
||||||
|
records.remove(record);
|
||||||
|
widget.removeWidget(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordState newRecord() {
|
||||||
|
Date date = new Date();
|
||||||
|
String name = "Unnamed";
|
||||||
|
String author = Main.client.player.getName().getString();
|
||||||
|
|
||||||
|
File file = new File(Main.me.records_folder,
|
||||||
|
"record_" + RecordState.FILE_DATE_FORMAT.format(date) +
|
||||||
|
"_" + Main.rand.nextInt(10) + ".rrm");
|
||||||
|
|
||||||
|
RecordState state = new RecordState(
|
||||||
|
file, name, date, author,
|
||||||
|
new ArrayList<>(),
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
|
||||||
|
addRecord(state);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
169
remappedSrc/themixray/repeating/mod/RecordState.java
Normal file
169
remappedSrc/themixray/repeating/mod/RecordState.java
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import themixray.repeating.mod.event.RecordEvent;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class RecordState {
|
||||||
|
public static SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("MM.dd.yyyy HH:mm:ss");
|
||||||
|
public static SimpleDateFormat FILE_DATE_FORMAT = new SimpleDateFormat("MM-dd-yyyy_HH-mm-ss");
|
||||||
|
|
||||||
|
private final File file;
|
||||||
|
private String name;
|
||||||
|
private Date date;
|
||||||
|
private String author;
|
||||||
|
|
||||||
|
private List<RecordEvent> events;
|
||||||
|
private Vec3d start_record_pos;
|
||||||
|
private Vec3d finish_record_pos;
|
||||||
|
|
||||||
|
public RecordState(File file,
|
||||||
|
String name,
|
||||||
|
Date date,
|
||||||
|
String author,
|
||||||
|
List<RecordEvent> events,
|
||||||
|
Vec3d start_record_pos,
|
||||||
|
Vec3d finish_record_pos) {
|
||||||
|
this.file = file;
|
||||||
|
this.name = name;
|
||||||
|
this.date = date;
|
||||||
|
this.author = author;
|
||||||
|
|
||||||
|
this.events = events;
|
||||||
|
this.start_record_pos = start_record_pos;
|
||||||
|
this.finish_record_pos = finish_record_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAuthor() {
|
||||||
|
return author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getDate() {
|
||||||
|
return date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RecordEvent> getEvents() {
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3d getFinishRecordPos() {
|
||||||
|
return finish_record_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3d getStartRecordPos() {
|
||||||
|
return start_record_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAuthor(String author) {
|
||||||
|
this.author = author;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDate(Date date) {
|
||||||
|
this.date = date;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvents(List<RecordEvent> events) {
|
||||||
|
this.events = events;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFinishRecordPos(Vec3d finish_record_pos) {
|
||||||
|
this.finish_record_pos = finish_record_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStartRecordPos(Vec3d start_record_pos) {
|
||||||
|
this.start_record_pos = start_record_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addEvent(RecordEvent event) {
|
||||||
|
events.add(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordEvent getLastEvent(String type) {
|
||||||
|
for (RecordEvent r: Lists.reverse(new ArrayList<>(events))) {
|
||||||
|
if (r.getType().equals(type)) {
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() throws IOException {
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
|
||||||
|
text.append(name).append("\n")
|
||||||
|
.append(DATE_FORMAT.format(date)).append("\n")
|
||||||
|
.append(author).append("\n");
|
||||||
|
|
||||||
|
text.append(start_record_pos.getX()).append("n")
|
||||||
|
.append(start_record_pos.getY()).append("n")
|
||||||
|
.append(start_record_pos.getZ()).append("x")
|
||||||
|
.append(finish_record_pos.getX()).append("n")
|
||||||
|
.append(finish_record_pos.getY()).append("n")
|
||||||
|
.append(finish_record_pos.getZ());
|
||||||
|
|
||||||
|
for (int i = 0; i < events.size(); i++) {
|
||||||
|
text.append("\n");
|
||||||
|
text.append(events.get(i).serialize());
|
||||||
|
}
|
||||||
|
|
||||||
|
Files.write(file.toPath(), text.toString().getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RecordState load(File file) throws Exception {
|
||||||
|
String text = Files.readString(file.toPath());
|
||||||
|
List<String> lines = List.of(text.split("\n"));
|
||||||
|
|
||||||
|
List<String> signature = lines.subList(0,4);
|
||||||
|
|
||||||
|
String name = signature.get(0);
|
||||||
|
Date date = DATE_FORMAT.parse(signature.get(1));
|
||||||
|
String author = signature.get(2);
|
||||||
|
|
||||||
|
String record_pos = signature.get(3);
|
||||||
|
|
||||||
|
String[] lss0 = record_pos.split("x");
|
||||||
|
String[] lss1 = lss0[0].split("n");
|
||||||
|
String[] lss2 = lss0[1].split("n");
|
||||||
|
|
||||||
|
Vec3d start_record_pos = new Vec3d(
|
||||||
|
Float.parseFloat(lss1[0]),
|
||||||
|
Float.parseFloat(lss1[1]),
|
||||||
|
Float.parseFloat(lss1[2]));
|
||||||
|
Vec3d finish_record_pos = new Vec3d(
|
||||||
|
Float.parseFloat(lss2[0]),
|
||||||
|
Float.parseFloat(lss2[1]),
|
||||||
|
Float.parseFloat(lss2[2]));
|
||||||
|
|
||||||
|
List<String> event_lines = lines.subList(4,lines.size());
|
||||||
|
List<RecordEvent> events = event_lines.stream().map(RecordEvent::deserialize).toList();
|
||||||
|
|
||||||
|
return new RecordState(file, name, date, author, events, start_record_pos, finish_record_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
file.delete();
|
||||||
|
Main.me.record_list.removeRecord(this);
|
||||||
|
Main.me.record_list.getWidget().removeWidget(this);
|
||||||
|
}
|
||||||
|
}
|
11
remappedSrc/themixray/repeating/mod/RenderListener.java
Normal file
11
remappedSrc/themixray/repeating/mod/RenderListener.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
|
||||||
|
public interface RenderListener {
|
||||||
|
default boolean beforeRender() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render(DrawContext context, int mouseX, int mouseY, float delta);
|
||||||
|
}
|
193
remappedSrc/themixray/repeating/mod/RepeatingScreen.java
Normal file
193
remappedSrc/themixray/repeating/mod/RepeatingScreen.java
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import net.fabricmc.api.EnvType;
|
||||||
|
import net.fabricmc.api.Environment;
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.Drawable;
|
||||||
|
import net.minecraft.client.gui.Element;
|
||||||
|
import net.minecraft.client.gui.Selectable;
|
||||||
|
import net.minecraft.client.gui.screen.Screen;
|
||||||
|
import net.minecraft.client.gui.tooltip.Tooltip;
|
||||||
|
import net.minecraft.client.gui.widget.ButtonWidget;
|
||||||
|
import net.minecraft.client.gui.widget.SliderWidget;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import themixray.repeating.mod.widget.RecordListWidget;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Environment(EnvType.CLIENT)
|
||||||
|
public class RepeatingScreen extends Screen {
|
||||||
|
private static List<RenderListener> render_listeners = new ArrayList<>();
|
||||||
|
|
||||||
|
public ButtonWidget record_btn;
|
||||||
|
public ButtonWidget loop_btn;
|
||||||
|
public ButtonWidget import_btn;
|
||||||
|
|
||||||
|
public SliderWidget pos_delay_slider;
|
||||||
|
|
||||||
|
public boolean was_build = false;
|
||||||
|
|
||||||
|
protected RepeatingScreen() {
|
||||||
|
super(Text.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addRenderListener(RenderListener render) {
|
||||||
|
render_listeners.add(render);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeRenderListener(RenderListener render) {
|
||||||
|
render_listeners.remove(render);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateButtons() {
|
||||||
|
if (was_build) {
|
||||||
|
record_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.is_recording) ? "stop_record" : "start_record")));
|
||||||
|
loop_btn.setMessage(Text.translatable("text.repeating-mod." + ((Main.me.loop_replay) ? "off_loop" : "on_loop")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
renderBackground(context,mouseX,mouseY,delta);
|
||||||
|
|
||||||
|
for (RenderListener l : render_listeners) {
|
||||||
|
if (l.beforeRender()) {
|
||||||
|
l.render(context, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
|
||||||
|
for (RenderListener l : render_listeners) {
|
||||||
|
if (!l.beforeRender()) {
|
||||||
|
l.render(context, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void init() {
|
||||||
|
RecordListWidget list_widget = Main.me.record_list.getWidget();
|
||||||
|
|
||||||
|
list_widget.method_46421(width / 2 + 2);
|
||||||
|
list_widget.method_46419(height / 2 - list_widget.getHeight() / 2);
|
||||||
|
list_widget.init(this);
|
||||||
|
|
||||||
|
|
||||||
|
record_btn = ButtonWidget.builder(
|
||||||
|
Text.translatable("text.repeating-mod.start_record"), button -> {
|
||||||
|
if (!Main.me.is_replaying) {
|
||||||
|
if (Main.me.is_recording)
|
||||||
|
Main.me.stopRecording();
|
||||||
|
else Main.me.startRecording();
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.dimensions(width / 2 - 120, height / 2 - 32, 120, 20)
|
||||||
|
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.record_tooltip")))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
loop_btn = ButtonWidget.builder(Text.empty(), button -> {
|
||||||
|
Main.me.loop_replay = !Main.me.loop_replay;
|
||||||
|
updateButtons();
|
||||||
|
})
|
||||||
|
.dimensions(width / 2 - 120, height / 2 - 10, 120, 20)
|
||||||
|
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.loop_tooltip")))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
pos_delay_slider = new SliderWidget(
|
||||||
|
width / 2 - 120, height / 2 + 12, 120, 20,
|
||||||
|
(Main.me.record_pos_delay < 0) ? Text.translatable("text.repeating-mod.nan_pos_delay") :
|
||||||
|
Text.translatable("text.repeating-mod.pos_delay", String.valueOf(Main.me.record_pos_delay)),
|
||||||
|
(Main.me.record_pos_delay+1d)/101d) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateMessage() {
|
||||||
|
double v = value*101d-1d;
|
||||||
|
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
|
||||||
|
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void applyValue() {
|
||||||
|
double v = value*101d-1d;
|
||||||
|
if (v <= 1) setMessage(Text.translatable("text.repeating-mod.nan_pos_delay"));
|
||||||
|
else setMessage(Text.translatable("text.repeating-mod.pos_delay", String.valueOf((long) v)));
|
||||||
|
Main.me.record_pos_delay = (long) v;
|
||||||
|
Main.me.conf.data.put("record_pos_delay",String.valueOf(Main.me.record_pos_delay));
|
||||||
|
Main.me.conf.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRelease(double mouseX, double mouseY) {
|
||||||
|
super.onRelease(mouseX, mouseY);
|
||||||
|
applyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDrag(double mouseX, double mouseY, double deltaX, double deltaY) {
|
||||||
|
super.onDrag(mouseX, mouseY, deltaX, deltaY);
|
||||||
|
applyValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
|
super.render(context, mouseX, mouseY, delta);
|
||||||
|
updateMessage();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pos_delay_slider.setTooltip(Tooltip.of(Text.translatable("text.repeating-mod.pos_delay_tooltip")));
|
||||||
|
|
||||||
|
import_btn = ButtonWidget.builder(Text.translatable("text.repeating-mod.import"), button -> {
|
||||||
|
new Thread(() -> {
|
||||||
|
FileDialog fd = new FileDialog((java.awt.Frame) null);
|
||||||
|
fd.setMultipleMode(true);
|
||||||
|
fd.setName("Choose record files");
|
||||||
|
fd.setTitle("Choose record files");
|
||||||
|
fd.setFilenameFilter((dir, name) -> name.endsWith(".rrm"));
|
||||||
|
fd.setVisible(true);
|
||||||
|
|
||||||
|
File[] files = fd.getFiles();
|
||||||
|
if (files != null) {
|
||||||
|
for (File file : files) {
|
||||||
|
try {
|
||||||
|
Main.me.record_list.addRecord(file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}).start();
|
||||||
|
})
|
||||||
|
.dimensions(width / 2 + 2, height / 2 - list_widget.getHeight() / 2 - 22, 180, 20)
|
||||||
|
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.import_tooltip")))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
was_build = true;
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
|
||||||
|
addDrawableChild(loop_btn);
|
||||||
|
addDrawableChild(record_btn);
|
||||||
|
addDrawableChild(import_btn);
|
||||||
|
addDrawableChild(pos_delay_slider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Element & Drawable & Selectable> T addDrawableChild(T drawableElement) {
|
||||||
|
return super.addDrawableChild(drawableElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Drawable> T addDrawable(T drawable) {
|
||||||
|
return super.addDrawable(drawable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends Element & Selectable> T addSelectableChild(T child) {
|
||||||
|
return super.addSelectableChild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Element child) {
|
||||||
|
super.remove(child);
|
||||||
|
}
|
||||||
|
}
|
94
remappedSrc/themixray/repeating/mod/TickTask.java
Normal file
94
remappedSrc/themixray/repeating/mod/TickTask.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package themixray.repeating.mod;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public abstract class TickTask implements Runnable {
|
||||||
|
public static List<TickTask> tasks = new ArrayList<>();
|
||||||
|
|
||||||
|
public static void tickTasks(TickAt at) {
|
||||||
|
for (TickTask t:new ArrayList<>(tasks))
|
||||||
|
if (t.getAt() == at) t.tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long living;
|
||||||
|
private long delay;
|
||||||
|
|
||||||
|
private boolean is_repeating;
|
||||||
|
private long period;
|
||||||
|
|
||||||
|
private boolean is_cancelled;
|
||||||
|
private TickAt at;
|
||||||
|
|
||||||
|
public enum TickAt {
|
||||||
|
CLIENT_HEAD, CLIENT_TAIL,
|
||||||
|
MOVEMENT_HEAD, MOVEMENT_TAIL,
|
||||||
|
RENDER_HEAD, RENDER_TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
public TickTask(long delay, TickAt at) {
|
||||||
|
this.is_cancelled = false;
|
||||||
|
this.is_repeating = false;
|
||||||
|
this.delay = delay;
|
||||||
|
this.living = 0;
|
||||||
|
this.period = 0;
|
||||||
|
this.at = at;
|
||||||
|
tasks.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TickTask(long delay, long period, TickAt at) {
|
||||||
|
this.is_cancelled = false;
|
||||||
|
this.is_repeating = true;
|
||||||
|
this.delay = delay;
|
||||||
|
this.period = period;
|
||||||
|
this.living = 0;
|
||||||
|
this.at = at;
|
||||||
|
tasks.add(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TickTask(long delay) {
|
||||||
|
this(delay,TickAt.CLIENT_HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TickTask(long delay, long period) {
|
||||||
|
this(delay,period,TickAt.CLIENT_HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel() {
|
||||||
|
if (!is_cancelled) {
|
||||||
|
is_cancelled = true;
|
||||||
|
tasks.remove(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return is_cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TickAt getAt() {
|
||||||
|
return at;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDelay(long delay) {
|
||||||
|
if (is_repeating) {
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public long getDelay() {
|
||||||
|
return this.delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
if (living >= delay) {
|
||||||
|
if (is_repeating) {
|
||||||
|
delay = period;
|
||||||
|
run();
|
||||||
|
living = -1;
|
||||||
|
} else {
|
||||||
|
run();
|
||||||
|
cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
living++;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
package themixray.repeating.mod.event;
|
||||||
|
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
|
||||||
|
public class RecordBlockBreakEvent extends RecordEvent {
|
||||||
|
public BlockPos pos;
|
||||||
|
|
||||||
|
public static RecordBlockBreakEvent fromArgs(String[] a) {
|
||||||
|
return new RecordBlockBreakEvent(new BlockPos(
|
||||||
|
Integer.parseInt(a[0]),
|
||||||
|
Integer.parseInt(a[1]),
|
||||||
|
Integer.parseInt(a[2])));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordBlockBreakEvent(
|
||||||
|
BlockPos pos) {
|
||||||
|
this.pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replay() {
|
||||||
|
Main.client.interactionManager.breakBlock(pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
return "b=" + pos.getX() + "&" + pos.getY() + "&" + pos.getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return "block_break";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package themixray.repeating.mod.event;
|
||||||
|
|
||||||
|
import net.minecraft.util.Hand;
|
||||||
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
|
||||||
|
public class RecordBlockInteractEvent extends RecordEvent {
|
||||||
|
public Hand hand;
|
||||||
|
public BlockHitResult hitResult;
|
||||||
|
|
||||||
|
public static RecordBlockInteractEvent fromArgs(String[] a) {
|
||||||
|
return new RecordBlockInteractEvent(
|
||||||
|
Hand.valueOf(a[5]),
|
||||||
|
new BlockHitResult(new Vec3d(
|
||||||
|
Double.parseDouble(a[0]),
|
||||||
|
Double.parseDouble(a[1]),
|
||||||
|
Double.parseDouble(a[2])),
|
||||||
|
Direction.byId(Integer.parseInt(a[4])),
|
||||||
|
new BlockPos(
|
||||||
|
Integer.parseInt(a[0]),
|
||||||
|
Integer.parseInt(a[1]),
|
||||||
|
Integer.parseInt(a[2])),
|
||||||
|
a[3].equals("1")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordBlockInteractEvent(Hand hand, BlockHitResult hitResult) {
|
||||||
|
this.hand = hand;
|
||||||
|
this.hitResult = hitResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replay() {
|
||||||
|
Main.client.interactionManager.interactBlock(Main.client.player, hand, hitResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
return "i=" + hitResult.getBlockPos().getX() + "&" + hitResult.getBlockPos().getY() + "&" + hitResult.getBlockPos().getZ() +
|
||||||
|
"&" + (hitResult.isInsideBlock() ? "1" : "0") + "&" + hitResult.getSide().getId() + "&" + hand.name();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return "block_interact";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
package themixray.repeating.mod.event;
|
||||||
|
|
||||||
|
public class RecordDelayEvent extends RecordEvent {
|
||||||
|
public long delay;
|
||||||
|
|
||||||
|
public static RecordDelayEvent fromArgs(String[] a) {
|
||||||
|
return new RecordDelayEvent(Long.parseLong(a[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordDelayEvent(long delay) {
|
||||||
|
this.delay = delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replay() {
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay / 20 * 1000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
return "d=" + delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return "delay";
|
||||||
|
}
|
||||||
|
}
|
28
remappedSrc/themixray/repeating/mod/event/RecordEvent.java
Normal file
28
remappedSrc/themixray/repeating/mod/event/RecordEvent.java
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package themixray.repeating.mod.event;
|
||||||
|
|
||||||
|
public abstract class RecordEvent {
|
||||||
|
public abstract void replay();
|
||||||
|
public abstract String serialize();
|
||||||
|
public abstract String getType();
|
||||||
|
|
||||||
|
public static RecordEvent deserialize(String t) {
|
||||||
|
try {
|
||||||
|
String type = String.valueOf(t.charAt(0));
|
||||||
|
String[] args = t.substring(2).split("&");
|
||||||
|
if (type.equals("d")) {
|
||||||
|
return RecordDelayEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("m")) {
|
||||||
|
return RecordMoveEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("p")) {
|
||||||
|
return RecordInputEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("b")) {
|
||||||
|
return RecordBlockBreakEvent.fromArgs(args);
|
||||||
|
} else if (type.equals("i")) {
|
||||||
|
return RecordBlockInteractEvent.fromArgs(args);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
147
remappedSrc/themixray/repeating/mod/event/RecordInputEvent.java
Normal file
147
remappedSrc/themixray/repeating/mod/event/RecordInputEvent.java
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package themixray.repeating.mod.event;
|
||||||
|
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
|
||||||
|
public class RecordInputEvent extends RecordEvent {
|
||||||
|
public Boolean sneaking;
|
||||||
|
public Boolean jumping;
|
||||||
|
public Boolean pressingForward;
|
||||||
|
public Boolean pressingBack;
|
||||||
|
public Boolean pressingLeft;
|
||||||
|
public Boolean pressingRight;
|
||||||
|
public Boolean sprinting;
|
||||||
|
|
||||||
|
public Float movementSideways;
|
||||||
|
public Float movementForward;
|
||||||
|
|
||||||
|
public float yaw;
|
||||||
|
public float head_yaw;
|
||||||
|
public float body_yaw;
|
||||||
|
public float pitch;
|
||||||
|
public float speed;
|
||||||
|
|
||||||
|
public static RecordInputEvent fromArgs(String[] a) {
|
||||||
|
return new RecordInputEvent(
|
||||||
|
(a[0].equals("n") ? null : a[0].equals("1")),
|
||||||
|
(a[1].equals("n") ? null : a[1].equals("1")),
|
||||||
|
(a[2].equals("n") ? null : Float.parseFloat(a[2])),
|
||||||
|
(a[3].equals("n") ? null : Float.parseFloat(a[3])),
|
||||||
|
(a[4].equals("n") ? null : a[4].equals("1")),
|
||||||
|
(a[5].equals("n") ? null : a[5].equals("1")),
|
||||||
|
(a[6].equals("n") ? null : a[6].equals("1")),
|
||||||
|
(a[7].equals("n") ? null : a[7].equals("1")),
|
||||||
|
Float.parseFloat(a[8]), Float.parseFloat(a[9]),
|
||||||
|
Float.parseFloat(a[10]),
|
||||||
|
(a[11].equals("n") ? null : a[11].equals("1")),
|
||||||
|
Float.parseFloat(a[12]),
|
||||||
|
Float.parseFloat(a[13]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordInputEvent(Boolean sneaking,
|
||||||
|
Boolean jumping,
|
||||||
|
Float movementSideways,
|
||||||
|
Float movementForward,
|
||||||
|
Boolean pressingForward,
|
||||||
|
Boolean pressingBack,
|
||||||
|
Boolean pressingLeft,
|
||||||
|
Boolean pressingRight,
|
||||||
|
float head_yaw,
|
||||||
|
float body_yaw,
|
||||||
|
float head_pitch,
|
||||||
|
Boolean sprinting,
|
||||||
|
float yaw,
|
||||||
|
float speed) {
|
||||||
|
this.sneaking = sneaking;
|
||||||
|
this.jumping = jumping;
|
||||||
|
this.movementSideways = movementSideways;
|
||||||
|
this.movementForward = movementForward;
|
||||||
|
this.pressingForward = pressingForward;
|
||||||
|
this.pressingBack = pressingBack;
|
||||||
|
this.pressingLeft = pressingLeft;
|
||||||
|
this.pressingRight = pressingRight;
|
||||||
|
this.head_yaw = head_yaw;
|
||||||
|
this.body_yaw = body_yaw;
|
||||||
|
this.pitch = head_pitch;
|
||||||
|
this.sprinting = sprinting;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fillEmpty(RecordInputEvent e) {
|
||||||
|
if (sneaking == null) sneaking = e.sneaking;
|
||||||
|
if (jumping == null) jumping = e.jumping;
|
||||||
|
if (movementSideways == null) movementSideways = e.movementSideways;
|
||||||
|
if (movementForward == null) movementForward = e.movementForward;
|
||||||
|
if (pressingForward == null) pressingForward = e.pressingForward;
|
||||||
|
if (pressingBack == null) pressingBack = e.pressingBack;
|
||||||
|
if (pressingLeft == null) pressingLeft = e.pressingLeft;
|
||||||
|
if (pressingRight == null) pressingRight = e.pressingRight;
|
||||||
|
if (sprinting == null) sprinting = e.sprinting;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return sneaking == null &&
|
||||||
|
jumping == null &&
|
||||||
|
movementSideways == null &&
|
||||||
|
movementForward == null &&
|
||||||
|
pressingForward == null &&
|
||||||
|
pressingBack == null &&
|
||||||
|
pressingLeft == null &&
|
||||||
|
pressingRight == null &&
|
||||||
|
sprinting == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replay() {
|
||||||
|
Main.input_replay = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void inputCallback() {
|
||||||
|
if (sprinting != null && Main.client.player.isSprinting() != sprinting)
|
||||||
|
Main.client.player.setSprinting(sprinting);
|
||||||
|
if (Main.client.player.getYaw() != yaw)
|
||||||
|
Main.client.player.setYaw(yaw);
|
||||||
|
if (Main.client.player.getHeadYaw() != head_yaw)
|
||||||
|
Main.client.player.setHeadYaw(head_yaw);
|
||||||
|
if (Main.client.player.getBodyYaw() != body_yaw)
|
||||||
|
Main.client.player.setBodyYaw(body_yaw);
|
||||||
|
if (Main.client.player.getPitch() != pitch)
|
||||||
|
Main.client.player.setPitch(pitch);
|
||||||
|
if (Main.client.player.getMovementSpeed() != speed)
|
||||||
|
Main.client.player.setMovementSpeed(speed);
|
||||||
|
if (sneaking != null && Main.client.player.input.sneaking != sneaking)
|
||||||
|
Main.client.player.input.sneaking = sneaking;
|
||||||
|
if (jumping != null && Main.client.player.input.jumping != jumping)
|
||||||
|
Main.client.player.input.jumping = jumping;
|
||||||
|
if (movementSideways != null && Main.client.player.input.movementSideways != movementSideways)
|
||||||
|
Main.client.player.input.movementSideways = movementSideways;
|
||||||
|
if (movementForward != null && Main.client.player.input.movementForward != movementForward)
|
||||||
|
Main.client.player.input.movementForward = movementForward;
|
||||||
|
if (pressingForward != null && Main.client.player.input.pressingForward != pressingForward)
|
||||||
|
Main.client.player.input.pressingForward = pressingForward;
|
||||||
|
if (pressingBack != null && Main.client.player.input.pressingBack != pressingBack)
|
||||||
|
Main.client.player.input.pressingBack = pressingBack;
|
||||||
|
if (pressingLeft != null && Main.client.player.input.pressingLeft != pressingLeft)
|
||||||
|
Main.client.player.input.pressingLeft = pressingLeft;
|
||||||
|
if (pressingRight != null && Main.client.player.input.pressingRight != pressingRight)
|
||||||
|
Main.client.player.input.pressingRight = pressingRight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
return "p=" +
|
||||||
|
((sneaking == null) ? "n" : (sneaking ? "1" : "0")) + "&" +
|
||||||
|
((jumping == null) ? "n" : (jumping ? "1" : "0")) + "&" +
|
||||||
|
((movementSideways == null) ? "n" : movementSideways) + "&" +
|
||||||
|
((movementForward == null) ? "n" : movementForward) + "&" +
|
||||||
|
((pressingForward == null) ? "n" : (pressingForward ? "1" : "0")) + "&" +
|
||||||
|
((pressingBack == null) ? "n" : (pressingBack ? "1" : "0")) + "&" +
|
||||||
|
((pressingLeft == null) ? "n" : (pressingLeft ? "1" : "0")) + "&" +
|
||||||
|
((pressingRight == null) ? "n" : (pressingRight ? "1" : "0")) + "&" +
|
||||||
|
head_yaw + "&" + body_yaw + "&" + pitch + "&" +
|
||||||
|
((sprinting == null) ? "n" : (sprinting ? "1" : "0") +
|
||||||
|
"&" + yaw + "&" + speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return "input";
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package themixray.repeating.mod.event;
|
||||||
|
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
|
||||||
|
public class RecordMoveEvent extends RecordEvent {
|
||||||
|
public Vec3d vec;
|
||||||
|
public float yaw;
|
||||||
|
public float pitch;
|
||||||
|
|
||||||
|
public static RecordMoveEvent fromArgs(String[] a) {
|
||||||
|
return new RecordMoveEvent(new Vec3d(
|
||||||
|
Double.parseDouble(a[0]),
|
||||||
|
Double.parseDouble(a[1]),
|
||||||
|
Double.parseDouble(a[2])),
|
||||||
|
Float.parseFloat(a[3]),
|
||||||
|
Float.parseFloat(a[4]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordMoveEvent(Vec3d vec, float yaw, float pitch) {
|
||||||
|
this.vec = vec;
|
||||||
|
this.yaw = yaw;
|
||||||
|
this.pitch = pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void replay() {
|
||||||
|
Vec3d p = Main.client.player.getPos();
|
||||||
|
Vec3d v = new Vec3d(vec.getX() - p.getX(), vec.getY() - p.getY(), vec.getZ() - p.getZ());
|
||||||
|
Main.client.player.move(MovementType.SELF, v);
|
||||||
|
Main.client.player.setYaw(yaw);
|
||||||
|
Main.client.player.setPitch(pitch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String serialize() {
|
||||||
|
return "m=" + vec.getX() + "&" + vec.getY() + "&" + vec.getZ() + "&" + yaw + "&" + pitch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return "move";
|
||||||
|
}
|
||||||
|
}
|
24
remappedSrc/themixray/repeating/mod/mixin/ClientMixin.java
Normal file
24
remappedSrc/themixray/repeating/mod/mixin/ClientMixin.java
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
import themixray.repeating.mod.TickTask;
|
||||||
|
|
||||||
|
@Mixin(MinecraftClient.class)
|
||||||
|
public abstract class ClientMixin {
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "tick")
|
||||||
|
private void onTickHead(CallbackInfo ci) {
|
||||||
|
if (Main.me.is_recording)
|
||||||
|
Main.me.recordAllInput();
|
||||||
|
TickTask.tickTasks(TickTask.TickAt.CLIENT_HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
|
private void onTickTail(CallbackInfo ci) {
|
||||||
|
TickTask.tickTasks(TickTask.TickAt.CLIENT_TAIL);
|
||||||
|
}
|
||||||
|
}
|
31
remappedSrc/themixray/repeating/mod/mixin/EntityMixin.java
Normal file
31
remappedSrc/themixray/repeating/mod/mixin/EntityMixin.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
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 themixray.repeating.mod.Main;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
public abstract class EntityMixin {
|
||||||
|
@Shadow public abstract UUID getUuid();
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
|
||||||
|
private void onSprint(boolean sprinting,CallbackInfo ci) {
|
||||||
|
if (Main.client.player != null) {
|
||||||
|
if (getUuid().equals(Main.client.player.getUuid())) {
|
||||||
|
if (Main.me.is_replaying) {
|
||||||
|
if (Main.input_replay != null &&
|
||||||
|
Main.input_replay.sprinting != null &&
|
||||||
|
Main.input_replay.sprinting != sprinting) {
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
remappedSrc/themixray/repeating/mod/mixin/InputMixin.java
Normal file
20
remappedSrc/themixray/repeating/mod/mixin/InputMixin.java
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.input.KeyboardInput;
|
||||||
|
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 themixray.repeating.mod.Main;
|
||||||
|
|
||||||
|
@Mixin(KeyboardInput.class)
|
||||||
|
public abstract class InputMixin {
|
||||||
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
|
private void onTickTail(boolean slowDown, float f, CallbackInfo ci) {
|
||||||
|
if (Main.me.is_replaying) {
|
||||||
|
if (Main.input_replay != null) {
|
||||||
|
Main.input_replay.inputCallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
44
remappedSrc/themixray/repeating/mod/mixin/MovementMixin.java
Normal file
44
remappedSrc/themixray/repeating/mod/mixin/MovementMixin.java
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents;
|
||||||
|
import net.fabricmc.fabric.api.event.player.UseBlockCallback;
|
||||||
|
import net.minecraft.client.network.ClientPlayerEntity;
|
||||||
|
import net.minecraft.util.ActionResult;
|
||||||
|
import net.minecraft.util.hit.HitResult;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
import themixray.repeating.mod.event.RecordBlockBreakEvent;
|
||||||
|
import themixray.repeating.mod.event.RecordBlockInteractEvent;
|
||||||
|
import themixray.repeating.mod.TickTask;
|
||||||
|
|
||||||
|
@Mixin(ClientPlayerEntity.class)
|
||||||
|
public abstract class MovementMixin {
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "init")
|
||||||
|
private void init(CallbackInfo ci) {
|
||||||
|
PlayerBlockBreakEvents.AFTER.register((world, player, pos, blockState, blockEntity) -> {
|
||||||
|
if (Main.me.is_recording)
|
||||||
|
Main.me.recordTick(new RecordBlockBreakEvent(pos));
|
||||||
|
});
|
||||||
|
|
||||||
|
UseBlockCallback.EVENT.register((player, world, hand, hitResult) -> {
|
||||||
|
if (hitResult.getType().equals(HitResult.Type.BLOCK))
|
||||||
|
if (Main.me.is_recording)
|
||||||
|
Main.me.recordTick(new RecordBlockInteractEvent(hand,hitResult));
|
||||||
|
return ActionResult.PASS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "tickMovement")
|
||||||
|
private void onMoveHead(CallbackInfo ci) {
|
||||||
|
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
|
private void onMoveTail(CallbackInfo ci) {
|
||||||
|
TickTask.tickTasks(TickTask.TickAt.MOVEMENT_TAIL);
|
||||||
|
}
|
||||||
|
}
|
29
remappedSrc/themixray/repeating/mod/mixin/NetworkMixin.java
Normal file
29
remappedSrc/themixray/repeating/mod/mixin/NetworkMixin.java
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.network.ClientPlayNetworkHandler;
|
||||||
|
import net.minecraft.network.listener.ServerPlayPacketListener;
|
||||||
|
import net.minecraft.network.packet.Packet;
|
||||||
|
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 java.time.Duration;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
@Mixin(ClientPlayNetworkHandler.class)
|
||||||
|
public abstract class NetworkMixin {
|
||||||
|
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
|
||||||
|
// private void onSendPacket1Head(Packet<?> packet,
|
||||||
|
// CallbackInfo ci) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")
|
||||||
|
// private void onSendPacket2Head(Packet<ServerPlayPacketListener> packet,
|
||||||
|
// BooleanSupplier sendCondition,
|
||||||
|
// Duration expirationTime,
|
||||||
|
// CallbackInfo ci) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
21
remappedSrc/themixray/repeating/mod/mixin/RendererMixin.java
Normal file
21
remappedSrc/themixray/repeating/mod/mixin/RendererMixin.java
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package themixray.repeating.mod.mixin;
|
||||||
|
|
||||||
|
import net.minecraft.client.render.*;
|
||||||
|
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 themixray.repeating.mod.TickTask;
|
||||||
|
|
||||||
|
@Mixin(GameRenderer.class)
|
||||||
|
public abstract class RendererMixin {
|
||||||
|
@Inject(at = @At(value = "HEAD"), method = "tick")
|
||||||
|
private void onTickHead(CallbackInfo ci) {
|
||||||
|
TickTask.tickTasks(TickTask.TickAt.RENDER_HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(at = @At(value = "TAIL"), method = "tick")
|
||||||
|
private void onTickTail(CallbackInfo ci) {
|
||||||
|
TickTask.tickTasks(TickTask.TickAt.RENDER_TAIL);
|
||||||
|
}
|
||||||
|
}
|
200
remappedSrc/themixray/repeating/mod/render/RenderHelper.java
Normal file
200
remappedSrc/themixray/repeating/mod/render/RenderHelper.java
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
package themixray.repeating.mod.render;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import themixray.repeating.mod.render.buffer.WorldBuffer;
|
||||||
|
import themixray.repeating.mod.render.shader.ShaderManager;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL33.*;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class RenderHelper {
|
||||||
|
public WorldBuffer startLines(WorldRenderContext context) {
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
return new WorldBuffer(GL_LINES, ShaderManager.getPositionColorShader(), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void endLines(WorldBuffer buffer) {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDepthMask(false);
|
||||||
|
buffer.draw();
|
||||||
|
glDepthMask(true);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawLine(WorldBuffer buffer, float x1, float y1, float z1, float x2, float y2, float z2, Color color) {
|
||||||
|
buffer.vert(x1, y1, z1, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
||||||
|
buffer.vert(x2, y2, z2, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WorldBuffer startTri(WorldRenderContext context) {
|
||||||
|
return new WorldBuffer(GL_TRIANGLES, ShaderManager.getPositionColorShader(), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void endTri(WorldBuffer buffer) {
|
||||||
|
//glDepthRange(0, 0.7);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
glDisable(GL_CULL_FACE);
|
||||||
|
glDepthMask(false);
|
||||||
|
buffer.draw();
|
||||||
|
glDepthMask(true);
|
||||||
|
glEnable(GL_CULL_FACE);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDepthRange(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawTri(WorldBuffer buffer, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, Color color) {
|
||||||
|
buffer.vert(x1, y1, z1, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
||||||
|
buffer.vert(x2, y2, z2, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
||||||
|
buffer.vert(x3, y3, z3, color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void drawRectFromTri(WorldBuffer buffer,
|
||||||
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2,
|
||||||
|
float x3, float y3, float z3,
|
||||||
|
float x4, float y4, float z4,
|
||||||
|
Color color) {
|
||||||
|
drawTri(buffer,
|
||||||
|
x1, y1, z1,
|
||||||
|
x2, y2, z2,
|
||||||
|
x3, y3, z3,
|
||||||
|
color);
|
||||||
|
drawTri(buffer,
|
||||||
|
x3, y3, z3,
|
||||||
|
x4, y4, z4,
|
||||||
|
x1, y1, z1,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawRectFromLines(WorldBuffer buffer,
|
||||||
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2,
|
||||||
|
float x3, float y3, float z3,
|
||||||
|
float x4, float y4, float z4,
|
||||||
|
Color color) {
|
||||||
|
drawLine(buffer,
|
||||||
|
x1, y1, z1,
|
||||||
|
x2, y2, z2,
|
||||||
|
color);
|
||||||
|
drawLine(buffer,
|
||||||
|
x2, y2, z2,
|
||||||
|
x3, y3, z3,
|
||||||
|
color);
|
||||||
|
drawLine(buffer,
|
||||||
|
x3, y3, z3,
|
||||||
|
x4, y4, z4,
|
||||||
|
color);
|
||||||
|
drawLine(buffer,
|
||||||
|
x4, y4, z4,
|
||||||
|
x1, y1, z1,
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawBoxFromTri(WorldBuffer buffer,
|
||||||
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2,
|
||||||
|
Color color) {
|
||||||
|
float[][] v = new float[][]{
|
||||||
|
new float[]{Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2)},
|
||||||
|
new float[]{Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)}};
|
||||||
|
|
||||||
|
drawRectFromTri(buffer,
|
||||||
|
v[0][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[1][1], v[0][2],
|
||||||
|
v[0][0], v[1][1], v[0][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromTri(buffer,
|
||||||
|
v[0][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[1][2],
|
||||||
|
v[0][0], v[0][1], v[1][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromTri(buffer,
|
||||||
|
v[0][0], v[0][1], v[0][2],
|
||||||
|
v[0][0], v[0][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[0][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromTri(buffer,
|
||||||
|
v[0][0], v[0][1], v[1][2],
|
||||||
|
v[1][0], v[0][1], v[1][2],
|
||||||
|
v[1][0], v[1][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[1][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromTri(buffer,
|
||||||
|
v[0][0], v[1][1], v[0][2],
|
||||||
|
v[1][0], v[1][1], v[0][2],
|
||||||
|
v[1][0], v[1][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[1][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromTri(buffer,
|
||||||
|
v[1][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[1][2],
|
||||||
|
v[1][0], v[1][1], v[1][2],
|
||||||
|
v[1][0], v[1][1], v[0][2],
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawBoxFromLines(WorldBuffer buffer,
|
||||||
|
float x1, float y1, float z1,
|
||||||
|
float x2, float y2, float z2,
|
||||||
|
Color color) {
|
||||||
|
float[][] v = new float[][]{
|
||||||
|
new float[]{Math.min(x1, x2), Math.min(y1, y2), Math.min(z1, z2)},
|
||||||
|
new float[]{Math.max(x1, x2), Math.max(y1, y2), Math.max(z1, z2)}};
|
||||||
|
|
||||||
|
drawRectFromLines(buffer,
|
||||||
|
v[0][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[1][1], v[0][2],
|
||||||
|
v[0][0], v[1][1], v[0][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromLines(buffer,
|
||||||
|
v[0][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[1][2],
|
||||||
|
v[0][0], v[0][1], v[1][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromLines(buffer,
|
||||||
|
v[0][0], v[0][1], v[0][2],
|
||||||
|
v[0][0], v[0][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[0][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromLines(buffer,
|
||||||
|
v[0][0], v[0][1], v[1][2],
|
||||||
|
v[1][0], v[0][1], v[1][2],
|
||||||
|
v[1][0], v[1][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[1][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromLines(buffer,
|
||||||
|
v[0][0], v[1][1], v[0][2],
|
||||||
|
v[1][0], v[1][1], v[0][2],
|
||||||
|
v[1][0], v[1][1], v[1][2],
|
||||||
|
v[0][0], v[1][1], v[1][2],
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawRectFromLines(buffer,
|
||||||
|
v[1][0], v[0][1], v[0][2],
|
||||||
|
v[1][0], v[0][1], v[1][2],
|
||||||
|
v[1][0], v[1][1], v[1][2],
|
||||||
|
v[1][0], v[1][1], v[0][2],
|
||||||
|
color);
|
||||||
|
}
|
||||||
|
}
|
13
remappedSrc/themixray/repeating/mod/render/RenderSystem.java
Normal file
13
remappedSrc/themixray/repeating/mod/render/RenderSystem.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package themixray.repeating.mod.render;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import themixray.repeating.mod.render.buffer.BufferManager;
|
||||||
|
import themixray.repeating.mod.render.shader.ShaderManager;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class RenderSystem {
|
||||||
|
public static void init() {
|
||||||
|
BufferManager.init();
|
||||||
|
ShaderManager.init();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
package themixray.repeating.mod.render.buffer;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL33.*;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class BufferManager {
|
||||||
|
private int vao;
|
||||||
|
private int vbo;
|
||||||
|
|
||||||
|
private int prevVao;
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
ClientLifecycleEvents.CLIENT_STARTED.register(client -> {
|
||||||
|
vao = glGenVertexArrays();
|
||||||
|
vbo = glGenBuffers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bindBuffer() {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unbindBuffer() {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void writeBuffer(FloatBuffer buffer) {
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, buffer, GL_STATIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void draw(int drawMode, int verts) {
|
||||||
|
glDrawArrays(drawMode, 0, verts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void bind() {
|
||||||
|
prevVao = glGetInteger(GL_VERTEX_ARRAY_BINDING);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void unbind() {
|
||||||
|
glBindVertexArray(prevVao);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package themixray.repeating.mod.render.buffer;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
public class Vertex {
|
||||||
|
@Getter
|
||||||
|
private float x;
|
||||||
|
@Getter
|
||||||
|
private float y;
|
||||||
|
@Getter
|
||||||
|
private float z;
|
||||||
|
@Getter
|
||||||
|
private float r;
|
||||||
|
@Getter
|
||||||
|
private float g;
|
||||||
|
@Getter
|
||||||
|
private float b;
|
||||||
|
@Getter
|
||||||
|
private float a;
|
||||||
|
|
||||||
|
public Vertex(float x, float y, float z, float r, float g, float b, float a) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.r = r;
|
||||||
|
this.g = g;
|
||||||
|
this.b = b;
|
||||||
|
this.a = a;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
package themixray.repeating.mod.render.buffer;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
import org.joml.Matrix4f;
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import themixray.repeating.mod.render.shader.Shader;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL33.*;
|
||||||
|
|
||||||
|
public class WorldBuffer {
|
||||||
|
private final List<Vertex> vertices = new ArrayList<>();
|
||||||
|
private final int drawMode;
|
||||||
|
private final Shader shader;
|
||||||
|
private FloatBuffer projectionMatrix;
|
||||||
|
private final Vec3d cameraPos;
|
||||||
|
|
||||||
|
public WorldBuffer(int drawMode, Shader shader, WorldRenderContext worldRenderContext) {
|
||||||
|
this.drawMode = drawMode;
|
||||||
|
this.shader = shader;
|
||||||
|
this.cameraPos = worldRenderContext.camera().getPos();
|
||||||
|
makeProjectionMatrix(worldRenderContext.projectionMatrix(), worldRenderContext.matrixStack().peek().getPositionMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void vert(float x, float y, float z, float r, float g, float b, float a) {
|
||||||
|
vertices.add(new Vertex(x - (float) cameraPos.x, y - (float) cameraPos.y, z - (float) cameraPos.z, r, g, b, a));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw() {
|
||||||
|
BufferManager.bind();
|
||||||
|
BufferManager.bindBuffer();
|
||||||
|
|
||||||
|
BufferManager.writeBuffer(getBuffer());
|
||||||
|
applyProjectionMatrix();
|
||||||
|
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(1, 4, GL_FLOAT, false, 0, vertices.size() * 3 * 4L);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
BufferManager.unbindBuffer();
|
||||||
|
|
||||||
|
shader.bind();
|
||||||
|
BufferManager.draw(drawMode, this.vertices.size());
|
||||||
|
shader.unbind();
|
||||||
|
|
||||||
|
BufferManager.unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
private FloatBuffer getBuffer() {
|
||||||
|
FloatBuffer floatBuffer = BufferUtils.createFloatBuffer(vertices.size() * 7);
|
||||||
|
ArrayList<Float> floats = new ArrayList<>();
|
||||||
|
for (Vertex vertex : vertices) {
|
||||||
|
floats.add(vertex.getX());
|
||||||
|
floats.add(vertex.getY());
|
||||||
|
floats.add(vertex.getZ());
|
||||||
|
}
|
||||||
|
for (Vertex vertex : vertices) {
|
||||||
|
floats.add(vertex.getR());
|
||||||
|
floats.add(vertex.getG());
|
||||||
|
floats.add(vertex.getB());
|
||||||
|
floats.add(vertex.getA());
|
||||||
|
}
|
||||||
|
Float[] floatArray = new Float[floats.size()];
|
||||||
|
floats.toArray(floatArray);
|
||||||
|
floatBuffer.put(ArrayUtils.toPrimitive(floatArray));
|
||||||
|
return floatBuffer.flip();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void makeProjectionMatrix(Matrix4f projectionMatrix, Matrix4f viewModelMatrix) {
|
||||||
|
this.projectionMatrix = projectionMatrix.mul(viewModelMatrix).get(BufferUtils.createFloatBuffer(16));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyProjectionMatrix() {
|
||||||
|
shader.uniformMatrix4f("u_projection", projectionMatrix);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package themixray.repeating.mod.render.shader;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.nio.FloatBuffer;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL33.*;
|
||||||
|
|
||||||
|
public class Shader {
|
||||||
|
@Getter
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
|
||||||
|
public Shader(String name) {
|
||||||
|
int v = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.VERTEX);
|
||||||
|
int f = ShaderManager.loadShaderProgram(name, ShaderManager.ShaderType.FRAGMENT);
|
||||||
|
this.id = glCreateProgram();
|
||||||
|
glAttachShader(id, v);
|
||||||
|
glAttachShader(id, f);
|
||||||
|
glLinkProgram(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bind() {
|
||||||
|
glUseProgram(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unbind() {
|
||||||
|
glUseProgram(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uniformMatrix4f(String name, FloatBuffer matrix) {
|
||||||
|
bind();
|
||||||
|
glUniformMatrix4fv(glGetUniformLocation(id, name), false, matrix);
|
||||||
|
unbind();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uniformValue2f(String name, float value1, float value2) {
|
||||||
|
bind();
|
||||||
|
glUniform2f(glGetUniformLocation(id, name), value1, value2);
|
||||||
|
unbind();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
package themixray.repeating.mod.render.shader;
|
||||||
|
|
||||||
|
import com.mojang.blaze3d.platform.GlStateManager;
|
||||||
|
import com.mojang.blaze3d.platform.TextureUtil;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
|
||||||
|
import net.minecraft.client.MinecraftClient;
|
||||||
|
import net.minecraft.client.gl.GlImportProcessor;
|
||||||
|
import net.minecraft.resource.Resource;
|
||||||
|
import net.minecraft.resource.ResourceFactory;
|
||||||
|
import net.minecraft.util.Identifier;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.lwjgl.system.MemoryUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.lwjgl.opengl.GL33.*;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class ShaderManager {
|
||||||
|
@Getter
|
||||||
|
private Shader positionColorShader;
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
ClientLifecycleEvents.CLIENT_STARTED.register(client -> loadShaders());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadShaders() {
|
||||||
|
positionColorShader = new Shader("position_color");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int loadShaderProgram(String name, ShaderType type) {
|
||||||
|
try {
|
||||||
|
boolean file_present = true;
|
||||||
|
ResourceFactory resourceFactory = MinecraftClient.getInstance().getResourceManager();
|
||||||
|
Optional<Resource> resource = resourceFactory.getResource(new Identifier("renderer", "shader/" + name + type.fileExtension));
|
||||||
|
int i = glCreateShader(type.glType);
|
||||||
|
if (resource.isPresent()) {
|
||||||
|
GlStateManager.glShaderSource(i, new GlImportProcessor() {
|
||||||
|
@SneakyThrows
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String loadImport(boolean inline, String name) {
|
||||||
|
return IOUtils.toString(resource.get().getInputStream(), StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
}.readSource(readResourceAsString(resource.get().getInputStream())));
|
||||||
|
} else file_present = false;
|
||||||
|
glCompileShader(i);
|
||||||
|
if (glGetShaderi(i, GL_COMPILE_STATUS) == 0 || !file_present) {
|
||||||
|
String shaderInfo = StringUtils.trim(glGetShaderInfoLog(i, 32768));
|
||||||
|
throw new IOException("Couldn't compile " + type.name + " program (" + name + ") : " + shaderInfo);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readResourceAsString(InputStream inputStream) {
|
||||||
|
ByteBuffer byteBuffer = null;
|
||||||
|
try {
|
||||||
|
byteBuffer = TextureUtil.readResource(inputStream);
|
||||||
|
int i = byteBuffer.position();
|
||||||
|
byteBuffer.rewind();
|
||||||
|
return MemoryUtil.memASCII(byteBuffer, i);
|
||||||
|
} catch (IOException ignored) {
|
||||||
|
} finally {
|
||||||
|
if (byteBuffer != null) {
|
||||||
|
MemoryUtil.memFree(byteBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ShaderType {
|
||||||
|
VERTEX("vertex", ".vsh", GL_VERTEX_SHADER),
|
||||||
|
FRAGMENT("fragment", ".fsh", GL_FRAGMENT_SHADER);
|
||||||
|
private final String name;
|
||||||
|
private final String fileExtension;
|
||||||
|
private final int glType;
|
||||||
|
|
||||||
|
ShaderType(String name, String fileExtension, int glType) {
|
||||||
|
this.name = name;
|
||||||
|
this.fileExtension = fileExtension;
|
||||||
|
this.glType = glType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
remappedSrc/themixray/repeating/mod/widget/RecordListWidget.java
Normal file
150
remappedSrc/themixray/repeating/mod/widget/RecordListWidget.java
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package themixray.repeating.mod.widget;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.Drawable;
|
||||||
|
import net.minecraft.client.gui.Element;
|
||||||
|
import net.minecraft.client.gui.Selectable;
|
||||||
|
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
|
||||||
|
import net.minecraft.client.gui.tooltip.Tooltip;
|
||||||
|
import net.minecraft.client.gui.widget.*;
|
||||||
|
import net.minecraft.client.util.math.MatrixStack;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
import themixray.repeating.mod.RecordState;
|
||||||
|
import themixray.repeating.mod.RepeatingScreen;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class RecordListWidget extends ScrollableWidget {
|
||||||
|
private List<RecordWidget> widgets = new ArrayList<>();
|
||||||
|
private boolean focused = false;
|
||||||
|
|
||||||
|
public RecordListWidget(int x, int y, int width, int height) {
|
||||||
|
super(x,y,width,height,Text.empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) {
|
||||||
|
focused = true;
|
||||||
|
boolean res = super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY);
|
||||||
|
focused = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected double getDeltaYPerScroll() {
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void renderContents(DrawContext ctx, int mouseX, int mouseY, float delta) {
|
||||||
|
int y = 0;
|
||||||
|
for (RecordWidget wid: widgets) {
|
||||||
|
wid.method_46419(y);
|
||||||
|
wid.render(ctx, mouseX, (int) (mouseY + this.getScrollY()), delta);
|
||||||
|
|
||||||
|
y += wid.getHeight();
|
||||||
|
y += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addWidget(RecordState record) {
|
||||||
|
RecordWidget widget = new RecordWidget(0, 0, width, 55, record, this);
|
||||||
|
widget.init(null);
|
||||||
|
widgets.add(0, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeWidget(RecordState record) {
|
||||||
|
widgets.removeIf(i -> i.getRecord().equals(record));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFocused(boolean focused) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFocused() {
|
||||||
|
return focused;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected int getContentsHeight() {
|
||||||
|
return !widgets.isEmpty() ? widgets.size() * 55 + (widgets.size() - 1) * 2 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(RepeatingScreen screen) {
|
||||||
|
for (RecordWidget widget : widgets) {
|
||||||
|
widget.init(screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addDrawableChild(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void appendClickableNarrations(NarrationMessageBuilder builder) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordWidget getWidget(RecordState record) {
|
||||||
|
for (RecordWidget widget : widgets) {
|
||||||
|
if (widget.getRecord().equals(record)) {
|
||||||
|
return widget;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface transport {
|
||||||
|
boolean check(ClickableWidget ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkTransport(transport tr) {
|
||||||
|
for (RecordWidget wid : widgets) {
|
||||||
|
for (ClickableWidget child : wid.getChildren()) {
|
||||||
|
if (tr.check(child)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkTransportNF(transport tr) {
|
||||||
|
for (RecordWidget wid : widgets) {
|
||||||
|
for (ClickableWidget child : wid.getChildren()) {
|
||||||
|
boolean res = tr.check(child);
|
||||||
|
|
||||||
|
if (res) {
|
||||||
|
child.setFocused(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
child.setFocused(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean mouseClicked(double mouseX, double mouseY, int button) {
|
||||||
|
return checkTransportNF((c) -> c.mouseClicked(mouseX, mouseY + this.getScrollY(), button)) || super.mouseClicked(mouseX, mouseY, button);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean charTyped(char chr, int modifiers) {
|
||||||
|
return checkTransport((c) -> c.charTyped(chr, modifiers)) || super.charTyped(chr, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
|
||||||
|
return checkTransport((c) -> c.keyPressed(keyCode, scanCode, modifiers)) || super.keyPressed(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean keyReleased(int keyCode, int scanCode, int modifiers) {
|
||||||
|
return checkTransport((c) -> c.keyReleased(keyCode, scanCode, modifiers)) || super.keyReleased(keyCode, scanCode, modifiers);
|
||||||
|
}
|
||||||
|
}
|
196
remappedSrc/themixray/repeating/mod/widget/RecordWidget.java
Normal file
196
remappedSrc/themixray/repeating/mod/widget/RecordWidget.java
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
package themixray.repeating.mod.widget;
|
||||||
|
|
||||||
|
import net.minecraft.client.gui.DrawContext;
|
||||||
|
import net.minecraft.client.gui.Drawable;
|
||||||
|
import net.minecraft.client.gui.tooltip.Tooltip;
|
||||||
|
import net.minecraft.client.gui.widget.*;
|
||||||
|
import net.minecraft.text.Style;
|
||||||
|
import net.minecraft.text.Text;
|
||||||
|
import themixray.repeating.mod.Main;
|
||||||
|
import themixray.repeating.mod.RecordState;
|
||||||
|
import themixray.repeating.mod.RenderListener;
|
||||||
|
import themixray.repeating.mod.RepeatingScreen;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public class RecordWidget implements Drawable, Widget {
|
||||||
|
private RecordState record;
|
||||||
|
|
||||||
|
private List<ClickableWidget> children;
|
||||||
|
|
||||||
|
private RecordListWidget parent;
|
||||||
|
|
||||||
|
private int x;
|
||||||
|
private int y;
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
|
||||||
|
public RecordWidget(int x, int y, int width, int height, RecordState record, RecordListWidget parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.record = record;
|
||||||
|
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
|
||||||
|
this.children = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void method_46421(int x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
public void method_46419(int y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
public int getX() {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
public int getY() {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ClickableWidget> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void forEachChild(Consumer<ClickableWidget> consumer) {
|
||||||
|
children.forEach(consumer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(RepeatingScreen screen) {
|
||||||
|
this.children = new ArrayList<>();
|
||||||
|
|
||||||
|
TextFieldWidget name_widget = new TextFieldWidget(
|
||||||
|
Main.client.textRenderer,
|
||||||
|
parent.getX() + getX() + 5,
|
||||||
|
parent.getY() + getY() + 5,
|
||||||
|
102,
|
||||||
|
10,
|
||||||
|
Text.empty());
|
||||||
|
|
||||||
|
name_widget.setText(record.getName());
|
||||||
|
|
||||||
|
name_widget.setChangedListener((s) -> {
|
||||||
|
record.setName(s);
|
||||||
|
try {
|
||||||
|
record.save();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
children.add(name_widget);
|
||||||
|
|
||||||
|
ButtonWidget delete_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.delete"), (i) -> {
|
||||||
|
record.remove();
|
||||||
|
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4, 65, 13).build();
|
||||||
|
|
||||||
|
children.add(delete_button);
|
||||||
|
|
||||||
|
ButtonWidget export_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.export"), (i) -> {
|
||||||
|
if (Desktop.isDesktopSupported()) {
|
||||||
|
Desktop desk = Desktop.getDesktop();
|
||||||
|
try {
|
||||||
|
desk.browseFileDirectory(record.getFile());
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
desk.browse(record.getFile().toURI());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new RuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 14, 65, 13).build();
|
||||||
|
|
||||||
|
children.add(export_button);
|
||||||
|
|
||||||
|
ButtonWidget replay_button = ButtonWidget.builder(Text.translatable("text.repeating-mod.start"), (i) -> {
|
||||||
|
if (Main.me.is_replaying) {
|
||||||
|
Main.me.stopReplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
i.setMessage(Text.translatable("text.repeating-mod.stop"));
|
||||||
|
Main.me.now_record = record;
|
||||||
|
Main.me.startReplay();
|
||||||
|
}).dimensions(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 28, 65, 13)
|
||||||
|
.tooltip(Tooltip.of(Text.translatable("text.repeating-mod.replay_tooltip"))).build();
|
||||||
|
|
||||||
|
children.add(replay_button);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RecordState getRecord() {
|
||||||
|
return record;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawText(int x, int y, DrawContext ctx, List<Text> lines, float size, int line_height, boolean shadow) {
|
||||||
|
ctx.getMatrices().push();
|
||||||
|
ctx.getMatrices().scale(size, size, size);
|
||||||
|
|
||||||
|
int now_y = y;
|
||||||
|
|
||||||
|
for (Text line : lines) {
|
||||||
|
ctx.drawText(Main.client.textRenderer, line, (int) (x / size), (int) (now_y / size), line.getStyle().getColor().getRgb(), shadow);
|
||||||
|
now_y += line_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.getMatrices().pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(DrawContext ctx, int mouseX, int mouseY, float delta) {
|
||||||
|
int color = record.equals(Main.me.now_record) ? 0xFF555555 : 0xFF333333;
|
||||||
|
|
||||||
|
ctx.fill(parent.getX() + getX(),
|
||||||
|
parent.getY() + getY(),
|
||||||
|
parent.getX() + getX() + getWidth(),
|
||||||
|
parent.getY() + getY() + getHeight(),
|
||||||
|
color);
|
||||||
|
|
||||||
|
drawText(
|
||||||
|
parent.getX() + getX() + 5,
|
||||||
|
parent.getY() + getY() + 5 + 12,
|
||||||
|
ctx, List.of(
|
||||||
|
Text.translatable("text.repeating-mod.recorded_at")
|
||||||
|
.append(": ")
|
||||||
|
.styled((s) -> s.withColor(0xbbbbbb)),
|
||||||
|
Text.literal(RecordState.DATE_FORMAT.format(record.getDate())).styled((s) -> s.withColor(0xffffff)),
|
||||||
|
Text.translatable("text.repeating-mod.author")
|
||||||
|
.append(": ")
|
||||||
|
.styled((s) -> s.withColor(0xbbbbbb)),
|
||||||
|
Text.literal(record.getAuthor()).styled((s) -> s.withColor(0xffffff))
|
||||||
|
), 1,
|
||||||
|
9,
|
||||||
|
false);
|
||||||
|
|
||||||
|
if (!children.isEmpty()) {
|
||||||
|
ClickableWidget name_widget = children.get(0);
|
||||||
|
name_widget.setPosition(parent.getX() + getX() + 5, parent.getY() + getY() + 5);
|
||||||
|
|
||||||
|
ClickableWidget delete_button = children.get(1);
|
||||||
|
delete_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4);
|
||||||
|
|
||||||
|
ClickableWidget export_button = children.get(2);
|
||||||
|
export_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 14);
|
||||||
|
|
||||||
|
ClickableWidget replay_button = children.get(3);
|
||||||
|
replay_button.setPosition(parent.getX() + getX() + 110,parent.getY() + getY() + 4 + 28);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ClickableWidget child : children) {
|
||||||
|
child.render(ctx, mouseX, mouseY, delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
settings.gradle
Normal file
10
settings.gradle
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
maven {
|
||||||
|
name = 'Fabric'
|
||||||
|
url = 'https://maven.fabricmc.net/'
|
||||||
|
}
|
||||||
|
mavenCentral()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
@ -51,7 +51,7 @@ public class RepeatingScreen extends Screen {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
||||||
renderBackground(context);
|
renderBackground(context,mouseX,mouseY,delta);
|
||||||
|
|
||||||
for (RenderListener l : render_listeners) {
|
for (RenderListener l : render_listeners) {
|
||||||
if (l.beforeRender()) {
|
if (l.beforeRender()) {
|
||||||
@ -132,12 +132,6 @@ public class RepeatingScreen extends Screen {
|
|||||||
super.onDrag(mouseX, mouseY, deltaX, deltaY);
|
super.onDrag(mouseX, mouseY, deltaX, deltaY);
|
||||||
applyValue();
|
applyValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
|
|
||||||
super.render(context, mouseX, mouseY, delta);
|
|
||||||
updateMessage();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
pos_delay_slider.setTooltip(Tooltip.of(Text.translatable("text.repeating-mod.pos_delay_tooltip")));
|
pos_delay_slider.setTooltip(Tooltip.of(Text.translatable("text.repeating-mod.pos_delay_tooltip")));
|
||||||
|
|
||||||
|
@ -16,13 +16,14 @@ public abstract class EntityMixin {
|
|||||||
|
|
||||||
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
|
@Inject(at = @At(value = "HEAD"), method = "setSprinting", cancellable = true)
|
||||||
private void onSprint(boolean sprinting,CallbackInfo ci) {
|
private void onSprint(boolean sprinting,CallbackInfo ci) {
|
||||||
|
if (Main.client.player != null) {
|
||||||
if (getUuid().equals(Main.client.player.getUuid())) {
|
if (getUuid().equals(Main.client.player.getUuid())) {
|
||||||
if (Main.me.is_replaying) {
|
if (Main.me.is_replaying) {
|
||||||
if (Main.input_replay != null &&
|
if (Main.input_replay != null &&
|
||||||
Main.input_replay.sprinting != null &&
|
Main.input_replay.sprinting != null &&
|
||||||
Main.input_replay.sprinting != sprinting) {
|
Main.input_replay.sprinting != sprinting) {
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
return;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,17 +13,17 @@ import java.util.function.BooleanSupplier;
|
|||||||
|
|
||||||
@Mixin(ClientPlayNetworkHandler.class)
|
@Mixin(ClientPlayNetworkHandler.class)
|
||||||
public abstract class NetworkMixin {
|
public abstract class NetworkMixin {
|
||||||
@Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
|
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;)V")
|
||||||
private void onSendPacket1Head(Packet<?> packet,
|
// private void onSendPacket1Head(Packet<?> packet,
|
||||||
CallbackInfo ci) {
|
// CallbackInfo ci) {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")
|
// @Inject(at = @At(value = "HEAD"), method = "sendPacket(Lnet/minecraft/network/packet/Packet;Ljava/util/function/BooleanSupplier;Ljava/time/Duration;)V")
|
||||||
private void onSendPacket2Head(Packet<ServerPlayPacketListener> packet,
|
// private void onSendPacket2Head(Packet<ServerPlayPacketListener> packet,
|
||||||
BooleanSupplier sendCondition,
|
// BooleanSupplier sendCondition,
|
||||||
Duration expirationTime,
|
// Duration expirationTime,
|
||||||
CallbackInfo ci) {
|
// CallbackInfo ci) {
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user