version 0.1.0-pre
This commit is contained in:
parent
3614b2dbd4
commit
e51810c408
44
.github/workflows/gradle-publish.yml
vendored
44
.github/workflows/gradle-publish.yml
vendored
|
|
@ -1,44 +0,0 @@
|
||||||
# This workflow uses actions that are not certified by GitHub.
|
|
||||||
# They are provided by a third-party and are governed by
|
|
||||||
# separate terms of service, privacy policy, and support
|
|
||||||
# documentation.
|
|
||||||
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
|
|
||||||
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
|
|
||||||
|
|
||||||
name: SCCore Packages
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Set up JDK 17
|
|
||||||
uses: actions/setup-java@v4
|
|
||||||
with:
|
|
||||||
java-version: '17'
|
|
||||||
distribution: 'temurin'
|
|
||||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
|
||||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
|
||||||
|
|
||||||
- name: Setup Gradle
|
|
||||||
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0
|
|
||||||
|
|
||||||
- name: Build with Gradle
|
|
||||||
run: ./gradlew build
|
|
||||||
|
|
||||||
# The USERNAME and TOKEN need to correspond to the credentials environment variables used in
|
|
||||||
# the publishing section of your build.gradle
|
|
||||||
- name: Publish to GitHub Packages
|
|
||||||
run: ./gradlew publish
|
|
||||||
env:
|
|
||||||
USERNAME: ${{ github.actor }}
|
|
||||||
TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,5 +1,6 @@
|
||||||
.idea
|
.idea
|
||||||
.gradle
|
.gradle
|
||||||
|
.github
|
||||||
build
|
build
|
||||||
run
|
run
|
||||||
run-data
|
run-data
|
||||||
|
|
@ -12,7 +12,7 @@ mapping_version=2023.09.03-1.20.1
|
||||||
mod_id=sccore
|
mod_id=sccore
|
||||||
mod_name=SnowyCrescentCore
|
mod_name=SnowyCrescentCore
|
||||||
mod_license=GNU AGPL 3.0
|
mod_license=GNU AGPL 3.0
|
||||||
mod_version=1.20.1-0.0.8-hotfix
|
mod_version=1.20.1-0.1.0-pre
|
||||||
mod_group_id=com.linearpast
|
mod_group_id=com.linearpast
|
||||||
mod_authors=LostInLinearPast
|
mod_authors=LostInLinearPast
|
||||||
mod_description=A lib about capability and player animator.
|
mod_description=A lib about capability and player animator.
|
||||||
|
|
|
||||||
252
gradlew
vendored
252
gradlew
vendored
|
|
@ -1,252 +0,0 @@
|
||||||
#!/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.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# 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/platforms/jvm/plugins-application/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 -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
|
||||||
' "$PWD" ) || 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" "$@"
|
|
||||||
94
gradlew.bat
vendored
94
gradlew.bat
vendored
|
|
@ -1,94 +0,0 @@
|
||||||
@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
|
|
||||||
@rem SPDX-License-Identifier: Apache-2.0
|
|
||||||
@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
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"key": "sccore:normal_layers",
|
|
||||||
"priority": 42
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "sccore:ride_layers",
|
|
||||||
"priority": 43
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
// 1.20.1 2025-10-30T21:02:30.6951333 Languages: zh_cn
|
// 1.20.1 2025-11-26T10:22:37.4821986 Languages: zh_cn
|
||||||
feac50843a3ec6d5a3ad4c4e917d0f19a2b857cb assets/sccore/lang/zh_cn.json
|
bfd0415418a7b7d284a9b445fd35a7242782beea assets/sccore/lang/zh_cn.json
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
// 1.20.1 2025-10-30T21:02:30.6972105 Languages: en_us
|
// 1.20.1 2025-11-26T10:22:37.4835694 Languages: en_us
|
||||||
165168d6118e3dde833169d2ab1bc0028d425d55 assets/sccore/lang/en_us.json
|
874336226401ae3f556eec3296550b37f72d8831 assets/sccore/lang/en_us.json
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,30 @@
|
||||||
{
|
{
|
||||||
"translation.sccore.animation.command_cooldown": "You cannot execute this command, cooling down: %s seconds.",
|
"translation.sccore.animation.animation_cooldown": "You cannot perform this operation: Cooling down (%s second(s)).",
|
||||||
"translation.sccore.animation.unknown_animation": "Unknown animation %s, please check if your resource packs is complete.",
|
"translation.sccore.animation.animation_expire": "You cannot perform this operation: It has expired.",
|
||||||
"translation.sccore.animation.without_animation_ride_entity": "Command run fail, full or unsupported animations.",
|
"translation.sccore.animation.animation_operation_unsupported": "Error: Unsupported operation.",
|
||||||
"translation.sccore.command.animation.accept_apply_expired": "Application expired.(%s minute(s))",
|
"translation.sccore.animation.animation_out_range": "You cannot perform this operation: The distance is not within %s blocks.",
|
||||||
|
"translation.sccore.animation.animation_resource_not_found": "Error: Resource not found, please check if there are any errors in the resource or operation.",
|
||||||
"translation.sccore.command.animation.accept_apply_success": "%s has accepted the application of %s.",
|
"translation.sccore.command.animation.accept_apply_success": "%s has accepted the application of %s.",
|
||||||
"translation.sccore.command.animation.accept_apply_too_far": "You are too far apart. (%s block(s))",
|
|
||||||
"translation.sccore.command.animation.accept_invite_expired": "Invite expired.(%s minute(s))",
|
|
||||||
"translation.sccore.command.animation.accept_invite_success": "Invitation accepted.",
|
"translation.sccore.command.animation.accept_invite_success": "Invitation accepted.",
|
||||||
"translation.sccore.command.animation.accept_invite_too_far": "You are too far apart. (%s block(s))",
|
|
||||||
"translation.sccore.command.animation.accept_message_click": "Click here to accept.",
|
"translation.sccore.command.animation.accept_message_click": "Click here to accept.",
|
||||||
"translation.sccore.command.animation.accept_request_expired": "Request expired.(%s minute(s))",
|
|
||||||
"translation.sccore.command.animation.accept_request_success": "Request accepted.",
|
"translation.sccore.command.animation.accept_request_success": "Request accepted.",
|
||||||
"translation.sccore.command.animation.animation_json_path": "%s",
|
"translation.sccore.command.animation.animation_json_path": "%s",
|
||||||
"translation.sccore.command.animation.animation_layer_not_present": "Animation layer is not present.",
|
|
||||||
"translation.sccore.command.animation.animation_not_present": "Animation is not present.",
|
|
||||||
"translation.sccore.command.animation.animation_to_json": "The animation %s has been stored in the path on %s:",
|
"translation.sccore.command.animation.animation_to_json": "The animation %s has been stored in the path on %s:",
|
||||||
"translation.sccore.command.animation.applied_join_message": "%S§b§l Apply for §r to join your animation. ",
|
"translation.sccore.command.animation.applied_join_message": "%S§b§l Apply for §r to join your animation. ",
|
||||||
"translation.sccore.command.animation.apply_expired": "%s has accepted your animation application but the application has expired. (%s minute(s))",
|
|
||||||
"translation.sccore.command.animation.apply_join_message": "Application sent.",
|
"translation.sccore.command.animation.apply_join_message": "Application sent.",
|
||||||
"translation.sccore.command.animation.apply_success": "%s has accepted your animation application.",
|
"translation.sccore.command.animation.apply_success": "%s has accepted your animation application.",
|
||||||
"translation.sccore.command.animation.apply_too_far": "%s has accepted your animation application but you are too far apart. (%s block(s))",
|
|
||||||
"translation.sccore.command.animation.clear_animations": "Animation cleared.",
|
"translation.sccore.command.animation.clear_animations": "Animation cleared.",
|
||||||
"translation.sccore.command.animation.command_run_fail": "Command run fail.",
|
"translation.sccore.command.animation.command_run_fail": "Command run fail.",
|
||||||
"translation.sccore.command.animation.command_run_success": "Command run success.",
|
"translation.sccore.command.animation.command_run_success": "Command run success.",
|
||||||
"translation.sccore.command.animation.invite_expired": "%s has accepted your animation invitation but the invitation has expired. (%s minute(s))",
|
|
||||||
"translation.sccore.command.animation.invite_message": "Invitation sent.",
|
"translation.sccore.command.animation.invite_message": "Invitation sent.",
|
||||||
"translation.sccore.command.animation.invite_success": "%s has accepted your animation invitation.",
|
"translation.sccore.command.animation.invite_success": "%s has accepted your animation invitation.",
|
||||||
"translation.sccore.command.animation.invite_too_far": "%s has accepted your animation invitation but you are too far apart. (%s block(s))",
|
|
||||||
"translation.sccore.command.animation.invited_message": "%s§c§l invites§r you to animation: %s. ",
|
"translation.sccore.command.animation.invited_message": "%s§c§l invites§r you to animation: %s. ",
|
||||||
|
"translation.sccore.command.animation.list_animation_resource": "The %2$s on %1$s has : %s",
|
||||||
"translation.sccore.command.animation.play_animation_fail": "Fail to play animation with: %s",
|
"translation.sccore.command.animation.play_animation_fail": "Fail to play animation with: %s",
|
||||||
"translation.sccore.command.animation.play_animation_success": "Successfully played animation on %s player(s).",
|
"translation.sccore.command.animation.play_animation_success": "Successfully played animation on %s player(s).",
|
||||||
"translation.sccore.command.animation.refresh_animations": "Animation refreshed.",
|
"translation.sccore.command.animation.refresh_animations": "Animation refreshed.",
|
||||||
"translation.sccore.command.animation.remove_animation_fail": "Fail to remove animation with: %s",
|
"translation.sccore.command.animation.remove_animation_fail": "Fail to remove animation with: %s",
|
||||||
"translation.sccore.command.animation.remove_animation_success": "Successfully removed animation on %s player(s).",
|
"translation.sccore.command.animation.remove_animation_success": "Successfully removed animation on %s player(s).",
|
||||||
"translation.sccore.command.animation.request_expired": "%s has accepted your animation request but the request has expired. (%s minute(s))",
|
|
||||||
"translation.sccore.command.animation.request_message": "Request sent.",
|
"translation.sccore.command.animation.request_message": "Request sent.",
|
||||||
"translation.sccore.command.animation.request_success": "%s has accepted your animation request.",
|
"translation.sccore.command.animation.request_success": "%s has accepted your animation request.",
|
||||||
"translation.sccore.command.animation.requested_message": "%s§d§l requests§r you to animation: %s. "
|
"translation.sccore.command.animation.requested_message": "%s§d§l requests§r you to animation: %s. "
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,30 @@
|
||||||
{
|
{
|
||||||
"translation.sccore.animation.command_cooldown": "你不能执行该指令,冷却中:%s 秒。",
|
"translation.sccore.animation.animation_cooldown": "你不能执行该操作: 冷却中(%s 秒)。",
|
||||||
"translation.sccore.animation.unknown_animation": "未知的动画%s,请检查你的资源包是否完整。",
|
"translation.sccore.animation.animation_expire": "你不能执行该操作: 已过期。",
|
||||||
"translation.sccore.animation.without_animation_ride_entity": "命令执行错误,已满人或不支持的动画。",
|
"translation.sccore.animation.animation_operation_unsupported": "错误: 不支持这样做。",
|
||||||
"translation.sccore.command.animation.accept_apply_expired": "申请已超时。(%s分钟)",
|
"translation.sccore.animation.animation_out_range": "你不能执行该操作: 距离不在%s格以内。",
|
||||||
|
"translation.sccore.animation.animation_resource_not_found": "错误: 资源未找到,请检查资源或操作是否有误。",
|
||||||
"translation.sccore.command.animation.accept_apply_success": "%s 接受了 %s 的申请。",
|
"translation.sccore.command.animation.accept_apply_success": "%s 接受了 %s 的申请。",
|
||||||
"translation.sccore.command.animation.accept_apply_too_far": "你们距离太远了。(%s格)",
|
|
||||||
"translation.sccore.command.animation.accept_invite_expired": "邀请已超时。(%s分钟)",
|
|
||||||
"translation.sccore.command.animation.accept_invite_success": "已接受邀请。",
|
"translation.sccore.command.animation.accept_invite_success": "已接受邀请。",
|
||||||
"translation.sccore.command.animation.accept_invite_too_far": "你们距离太远了。(%s格)",
|
|
||||||
"translation.sccore.command.animation.accept_message_click": "单击此处同意。",
|
"translation.sccore.command.animation.accept_message_click": "单击此处同意。",
|
||||||
"translation.sccore.command.animation.accept_request_expired": "请求已超时。(%s分钟)",
|
|
||||||
"translation.sccore.command.animation.accept_request_success": "已接受请求。",
|
"translation.sccore.command.animation.accept_request_success": "已接受请求。",
|
||||||
"translation.sccore.command.animation.animation_json_path": "%s",
|
"translation.sccore.command.animation.animation_json_path": "%s",
|
||||||
"translation.sccore.command.animation.animation_layer_not_present": "动画层不存在。",
|
|
||||||
"translation.sccore.command.animation.animation_not_present": "动画不存在。",
|
|
||||||
"translation.sccore.command.animation.animation_to_json": "动画%s已经存储到%s路径:",
|
"translation.sccore.command.animation.animation_to_json": "动画%s已经存储到%s路径:",
|
||||||
"translation.sccore.command.animation.applied_join_message": "%s§b§l 申请§r加入动画。",
|
"translation.sccore.command.animation.applied_join_message": "%s§b§l 申请§r加入动画。",
|
||||||
"translation.sccore.command.animation.apply_expired": "%s 接受了你的动画申请,但是申请超时了。(%s分钟)",
|
|
||||||
"translation.sccore.command.animation.apply_join_message": "已发送申请。",
|
"translation.sccore.command.animation.apply_join_message": "已发送申请。",
|
||||||
"translation.sccore.command.animation.apply_success": "%s 接受了你的动画申请。",
|
"translation.sccore.command.animation.apply_success": "%s 接受了你的动画申请。",
|
||||||
"translation.sccore.command.animation.apply_too_far": "%s 接受了你的动画申请,但你们距离太远了。(%s格)",
|
|
||||||
"translation.sccore.command.animation.clear_animations": "动画已清除。",
|
"translation.sccore.command.animation.clear_animations": "动画已清除。",
|
||||||
"translation.sccore.command.animation.command_run_fail": "命令执行失败。",
|
"translation.sccore.command.animation.command_run_fail": "命令执行失败。",
|
||||||
"translation.sccore.command.animation.command_run_success": "命令执行成功。",
|
"translation.sccore.command.animation.command_run_success": "命令执行成功。",
|
||||||
"translation.sccore.command.animation.invite_expired": "%s 接受了你的动画邀请,但是邀请超时了。(%s分钟)",
|
|
||||||
"translation.sccore.command.animation.invite_message": "已发送邀请。",
|
"translation.sccore.command.animation.invite_message": "已发送邀请。",
|
||||||
"translation.sccore.command.animation.invite_success": "%s 接受了你的动画邀请。",
|
"translation.sccore.command.animation.invite_success": "%s 接受了你的动画邀请。",
|
||||||
"translation.sccore.command.animation.invite_too_far": "%s 接受了你的动画邀请,但你们距离太远了。(%s格)",
|
|
||||||
"translation.sccore.command.animation.invited_message": "%s§c§l 邀请§r你进行动画:%s。",
|
"translation.sccore.command.animation.invited_message": "%s§c§l 邀请§r你进行动画:%s。",
|
||||||
|
"translation.sccore.command.animation.list_animation_resource": "%s侧的%s有:%s",
|
||||||
"translation.sccore.command.animation.play_animation_fail": "在这些玩家上播放动画失败:%s",
|
"translation.sccore.command.animation.play_animation_fail": "在这些玩家上播放动画失败:%s",
|
||||||
"translation.sccore.command.animation.play_animation_success": "在%s个玩家上播放动画成功。",
|
"translation.sccore.command.animation.play_animation_success": "在%s个玩家上播放动画成功。",
|
||||||
"translation.sccore.command.animation.refresh_animations": "动画同步状态已刷新。",
|
"translation.sccore.command.animation.refresh_animations": "动画同步状态已刷新。",
|
||||||
"translation.sccore.command.animation.remove_animation_fail": "在这些玩家上移除动画失败:%s",
|
"translation.sccore.command.animation.remove_animation_fail": "在这些玩家上移除动画失败:%s",
|
||||||
"translation.sccore.command.animation.remove_animation_success": "在%s个玩家上移除动画成功。",
|
"translation.sccore.command.animation.remove_animation_success": "在%s个玩家上移除动画成功。",
|
||||||
"translation.sccore.command.animation.request_expired": "%s 接受了你的动画请求,但是请求超时了。(%s分钟)",
|
|
||||||
"translation.sccore.command.animation.request_message": "已发送请求。",
|
"translation.sccore.command.animation.request_message": "已发送请求。",
|
||||||
"translation.sccore.command.animation.request_success": "%s 接受了你的动画请求。",
|
"translation.sccore.command.animation.request_success": "%s 接受了你的动画请求。",
|
||||||
"translation.sccore.command.animation.requested_message": "%s§d§l 请求§r你进行动画:%s。"
|
"translation.sccore.command.animation.requested_message": "%s§d§l 请求§r你进行动画:%s。"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.linearpast.sccore;
|
package com.linearpast.sccore;
|
||||||
|
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
import com.linearpast.sccore.core.ModChannel;
|
||||||
import com.linearpast.sccore.core.ModCommands;
|
import com.linearpast.sccore.core.ModCommands;
|
||||||
|
|
@ -34,7 +34,7 @@ public class SnowyCrescentCore {
|
||||||
|
|
||||||
CapabilityUtils.registerHandler(forgeBus);
|
CapabilityUtils.registerHandler(forgeBus);
|
||||||
ModChannel.register();
|
ModChannel.register();
|
||||||
AnimationUtils.register(forgeBus, modBus);
|
IAnimationHelper.register(forgeBus, modBus);
|
||||||
ModCommands.registerCommands(forgeBus, modBus);
|
ModCommands.registerCommands(forgeBus, modBus);
|
||||||
|
|
||||||
if(!FMLEnvironment.production || Boolean.getBoolean(ENABLE_EXAMPLES_PROPERTY_KEY)) {
|
if(!FMLEnvironment.production || Boolean.getBoolean(ENABLE_EXAMPLES_PROPERTY_KEY)) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.linearpast.sccore.animation;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.helper.*;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class AnimationApi {
|
||||||
|
public static AnimationApi getInstance() {
|
||||||
|
return new AnimationApi();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimationHelper getAnimationHelper() {
|
||||||
|
return AnimationHelper.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawAnimationHelper getRawAnimationHelper() {
|
||||||
|
return RawAnimationHelper.INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonHelper getJsonHelper(MinecraftServer server) {
|
||||||
|
return JsonHelper.getHelper(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAnimationHelper<?, ?> getHelperFromAnimKey(ResourceLocation location) {
|
||||||
|
return new HelperGetterFromAnimation(location).getHelper();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<IAnimationHelper<?, ?>> getAllHelpers() {
|
||||||
|
return IHelperGetter.HELPERS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
package com.linearpast.sccore.animation;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
|
||||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
|
||||||
import com.linearpast.sccore.animation.mixin.IMixinKeyframeAnimationPlayer;
|
|
||||||
import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
|
||||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRequestPacket;
|
|
||||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRidePacket;
|
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.modifier.AbstractFadeModifier;
|
|
||||||
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
|
||||||
import dev.kosmx.playerAnim.core.util.Ease;
|
|
||||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.client.player.AbstractClientPlayer;
|
|
||||||
import net.minecraft.client.player.LocalPlayer;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class AnimationPlayer {
|
|
||||||
|
|
||||||
public static void requestAnimationToServer(@Nullable AbstractClientPlayer player, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
|
||||||
UUID uuid = null;
|
|
||||||
if(player != null) uuid = player.getUUID();
|
|
||||||
ModChannel.sendToServer(new PlayAnimationRequestPacket(uuid, layer, animation));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean serverPlayAnimation(ServerPlayer serverPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
|
||||||
if(data == null) return false;
|
|
||||||
if(animation != null) {
|
|
||||||
return data.mergeAnimation(layer, animation);
|
|
||||||
} else {
|
|
||||||
return data.removeAnimation(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean playAnimationWithRide(ServerPlayer serverPlayer, ResourceLocation layer, @Nullable ResourceLocation animation, boolean force){
|
|
||||||
if(animation != null) {
|
|
||||||
return AnimationRideEntity.create(serverPlayer, layer, animation, force);
|
|
||||||
} else {
|
|
||||||
serverPlayer.unRide();
|
|
||||||
AnimationDataCapability.getCapability(serverPlayer).ifPresent(IAnimationCapability::removeRiderAnimation);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void requestAnimationRideToServer(ResourceLocation layer, @Nullable ResourceLocation animation, boolean force) {
|
|
||||||
ModChannel.sendToServer(new PlayAnimationRidePacket(layer, animation, force));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearAnimation(ServerPlayer serverPlayer) {
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
|
||||||
if(data == null) return;
|
|
||||||
data.clearAnimations();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void syncAnimation(ServerPlayer player, ServerPlayer target) {
|
|
||||||
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID()), player);
|
|
||||||
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID()), target);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static void syncAnimation(AbstractClientPlayer clientPlayer, AbstractClientPlayer target) {
|
|
||||||
try {
|
|
||||||
IAnimationCapability clientPlayerData = AnimationDataCapability.getCapability(clientPlayer).orElse(null);
|
|
||||||
if(clientPlayerData == null) return;
|
|
||||||
IAnimationCapability targetData = AnimationDataCapability.getCapability(target).orElse(null);
|
|
||||||
if(targetData == null) return;
|
|
||||||
ResourceLocation clientPlayerLayer = clientPlayerData.getRiderAnimLayer();
|
|
||||||
ResourceLocation targetLayer = targetData.getRiderAnimLayer();
|
|
||||||
if(clientPlayerLayer == null || targetLayer == null) return;
|
|
||||||
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
|
||||||
.getPlayerAssociatedData(clientPlayer).get(clientPlayerLayer);
|
|
||||||
ModifierLayer<IAnimation> targetModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
|
||||||
.getPlayerAssociatedData(target).get(targetLayer);
|
|
||||||
if(modifierLayer == null || targetModifierLayer == null) return;
|
|
||||||
IMixinKeyframeAnimationPlayer animation = (IMixinKeyframeAnimationPlayer) modifierLayer.getAnimation();
|
|
||||||
KeyframeAnimationPlayer targetAnimation = (KeyframeAnimationPlayer) targetModifierLayer.getAnimation();
|
|
||||||
if(animation == null || targetAnimation == null) return;
|
|
||||||
int currentTick = targetAnimation.getCurrentTick();
|
|
||||||
animation.sccore$setCurrentTick(currentTick);
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static void playAnimation(@Nullable AbstractClientPlayer clientPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
|
||||||
try {
|
|
||||||
LocalPlayer localPlayer = Minecraft.getInstance().player;
|
|
||||||
if(clientPlayer == null) clientPlayer = localPlayer;
|
|
||||||
if(clientPlayer == null) return;
|
|
||||||
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
|
||||||
.getPlayerAssociatedData(clientPlayer).get(layer);
|
|
||||||
if(animation == null) {
|
|
||||||
if(modifierLayer != null) {
|
|
||||||
modifierLayer.replaceAnimationWithFade(
|
|
||||||
AbstractFadeModifier.standardFadeIn(3, Ease.INOUTSINE),
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Animation anim = AnimationUtils.getAnimation(animation);
|
|
||||||
if(anim == null) return;
|
|
||||||
if(modifierLayer == null) return;
|
|
||||||
KeyframeAnimation keyframeAnimation = anim.getAnimation();
|
|
||||||
if(keyframeAnimation == null) {
|
|
||||||
if(localPlayer == null) return;
|
|
||||||
localPlayer.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.UNKNOWN_ANIMATION.getKey(),
|
|
||||||
animation.toString()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
Objects.requireNonNull(modifierLayer).replaceAnimationWithFade(
|
|
||||||
AbstractFadeModifier.standardFadeIn(3, Ease.INOUTSINE),
|
|
||||||
new KeyframeAnimationPlayer(keyframeAnimation)
|
|
||||||
);
|
|
||||||
}catch (Exception e) {
|
|
||||||
SnowyCrescentCore.log.error("Failed to play animation : {}", animation, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,434 +0,0 @@
|
||||||
package com.linearpast.sccore.animation;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
|
||||||
import com.linearpast.sccore.animation.data.Ride;
|
|
||||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
|
||||||
import com.linearpast.sccore.animation.event.PlayerTickEvent;
|
|
||||||
import com.linearpast.sccore.animation.event.client.CameraAnglesModify;
|
|
||||||
import com.linearpast.sccore.animation.event.client.ClientPlayerTick;
|
|
||||||
import com.linearpast.sccore.animation.event.client.EntityRendererRegisterEvent;
|
|
||||||
import com.linearpast.sccore.animation.network.toserver.RefreshAnimationPacket;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationCapabilities;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationChannels;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationEntities;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
|
||||||
import com.linearpast.sccore.core.ModLazyRun;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
|
||||||
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
|
||||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
|
||||||
import net.minecraft.client.player.AbstractClientPlayer;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
||||||
import net.minecraftforge.common.util.FakePlayer;
|
|
||||||
import net.minecraftforge.eventbus.api.IEventBus;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Animation Util. May be you can call it Api.
|
|
||||||
*/
|
|
||||||
public class AnimationUtils {
|
|
||||||
public static final String AnimModId = "playeranimator";
|
|
||||||
public static final ModLazyRun ANIMATION_RUNNER = new ModLazyRun(AnimModId) {
|
|
||||||
@Override
|
|
||||||
public void addCommonListener(IEventBus forgeBus, IEventBus modBus) {
|
|
||||||
AnimationEntities.register(modBus);
|
|
||||||
forgeBus.addListener(AnimationRegistry::onServerStarted);
|
|
||||||
forgeBus.addListener(AnimationRegistry::onPlayerLoggedIn);
|
|
||||||
forgeBus.addListener(PlayerTickEvent::onPlayerTickEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addClientListener(IEventBus forgeBus, IEventBus modBus) {
|
|
||||||
forgeBus.addListener(CameraAnglesModify::changeCameraView);
|
|
||||||
modBus.addListener(EntityRendererRegisterEvent::registerEntityRenderer);
|
|
||||||
forgeBus.addListener(ClientPlayerTick::onPlayerTick);
|
|
||||||
forgeBus.addListener(ClientPlayerTick::delayRuns);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* Play animation.
|
|
||||||
* If run in Dist.CLIENT, player can be null, it will play animation only client.
|
|
||||||
* If animation be null, it will remove animation on layer.
|
|
||||||
* </pre>
|
|
||||||
* @param player Target player
|
|
||||||
* @param layer Target layer
|
|
||||||
* @param animation Animation
|
|
||||||
* @return If success
|
|
||||||
*/
|
|
||||||
public static boolean playAnimation(@Nullable Player player, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
if(isAnimationLayerPresent(layer) && (animation == null || isAnimationPresent(animation))) {
|
|
||||||
if(player instanceof ServerPlayer serverPlayer) {
|
|
||||||
if(serverPlayer instanceof FakePlayer) return false;
|
|
||||||
return AnimationPlayer.serverPlayAnimation(serverPlayer, layer, animation);
|
|
||||||
}else if(player == null || player instanceof AbstractClientPlayer) {
|
|
||||||
AnimationPlayer.requestAnimationToServer((AbstractClientPlayer) player, layer, animation);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Client send request to server and run play animation. <br>
|
|
||||||
* Only play animation with client self.
|
|
||||||
* @param layer Target layer
|
|
||||||
* @param animation Target animation
|
|
||||||
* @return If success
|
|
||||||
*/
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static boolean requestAnimationClient(@Nullable AbstractClientPlayer player, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
if(isAnimationLayerPresent(layer) && (animation == null || isAnimationPresent(animation))) {
|
|
||||||
AnimationPlayer.requestAnimationToServer(player, layer, animation);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* Play animation with ride. Player will ride an entity, then play animation.
|
|
||||||
* When player unride, animation will be remove.
|
|
||||||
* If run in Dist.CLIENT, the serverPlayer can be null.
|
|
||||||
* If animation be null, it will call function: {@link ServerPlayer#unRide()}
|
|
||||||
* If player is riding and the "force" is false, it will return false
|
|
||||||
* </pre>
|
|
||||||
* @param serverPlayer Target player
|
|
||||||
* @param layer Target layer
|
|
||||||
* @param animation Animation
|
|
||||||
* @param force If force to ride and play animation
|
|
||||||
* @return If success
|
|
||||||
*/
|
|
||||||
public static boolean playAnimationWithRide(@Nullable ServerPlayer serverPlayer, ResourceLocation layer, @Nullable ResourceLocation animation, boolean force) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
if(isAnimationLayerPresent(layer) && (animation == null || isAnimationPresent(animation))) {
|
|
||||||
Animation anim = AnimationUtils.getAnimation(animation);
|
|
||||||
if(anim != null && anim.getRide() == null) return false;
|
|
||||||
if(serverPlayer != null) {
|
|
||||||
if(serverPlayer instanceof FakePlayer) return false;
|
|
||||||
if(serverPlayer.getVehicle() != null && force) serverPlayer.unRide();
|
|
||||||
else if(serverPlayer.getVehicle() != null) return false;
|
|
||||||
return AnimationPlayer.playAnimationWithRide(serverPlayer, layer, animation, true);
|
|
||||||
} else {
|
|
||||||
AnimationPlayer.requestAnimationRideToServer(layer, animation, force);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove animation.
|
|
||||||
* @see AnimationUtils#playAnimation
|
|
||||||
* @param player Target player
|
|
||||||
* @param layer Target layer
|
|
||||||
* @return If success
|
|
||||||
*/
|
|
||||||
public static boolean removeAnimation(@Nullable Player player, ResourceLocation layer) {
|
|
||||||
return playAnimation(player, layer, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get animation which is playing now on player. <br>
|
|
||||||
* If layer is null, it will return the first playing animation which can be found.
|
|
||||||
* @param player Target player
|
|
||||||
* @param layer Target layer
|
|
||||||
* @return Playing animation resource location
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static ResourceLocation getAnimationPlaying(Player player, @Nullable ResourceLocation layer) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
|
||||||
if(data == null) return null;
|
|
||||||
if(layer == null){
|
|
||||||
for (ResourceLocation value : data.getAnimations().values()) {
|
|
||||||
if(value != null) return value;
|
|
||||||
}
|
|
||||||
} else if (isAnimationLayerPresent(layer)) {
|
|
||||||
if(data.isAnimationPresent(layer)){
|
|
||||||
return data.getAnimation(layer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if layer exist animation which is not stop.
|
|
||||||
* <p>
|
|
||||||
* Only in dist client
|
|
||||||
* @param player Target player
|
|
||||||
* @param layer Target layer
|
|
||||||
* @return True when the currentTick not larger than stopTick
|
|
||||||
*/
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static boolean isClientAnimationNotStop(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
try {
|
|
||||||
Set<ResourceLocation> resourceLocations = new HashSet<>();
|
|
||||||
if(layer == null) resourceLocations = AnimationRegistry.getLayers().keySet();
|
|
||||||
else resourceLocations.add(layer);
|
|
||||||
for (ResourceLocation location : resourceLocations) {
|
|
||||||
ModifierLayer<IAnimation> animationModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
|
||||||
.getPlayerAssociatedData(player).get(location);
|
|
||||||
if(animationModifierLayer == null) continue;
|
|
||||||
KeyframeAnimationPlayer animation = (KeyframeAnimationPlayer) animationModifierLayer.getAnimation();
|
|
||||||
if(animation == null) return false;
|
|
||||||
int currentTick = animation.getCurrentTick();
|
|
||||||
int stopTick = animation.getStopTick();
|
|
||||||
return currentTick <= stopTick;
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if layer exist animation which is not end.
|
|
||||||
* <p>
|
|
||||||
* Only in dist client
|
|
||||||
* @param player Target player
|
|
||||||
* @param layer Target layer
|
|
||||||
* @return True when animation is loop, or currentTick not larger than endTick
|
|
||||||
*/
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static boolean isClientAnimationNotEnd(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
try {
|
|
||||||
Set<ResourceLocation> resourceLocations = new HashSet<>();
|
|
||||||
if(layer == null) resourceLocations = AnimationRegistry.getLayers().keySet();
|
|
||||||
else resourceLocations.add(layer);
|
|
||||||
for (ResourceLocation location : resourceLocations) {
|
|
||||||
ModifierLayer<IAnimation> animationModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
|
||||||
.getPlayerAssociatedData(player).get(location);
|
|
||||||
if(animationModifierLayer == null) continue;
|
|
||||||
KeyframeAnimationPlayer animation = (KeyframeAnimationPlayer) animationModifierLayer.getAnimation();
|
|
||||||
if(animation == null) return false;
|
|
||||||
int currentTick = animation.getCurrentTick();
|
|
||||||
boolean isLoop = animation.getData().isInfinite;
|
|
||||||
int endTick = animation.getData().endTick;
|
|
||||||
return isLoop || currentTick <= endTick;
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync animation tick to client
|
|
||||||
* @param player Player
|
|
||||||
* @param target Target player
|
|
||||||
*/
|
|
||||||
public static void syncAnimation(ServerPlayer player, ServerPlayer target) {
|
|
||||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.syncAnimation(player, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sync animation tick on client
|
|
||||||
* @param player Player
|
|
||||||
* @param target Target player
|
|
||||||
*/
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static void syncAnimation(AbstractClientPlayer player, AbstractClientPlayer target) {
|
|
||||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.syncAnimation(player, target));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Join animation.
|
|
||||||
* @param player Will join player
|
|
||||||
* @param target Joined player
|
|
||||||
* @param force If force
|
|
||||||
* @return If success
|
|
||||||
*/
|
|
||||||
public static boolean joinAnimation(ServerPlayer player, ServerPlayer target, boolean force) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
Entity vehicle = target.getVehicle();
|
|
||||||
if(!(vehicle instanceof AnimationRideEntity rideEntity)) return false;
|
|
||||||
int playerCount = rideEntity.getPlayers().size();
|
|
||||||
Animation animation = rideEntity.getAnimation();
|
|
||||||
if(animation == null) return false;
|
|
||||||
Ride ride = animation.getRide();
|
|
||||||
if(ride == null) return false;
|
|
||||||
int maxCount = ride.getComponentAnimations().size();
|
|
||||||
if(playerCount >= maxCount) return false;
|
|
||||||
return player.startRiding(vehicle, force);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <pre>
|
|
||||||
* Start animation together...
|
|
||||||
* The max participants' count is depend on your animation.
|
|
||||||
* Max count = Size of {@link Ride#getComponentAnimations()}
|
|
||||||
* </pre>
|
|
||||||
* @param player Leader
|
|
||||||
* @param layer Target layer
|
|
||||||
* @param animation Animation location
|
|
||||||
* @param force If force start leader
|
|
||||||
* @param participants Participants
|
|
||||||
*/
|
|
||||||
public static void startAnimationTogether(
|
|
||||||
ServerPlayer player,
|
|
||||||
ResourceLocation layer,
|
|
||||||
ResourceLocation animation,
|
|
||||||
boolean force,
|
|
||||||
ServerPlayer ... participants
|
|
||||||
) {
|
|
||||||
AnimationUtils.playAnimationWithRide(player, layer, animation, force);
|
|
||||||
for (ServerPlayer participant : participants) {
|
|
||||||
AnimationUtils.joinAnimation(participant, player, force);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detach animation
|
|
||||||
* @param player Player
|
|
||||||
*/
|
|
||||||
public static void detachAnimation(ServerPlayer player) {
|
|
||||||
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
|
||||||
if(player.getVehicle() instanceof AnimationRideEntity) {
|
|
||||||
player.unRide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear Player animations.
|
|
||||||
* @param serverPlayer Target player
|
|
||||||
*/
|
|
||||||
public static void clearAnimation(ServerPlayer serverPlayer) {
|
|
||||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.clearAnimation(serverPlayer));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if layer exist and has been invite.
|
|
||||||
* @param layer Target layer
|
|
||||||
* @return If layer exist and has been invite
|
|
||||||
*/
|
|
||||||
public static boolean isAnimationLayerPresent(ResourceLocation layer) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationRegistry.getLayers().containsKey(layer));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if animation exist and has been invite.
|
|
||||||
* @param location Animation resource location
|
|
||||||
* @return If animation exist and has been invited
|
|
||||||
*/
|
|
||||||
public static boolean isAnimationPresent(ResourceLocation location) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationRegistry.getAnimations().containsKey(location));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The register handler
|
|
||||||
* @param forgeBus Forge event bus
|
|
||||||
* @param modBus Mod event bus
|
|
||||||
*/
|
|
||||||
public static void register(IEventBus forgeBus, IEventBus modBus){
|
|
||||||
AnimationUtils.ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
|
||||||
AnimationCapabilities.registerAnimationCapability();
|
|
||||||
AnimationChannels.registerChannel();
|
|
||||||
});
|
|
||||||
AnimationUtils.ANIMATION_RUNNER.testLoadedAndAddListener(forgeBus, modBus);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get animation data from animation resource location. <br>
|
|
||||||
* You will get null if you use it too early. <br>
|
|
||||||
* Suggest only use it in game has loaded.
|
|
||||||
* @param location Animation resource location
|
|
||||||
* @return Animation data
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static Animation getAnimation(ResourceLocation location) {
|
|
||||||
return AnimationRegistry.getAnimations().getOrDefault(location, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the LyingType when there are animations which playing on player. <br>
|
|
||||||
* And It will return the first which be found.
|
|
||||||
* @param player Target player
|
|
||||||
* @return The first LyingType it find.
|
|
||||||
*/
|
|
||||||
@Nullable
|
|
||||||
public static Animation.LyingType getSideView(Player player) {
|
|
||||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
|
||||||
if(data == null) return null;
|
|
||||||
Animation.LyingType lyingType = null;
|
|
||||||
for (ResourceLocation value : data.getAnimations().values()) {
|
|
||||||
Animation animation = getAnimation(value);
|
|
||||||
if(animation == null) return null;
|
|
||||||
Animation.LyingType type = animation.getLyingType();
|
|
||||||
if(type == null) continue;
|
|
||||||
switch (type) {
|
|
||||||
case FRONT,BACK -> {}
|
|
||||||
case LEFT,RIGHT -> lyingType = animation.getLyingType();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lyingType;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the HeightModifier when there are animations which playing on player. <br>
|
|
||||||
* And It will return the first which be found.
|
|
||||||
* @param player Target player
|
|
||||||
* @return The first HeightModifier it find.
|
|
||||||
*/
|
|
||||||
public static float getHeightModifier(Player player) {
|
|
||||||
Float result = ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
|
||||||
if (data == null) return 1.0f;
|
|
||||||
float heightModifier = 1.0f;
|
|
||||||
for (ResourceLocation value : data.getAnimations().values()) {
|
|
||||||
Animation animation = getAnimation(value);
|
|
||||||
if (animation == null) continue;
|
|
||||||
float animationHeightModifier = animation.getHeightModifier();
|
|
||||||
heightModifier = Math.min(heightModifier, animationHeightModifier);
|
|
||||||
}
|
|
||||||
return heightModifier;
|
|
||||||
});
|
|
||||||
return result == null ? 1.0f : result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if animation is playing <br>
|
|
||||||
* if not, it will remove the animation resource location on client
|
|
||||||
* <p>
|
|
||||||
* Only in dist client
|
|
||||||
* @param clientPlayer Target player
|
|
||||||
*/
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
|
||||||
public static void refreshAnimation(AbstractClientPlayer clientPlayer) {
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(clientPlayer).orElse(null);
|
|
||||||
if(data == null) return;
|
|
||||||
Set<ResourceLocation> oldLayers = new HashSet<>(data.getAnimations().keySet());
|
|
||||||
boolean dirty = false;
|
|
||||||
for (ResourceLocation layer : Set.copyOf(oldLayers)) {
|
|
||||||
if (!isClientAnimationNotStop(clientPlayer, layer)) {
|
|
||||||
oldLayers.remove(layer);
|
|
||||||
dirty = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(dirty) ModChannel.sendToServer(new RefreshAnimationPacket(oldLayers));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
package com.linearpast.sccore.animation.capability;
|
package com.linearpast.sccore.animation.capability;
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||||
|
|
@ -35,7 +35,7 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
||||||
public void mergeAnimations(Map<ResourceLocation, ResourceLocation> animations) {
|
public void mergeAnimations(Map<ResourceLocation, ResourceLocation> animations) {
|
||||||
animations.forEach((key, value) -> {
|
animations.forEach((key, value) -> {
|
||||||
if (AnimationRegistry.getLayers().containsKey(key)) {
|
if (AnimationRegistry.getLayers().containsKey(key)) {
|
||||||
if (AnimationUtils.isAnimationPresent(value)) {
|
if (AnimationHelper.INSTANCE.isAnimationPresent(value)) {
|
||||||
if(Objects.equals(rideAnimLayer, key)) {
|
if(Objects.equals(rideAnimLayer, key)) {
|
||||||
removeRiderAnimation();
|
removeRiderAnimation();
|
||||||
}
|
}
|
||||||
|
|
@ -49,7 +49,7 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
||||||
@Override
|
@Override
|
||||||
public boolean mergeAnimation(ResourceLocation layer, ResourceLocation animation) {
|
public boolean mergeAnimation(ResourceLocation layer, ResourceLocation animation) {
|
||||||
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
||||||
if (AnimationUtils.isAnimationPresent(animation)) {
|
if (AnimationHelper.INSTANCE.isAnimationPresent(animation)) {
|
||||||
if(Objects.equals(rideAnimLayer, layer)) {
|
if(Objects.equals(rideAnimLayer, layer)) {
|
||||||
removeRiderAnimation();
|
removeRiderAnimation();
|
||||||
}
|
}
|
||||||
|
|
@ -74,12 +74,12 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public ResourceLocation getAnimation(ResourceLocation layer) {
|
public ResourceLocation getAnimation(ResourceLocation layer) {
|
||||||
return animMap.get(layer);
|
return animMap.getOrDefault(layer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<ResourceLocation, ResourceLocation> getAnimations() {
|
public Map<ResourceLocation, ResourceLocation> getAnimations() {
|
||||||
return animMap;
|
return Map.copyOf(animMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -105,8 +105,8 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRiderAnimation(@NotNull ResourceLocation layer, @NotNull ResourceLocation animation) {
|
public void setRiderAnimation(@NotNull ResourceLocation layer, @NotNull ResourceLocation animation) {
|
||||||
if(AnimationUtils.isAnimationLayerPresent(layer)) {
|
if(AnimationHelper.INSTANCE.isAnimationLayerPresent(layer)) {
|
||||||
if(AnimationUtils.isAnimationPresent(animation)) {
|
if(AnimationHelper.INSTANCE.isAnimationPresent(animation)) {
|
||||||
this.rideAnimLayer = layer;
|
this.rideAnimLayer = layer;
|
||||||
this.rideAnimation = animation;
|
this.rideAnimation = animation;
|
||||||
if(animMap.get(layer) != null) {
|
if(animMap.get(layer) != null) {
|
||||||
|
|
@ -163,19 +163,24 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
||||||
if(tag.contains(RideAnimation)) this.rideAnimation = new ResourceLocation(tag.getString(RideAnimation));
|
if(tag.contains(RideAnimation)) this.rideAnimation = new ResourceLocation(tag.getString(RideAnimation));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SimpleCapabilityPacket<Player> getDefaultPacket() {
|
public SimpleCapabilityPacket<Player> getDefaultPacket() {
|
||||||
return new AnimationCapabilityPacket(serializeNBT());
|
return new AnimationCapabilityPacket(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void attachInit(Player player) {
|
public void attachInit(Player player) {
|
||||||
Map<ResourceLocation, ResourceLocation> map = new HashMap<>(this.animMap);
|
Map<ResourceLocation, ResourceLocation> map = new HashMap<>(this.animMap);
|
||||||
map.forEach((key, value) -> {
|
map.forEach((key, value) -> {
|
||||||
if(!AnimationUtils.isAnimationLayerPresent(key)) this.animMap.remove(key);
|
if(!AnimationHelper.INSTANCE.isAnimationLayerPresent(key)) this.animMap.remove(key);
|
||||||
if(!AnimationUtils.isAnimationPresent(value)) this.animMap.remove(key);
|
if(!AnimationHelper.INSTANCE.isAnimationPresent(value)) this.animMap.remove(key);
|
||||||
});
|
});
|
||||||
if(rideAnimLayer != null && !AnimationUtils.isAnimationLayerPresent(rideAnimLayer)) {
|
if(rideAnimLayer != null && !AnimationHelper.INSTANCE.isAnimationLayerPresent(rideAnimLayer)) {
|
||||||
removeRiderAnimation();
|
removeRiderAnimation();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,172 @@
|
||||||
|
package com.linearpast.sccore.animation.capability;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.network.toclient.RawAnimationCapabilityPacket;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||||
|
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
||||||
|
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
||||||
|
import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public class RawAnimationDataCapability extends SimplePlayerCapabilitySync {
|
||||||
|
public static final ResourceLocation key = new ResourceLocation(SnowyCrescentCore.MODID, "raw_animation_data");
|
||||||
|
|
||||||
|
public static final String AnimMap = "AnimMap";
|
||||||
|
public static final String RideAnimLayer = "RideAnimLayer";
|
||||||
|
public static final String RideAnimation = "RideAnimation";
|
||||||
|
|
||||||
|
private final Map<ResourceLocation, ResourceLocation> animMap = new HashMap<>();
|
||||||
|
private ResourceLocation rideAnimLayer;
|
||||||
|
private ResourceLocation rideAnimation;
|
||||||
|
|
||||||
|
public boolean mergeAnimation(ResourceLocation layer, ResourceLocation animation) {
|
||||||
|
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
||||||
|
if(Objects.equals(rideAnimLayer, layer)) {
|
||||||
|
removeRiderAnimation();
|
||||||
|
}
|
||||||
|
this.animMap.put(layer, animation);
|
||||||
|
setDirty(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeAnimation(ResourceLocation layer) {
|
||||||
|
ResourceLocation remove = this.animMap.remove(layer);
|
||||||
|
if(remove != null) {
|
||||||
|
setDirty(true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ResourceLocation getAnimation(ResourceLocation layer) {
|
||||||
|
return animMap.getOrDefault(layer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<ResourceLocation, ResourceLocation> getAnimations() {
|
||||||
|
return Map.copyOf(animMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearAnimations() {
|
||||||
|
this.animMap.clear();
|
||||||
|
setDirty(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isAnimationPresent(ResourceLocation layer) {
|
||||||
|
return animMap.containsKey(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation getRiderAnimLayer() {
|
||||||
|
return rideAnimLayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation getRiderAnimation() {
|
||||||
|
return rideAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRiderAnimation(@NotNull ResourceLocation layer, @NotNull ResourceLocation animation) {
|
||||||
|
if(AnimationHelper.INSTANCE.isAnimationLayerPresent(layer)) {
|
||||||
|
MinecraftServer currentServer = ServerLifecycleHooks.getCurrentServer();
|
||||||
|
if(currentServer == null) return;
|
||||||
|
ServerPlayer serverPlayer = currentServer.getPlayerList().getPlayer(this.getOwnerUUID());
|
||||||
|
if(serverPlayer == null) return;
|
||||||
|
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
||||||
|
if(data == null) return;
|
||||||
|
if(data.getRiderAnimation() != null) return;
|
||||||
|
if(data.getRiderAnimLayer() != null) {
|
||||||
|
data.removeRiderAnimation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.rideAnimLayer = layer;
|
||||||
|
this.rideAnimation = animation;
|
||||||
|
if(animMap.get(layer) != null) {
|
||||||
|
animMap.remove(layer);
|
||||||
|
}
|
||||||
|
setDirty(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeRiderAnimation() {
|
||||||
|
this.rideAnimLayer = null;
|
||||||
|
this.rideAnimation = null;
|
||||||
|
setDirty(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void copyFrom(ICapabilitySync<?> oldData) {
|
||||||
|
IAnimationCapability data = (IAnimationCapability) oldData;
|
||||||
|
this.animMap.clear();
|
||||||
|
this.animMap.putAll(data.getAnimations());
|
||||||
|
this.rideAnimLayer = data.getRiderAnimLayer();
|
||||||
|
this.rideAnimation = data.getRiderAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag toTag(CompoundTag tag) {
|
||||||
|
if(!animMap.isEmpty()) {
|
||||||
|
CompoundTag animMapTag = new CompoundTag();
|
||||||
|
animMap.forEach((string, animation) ->
|
||||||
|
animMapTag.putString(string.toString(), animation.toString())
|
||||||
|
);
|
||||||
|
tag.put(AnimMap, animMapTag);
|
||||||
|
}
|
||||||
|
if(rideAnimLayer != null) tag.putString(RideAnimLayer, rideAnimLayer.toString());
|
||||||
|
if(rideAnimation != null) tag.putString(RideAnimation, rideAnimation.toString());
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void fromTag(CompoundTag tag) {
|
||||||
|
this.animMap.clear();
|
||||||
|
this.rideAnimLayer = null;
|
||||||
|
this.rideAnimation = null;
|
||||||
|
if(tag.contains(AnimMap)) {
|
||||||
|
CompoundTag animMapTag = tag.getCompound(AnimMap);
|
||||||
|
animMapTag.getAllKeys().forEach(key -> this.animMap.put(
|
||||||
|
new ResourceLocation(key),
|
||||||
|
new ResourceLocation(animMapTag.getString(key))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if(tag.contains(RideAnimLayer)) this.rideAnimLayer = new ResourceLocation(tag.getString(RideAnimLayer));
|
||||||
|
if(tag.contains(RideAnimation)) this.rideAnimation = new ResourceLocation(tag.getString(RideAnimation));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SimpleCapabilityPacket<Player> getDefaultPacket() {
|
||||||
|
return new RawAnimationCapabilityPacket(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void attachInit(Player entity) {
|
||||||
|
clearAnimations();
|
||||||
|
removeRiderAnimation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Optional<RawAnimationDataCapability> getCapability(Player player){
|
||||||
|
return Optional.ofNullable(CapabilityUtils.getPlayerCapability(
|
||||||
|
player, RawAnimationDataCapability.key, RawAnimationDataCapability.class
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
package com.linearpast.sccore.animation.command;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.animation.command.exception.ApiBackException;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IHelperGetter;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.arguments.EntityArgument;
|
||||||
|
import net.minecraft.network.chat.ClickEvent;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.Commands.argument;
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
|
public class ApplyCommand {
|
||||||
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||||
|
animCommand
|
||||||
|
.then(literal("apply")
|
||||||
|
.then(argument("target", EntityArgument.player())
|
||||||
|
.executes(ApplyCommand::apply)
|
||||||
|
)
|
||||||
|
.then(literal("accept")
|
||||||
|
.then(argument("player", EntityArgument.player())
|
||||||
|
.executes(ApplyCommand::acceptApply)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int apply(CommandContext<CommandSourceStack> context) {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
try {
|
||||||
|
ServerPlayer target = EntityArgument.getPlayer(context, "target");
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
|
||||||
|
Entity vehicle = target.getVehicle();
|
||||||
|
if(vehicle == null) throw new ApiBackException(ApiBack.UNSUPPORTED);
|
||||||
|
|
||||||
|
ApiBack back = AnimationHelper.INSTANCE.apply(player, target);
|
||||||
|
if(back == ApiBack.COOLDOWN) {
|
||||||
|
int cooldown = ModConfigs.Server.applyCooldown.get();
|
||||||
|
throw ApiBackException.withCooldown(cooldown);
|
||||||
|
}
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
|
//click event
|
||||||
|
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
||||||
|
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim apply accept " + player.getName().getString())
|
||||||
|
).withUnderlined(true);
|
||||||
|
|
||||||
|
//send message to all participants
|
||||||
|
for (Entity passenger : vehicle.getPassengers()) {
|
||||||
|
passenger.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.APPLIED_JOIN_MESSAGE.getKey(),
|
||||||
|
player.getName().copy()
|
||||||
|
).append(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
||||||
|
).setStyle(pStyle)));
|
||||||
|
}
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.APPLY_JOIN_MESSAGE.getKey()
|
||||||
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
return 1;
|
||||||
|
} catch (ApiBackException e) {
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
|
} catch (Exception e) {
|
||||||
|
source.sendFailure(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int acceptApply(CommandContext<CommandSourceStack> context) {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
try {
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
ServerPlayer applier = EntityArgument.getPlayer(context, "applier");
|
||||||
|
|
||||||
|
Entity vehicle = player.getVehicle();
|
||||||
|
if(vehicle == null) throw new ApiBackException(ApiBack.UNSUPPORTED);
|
||||||
|
|
||||||
|
ApiBack back = ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
for (IAnimationHelper<?, ?> helper : IHelperGetter.HELPERS) {
|
||||||
|
back = helper.acceptApply(player, applier);
|
||||||
|
if(back == ApiBack.SUCCESS) break;
|
||||||
|
}
|
||||||
|
if(back == ApiBack.OUT_RANGE) throw ApiBackException.withOutRange(ModConfigs.Server.applyValidDistance.get());
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
|
//define message
|
||||||
|
MutableComponent successMessage = Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ACCEPT_APPLY_SUCCESS.getKey(),
|
||||||
|
player.getName().copy(), applier.getName().copy()
|
||||||
|
).withStyle(ChatFormatting.GREEN);
|
||||||
|
|
||||||
|
//send message
|
||||||
|
source.sendSuccess(() -> successMessage, true);
|
||||||
|
for (Entity passenger : vehicle.getPassengers()) {
|
||||||
|
if(!passenger.getUUID().equals(player.getUUID()) && !passenger.getUUID().equals(applier.getUUID())) {
|
||||||
|
passenger.sendSystemMessage(successMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
applier.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.APPLY_SUCCESS.getKey(),
|
||||||
|
player.getName().copy()
|
||||||
|
).withStyle(ChatFormatting.GREEN));
|
||||||
|
} catch (ApiBackException e) {
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
|
} catch (Exception e) {
|
||||||
|
source.sendFailure(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,191 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.command;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
|
||||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.commands.arguments.EntityArgument;
|
|
||||||
import net.minecraft.network.chat.ClickEvent;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.MutableComponent;
|
|
||||||
import net.minecraft.network.chat.Style;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
public class ApplyJoinAnimCommand {
|
|
||||||
private static final Map<UUID, Map<UUID, ApplyRecord>> applies = new HashMap<>();
|
|
||||||
record ApplyRecord(long time, boolean isForce){}
|
|
||||||
private static final Map<UUID, Long> lastAppliedMap = new HashMap<>();
|
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
|
||||||
animCommand
|
|
||||||
.then(literal("joinApply")
|
|
||||||
.then(argument("target", EntityArgument.player())
|
|
||||||
.executes(ApplyJoinAnimCommand::tryJoinAnimation)
|
|
||||||
.then(argument("force", BoolArgumentType.bool())
|
|
||||||
.executes(ApplyJoinAnimCommand::tryJoinAnimation)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(literal("accept")
|
|
||||||
.then(argument("player", EntityArgument.player())
|
|
||||||
.executes(ApplyJoinAnimCommand::acceptJoinAnimation)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int tryJoinAnimation(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
boolean force = false;
|
|
||||||
try {force = BoolArgumentType.getBool(context, "force");}
|
|
||||||
catch (Exception ignored) {}
|
|
||||||
ServerPlayer target = EntityArgument.getPlayer(context, "target");
|
|
||||||
ServerPlayer player;
|
|
||||||
try {player = EntityArgument.getPlayer(context, "player");}
|
|
||||||
catch (Exception e) { player = source.getPlayerOrException(); }
|
|
||||||
|
|
||||||
Entity vehicle = target.getVehicle();
|
|
||||||
if(!(vehicle instanceof AnimationRideEntity rideEntity) || !rideEntity.canAddPassenger(player)) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.WITHOUT_ANIMATION_RIDE_ENTITY.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//cooldown
|
|
||||||
Long lastApplied = lastAppliedMap.getOrDefault(player.getUUID(), null);
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
int applyCooldown = ModConfigs.Server.applyCooldown.get() * 1000;
|
|
||||||
if(!(lastApplied == null || now - lastApplied > applyCooldown)) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_COOLDOWN.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lastAppliedMap.put(player.getUUID(), now);
|
|
||||||
|
|
||||||
UUID rideEntityUUID = rideEntity.getUUID();
|
|
||||||
Map<UUID, ApplyRecord> applyRecordMap = applies.getOrDefault(rideEntityUUID, new HashMap<>());
|
|
||||||
applyRecordMap.put(player.getUUID(), new ApplyRecord(now, force));
|
|
||||||
applies.put(rideEntityUUID, applyRecordMap);
|
|
||||||
|
|
||||||
//click event
|
|
||||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
|
||||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim joinApply accept " + player.getName().getString())
|
|
||||||
).withUnderlined(true);
|
|
||||||
|
|
||||||
//send message to all participants
|
|
||||||
for (Entity passenger : rideEntity.getPassengers()) {
|
|
||||||
passenger.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.APPLIED_JOIN_MESSAGE.getKey(),
|
|
||||||
player.getName().copy()
|
|
||||||
).append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
|
||||||
).setStyle(pStyle)));
|
|
||||||
}
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.APPLY_JOIN_MESSAGE.getKey()
|
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int acceptJoinAnimation(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
ServerPlayer target = source.getPlayerOrException();
|
|
||||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
|
||||||
if(!(target.getVehicle() instanceof AnimationRideEntity rideEntity) || !rideEntity.canAddPassenger(player)) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.WITHOUT_ANIMATION_RIDE_ENTITY.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<UUID, ApplyRecord> applyRecordMap = applies.getOrDefault(rideEntity.getUUID(), null);
|
|
||||||
if(applyRecordMap == null) throw new Exception();
|
|
||||||
ApplyRecord applyRecord = applyRecordMap.getOrDefault(player.getUUID(), null);
|
|
||||||
|
|
||||||
//test if expired
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
Integer applyDuration = ModConfigs.Server.applyDuration.get();
|
|
||||||
if(now - applyRecord.time > applyDuration * 1000 || applyDuration == 0) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_APPLY_EXPIRED.getKey(),
|
|
||||||
applyDuration
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.APPLY_EXPIRED.getKey(),
|
|
||||||
target.getName().copy(),
|
|
||||||
applyDuration
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//test if in range
|
|
||||||
Integer applyDistance = ModConfigs.Server.applyDistance.get();
|
|
||||||
if(player.position().distanceToSqr(rideEntity.position()) > applyDistance * applyDistance || applyDistance == 0) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_APPLY_TOO_FAR.getKey(),
|
|
||||||
applyDistance
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.APPLY_TOO_FAR.getKey(),
|
|
||||||
target.getName().copy(),
|
|
||||||
applyDistance
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
applyRecordMap.remove(player.getUUID());
|
|
||||||
applies.put(player.getUUID(), applyRecordMap);
|
|
||||||
|
|
||||||
//define message
|
|
||||||
MutableComponent successMessage = Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_APPLY_SUCCESS.getKey(),
|
|
||||||
target.getName().copy(),
|
|
||||||
player.getName().copy()
|
|
||||||
).withStyle(ChatFormatting.GREEN);
|
|
||||||
|
|
||||||
//play
|
|
||||||
AnimationUtils.joinAnimation(player, target, applyRecord.isForce);
|
|
||||||
|
|
||||||
//send message
|
|
||||||
source.sendSuccess(() -> successMessage, true);
|
|
||||||
for (Entity passenger : rideEntity.getPassengers()) {
|
|
||||||
if(!passenger.getUUID().equals(target.getUUID()) && !passenger.getUUID().equals(player.getUUID())) {
|
|
||||||
passenger.sendSystemMessage(successMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.APPLY_SUCCESS.getKey(),
|
|
||||||
target.getName().copy()
|
|
||||||
).withStyle(ChatFormatting.GREEN));
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,178 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.command;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
|
||||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.commands.arguments.EntityArgument;
|
|
||||||
import net.minecraft.network.chat.ClickEvent;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.Style;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
public class CombineAnimCommand {
|
|
||||||
private static final Map<UUID, Long> lastInvitedMap = new HashMap<>();
|
|
||||||
record InviteRecord(long time, ResourceLocation layer, ResourceLocation animation, boolean isForce){}
|
|
||||||
private static final Map<UUID, Map<UUID, InviteRecord>> invites = new HashMap<>();
|
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
|
||||||
animCommand.then(literal("invite")
|
|
||||||
.then(argument("player", EntityArgument.player())
|
|
||||||
.then(argument("layer", AnimationLayerArgument.layer())
|
|
||||||
.then(argument("anim", AnimationArgument.animation())
|
|
||||||
.executes(CombineAnimCommand::invite)
|
|
||||||
.then(argument("force", BoolArgumentType.bool())
|
|
||||||
.executes(CombineAnimCommand::invite)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(literal("accept")
|
|
||||||
.then(argument("player", EntityArgument.player())
|
|
||||||
.executes(CombineAnimCommand::acceptInvite)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int invite(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
//get info
|
|
||||||
boolean force = false;
|
|
||||||
try {force = BoolArgumentType.getBool(context, "force");}
|
|
||||||
catch (Exception ignored) {}
|
|
||||||
ServerPlayer player = source.getPlayerOrException();
|
|
||||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
|
||||||
|
|
||||||
//cooldown
|
|
||||||
Long lastInvited = lastInvitedMap.getOrDefault(player.getUUID(), null);
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
int inviteCooldown = ModConfigs.Server.inviteCooldown.get() * 1000;
|
|
||||||
if(!(lastInvited == null || now - lastInvited > inviteCooldown)) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_COOLDOWN.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lastInvitedMap.put(player.getUUID(), now);
|
|
||||||
|
|
||||||
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
|
||||||
String animString = AnimationArgument.getAnimation(context, "anim");
|
|
||||||
ResourceLocation layer = new ResourceLocation(layerString);
|
|
||||||
ResourceLocation anim = new ResourceLocation(animString);
|
|
||||||
|
|
||||||
//test info present
|
|
||||||
boolean animationPresent = AnimationUtils.isAnimationPresent(anim);
|
|
||||||
boolean animationLayerPresent = AnimationUtils.isAnimationLayerPresent(layer);
|
|
||||||
if(!animationLayerPresent || !animationPresent) throw new Exception();
|
|
||||||
|
|
||||||
//update static cache
|
|
||||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), new HashMap<>());
|
|
||||||
inviteRecordMap.put(target.getUUID(), new InviteRecord(System.currentTimeMillis(), layer, anim, force));
|
|
||||||
invites.put(player.getUUID(), inviteRecordMap);
|
|
||||||
|
|
||||||
//click event
|
|
||||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
|
||||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim invite accept " + player.getName().getString())
|
|
||||||
).withUnderlined(true);
|
|
||||||
//send message
|
|
||||||
target.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.INVITED_MESSAGE.getKey(),
|
|
||||||
player.getName().copy(),
|
|
||||||
anim.toString()
|
|
||||||
).append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
|
||||||
).setStyle(pStyle)));
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.INVITE_MESSAGE.getKey()
|
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int acceptInvite(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
ServerPlayer target = source.getPlayerOrException();
|
|
||||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
|
||||||
|
|
||||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), null);
|
|
||||||
if(inviteRecordMap == null) throw new Exception();
|
|
||||||
InviteRecord inviteRecord = inviteRecordMap.getOrDefault(target.getUUID(), null);
|
|
||||||
if(inviteRecord == null) throw new Exception();
|
|
||||||
|
|
||||||
//test if expired
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
Integer inviteDuration = ModConfigs.Server.inviteDuration.get();
|
|
||||||
if(now - inviteRecord.time > inviteDuration * 1000 || inviteDuration == 0) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_INVITE_EXPIRED.getKey(),
|
|
||||||
inviteDuration
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.INVITE_EXPIRED.getKey(),
|
|
||||||
target.getName().copy(),
|
|
||||||
inviteDuration
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//test if in range
|
|
||||||
Integer inviteDistance = ModConfigs.Server.inviteDistance.get();
|
|
||||||
if(player.position().distanceToSqr(target.position()) > inviteDistance * inviteDistance || inviteDistance == 0) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_INVITE_TOO_FAR.getKey(),
|
|
||||||
inviteDistance
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.INVITE_TOO_FAR.getKey(),
|
|
||||||
target.getName().copy(),
|
|
||||||
inviteDistance
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
inviteRecordMap.remove(target.getUUID());
|
|
||||||
invites.put(player.getUUID(), inviteRecordMap);
|
|
||||||
|
|
||||||
//play animation
|
|
||||||
AnimationUtils.startAnimationTogether(player, inviteRecord.layer, inviteRecord.animation, inviteRecord.isForce, target);
|
|
||||||
|
|
||||||
//send message
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_INVITE_SUCCESS.getKey()
|
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.INVITE_SUCCESS.getKey(),
|
|
||||||
target.getName().copy()
|
|
||||||
).withStyle(ChatFormatting.GREEN));
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,141 @@
|
||||||
|
package com.linearpast.sccore.animation.command;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||||
|
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||||
|
import com.linearpast.sccore.animation.command.exception.ApiBackException;
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.HelperGetterFromAnimation;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IHelperGetter;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.arguments.EntityArgument;
|
||||||
|
import net.minecraft.network.chat.ClickEvent;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.Commands.argument;
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
|
public class InviteCommand {
|
||||||
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||||
|
animCommand.then(literal("invite")
|
||||||
|
.then(argument("players", EntityArgument.players())
|
||||||
|
.then(argument("layer", AnimationLayerArgument.layer())
|
||||||
|
.then(argument("anim", AnimationArgument.animation())
|
||||||
|
.executes(InviteCommand::invite)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(literal("accept")
|
||||||
|
.then(argument("player", EntityArgument.player())
|
||||||
|
.executes(InviteCommand::acceptInvite)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int invite(CommandContext<CommandSourceStack> context) {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
try {
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
Collection<ServerPlayer> players = EntityArgument.getPlayers(context, "players");
|
||||||
|
|
||||||
|
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
||||||
|
String animString = AnimationArgument.getAnimation(context, "anim");
|
||||||
|
ResourceLocation layer = new ResourceLocation(layerString);
|
||||||
|
ResourceLocation anim = new ResourceLocation(animString);
|
||||||
|
|
||||||
|
//test info present
|
||||||
|
IAnimationHelper<?, ?> helper = HelperGetterFromAnimation.create(anim).getHelper();
|
||||||
|
if (helper == null) throw new ApiBackException(ApiBack.RESOURCE_NOT_FOUND);
|
||||||
|
AnimationData animationData;
|
||||||
|
if(helper.isAnimationPresent(anim)) animationData = helper.getAnimation(anim);
|
||||||
|
else animationData = RawAnimationData.create(anim);
|
||||||
|
|
||||||
|
List<UUID> targets = players.stream().map(Entity::getUUID).toList();
|
||||||
|
ApiBack back = helper.invite(player, layer, animationData, targets);
|
||||||
|
if(back == ApiBack.COOLDOWN) {
|
||||||
|
int cooldown = ModConfigs.Server.inviteCooldown.get();
|
||||||
|
throw ApiBackException.withCooldown(cooldown);
|
||||||
|
}
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
|
//click event
|
||||||
|
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
||||||
|
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim invite accept " + player.getName().getString())
|
||||||
|
).withUnderlined(true);
|
||||||
|
//send message
|
||||||
|
for (ServerPlayer target : players) {
|
||||||
|
target.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.INVITED_MESSAGE.getKey(),
|
||||||
|
player.getName().copy(),
|
||||||
|
anim.toString()
|
||||||
|
).append(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
||||||
|
).setStyle(pStyle)));
|
||||||
|
}
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.INVITE_MESSAGE.getKey()
|
||||||
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
return 1;
|
||||||
|
} catch (ApiBackException e) {
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
|
} catch (Exception e) {
|
||||||
|
source.sendFailure(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int acceptInvite(CommandContext<CommandSourceStack> context) {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
try {
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
ServerPlayer inviter = EntityArgument.getPlayer(context, "player");
|
||||||
|
|
||||||
|
//play animation
|
||||||
|
ApiBack back = ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
for (IAnimationHelper<?, ?> helper : IHelperGetter.HELPERS) {
|
||||||
|
back = helper.acceptInvite(player, inviter);
|
||||||
|
if(back == ApiBack.SUCCESS) break;
|
||||||
|
}
|
||||||
|
if(back == ApiBack.OUT_RANGE) throw ApiBackException.withOutRange(ModConfigs.Server.inviteValidDistance.get());
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
|
//send message
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ACCEPT_INVITE_SUCCESS.getKey()
|
||||||
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
inviter.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.INVITE_SUCCESS.getKey(),
|
||||||
|
player.getName().copy()
|
||||||
|
).withStyle(ChatFormatting.GREEN));
|
||||||
|
return 1;
|
||||||
|
} catch (ApiBackException e) {
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
|
} catch (Exception e) {
|
||||||
|
source.sendFailure(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
package com.linearpast.sccore.animation.command;
|
package com.linearpast.sccore.animation.command;
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.helper.JsonHelper;
|
||||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
|
||||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
|
@ -13,24 +10,19 @@ import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.network.chat.MutableComponent;
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.world.level.storage.LevelResource;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
import static net.minecraft.commands.Commands.argument;
|
||||||
import static net.minecraft.commands.Commands.literal;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
public class GenerateJsonCommand {
|
public class JsonCommand {
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||||
animCommand.then(literal("json").requires(cs -> cs.hasPermission(2))
|
animCommand.then(literal("json").requires(cs -> cs.hasPermission(2))
|
||||||
.then(literal("clearFile").executes(GenerateJsonCommand::clearJson))
|
.then(literal("clearFile").executes(JsonCommand::clearJson))
|
||||||
.then(literal("generate")
|
.then(literal("generate")
|
||||||
.then(literal("anim")
|
.then(literal("anim")
|
||||||
.then(literal("example").executes(GenerateJsonCommand::generateExample))
|
.then(literal("example").executes(JsonCommand::generateExample))
|
||||||
.executes(context -> generateJson(context, false, false))
|
.executes(context -> generateJson(context, false, false))
|
||||||
.then(argument("reset", BoolArgumentType.bool())
|
.then(argument("reset", BoolArgumentType.bool())
|
||||||
.executes(context ->
|
.executes(context ->
|
||||||
|
|
@ -50,60 +42,25 @@ public class GenerateJsonCommand {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//clear path, remove file.
|
|
||||||
private static void clearPath(Path dir) throws IOException {
|
|
||||||
if (!Files.exists(dir)) return;
|
|
||||||
try (var pathStream = Files.walk(dir)) {
|
|
||||||
pathStream.sorted(Comparator.reverseOrder()).forEach(path -> {
|
|
||||||
try {
|
|
||||||
Files.delete(path);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (RuntimeException ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int generateJson(CommandContext<CommandSourceStack> context, boolean isLayer, boolean isReset) {
|
private static int generateJson(CommandContext<CommandSourceStack> context, boolean isLayer, boolean isReset) {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
try {
|
try {
|
||||||
//get animation path
|
|
||||||
Path animationPath = getAnimationPath(source);
|
|
||||||
if (!Files.exists(animationPath)) {
|
|
||||||
try {Files.createDirectories(animationPath);}
|
|
||||||
catch (IOException e) { throw new RuntimeException(e); }
|
|
||||||
}
|
|
||||||
if(isReset) clearPath(animationPath);
|
|
||||||
|
|
||||||
//generate json layer or animation
|
|
||||||
if(isLayer) {
|
|
||||||
//generate
|
//generate
|
||||||
Path path = AnimLayerJson.Writer.syntaxImmediately(animationPath);
|
JsonHelper helper = JsonHelper.getHelper(source.getServer());
|
||||||
//send message
|
Path path = helper.generateJson(isLayer, isReset);
|
||||||
MutableComponent component = Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
if(path == null) throw new Exception();
|
||||||
"layer", "Server"
|
MutableComponent component;
|
||||||
).withStyle(ChatFormatting.GREEN);
|
String key = ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey();
|
||||||
component.append(Component.translatable(
|
if(isLayer) component = Component.translatable(key, "layer", "Server");
|
||||||
|
else component = Component.translatable(key, "anim", "Server");
|
||||||
|
|
||||||
|
component.withStyle(ChatFormatting.GREEN).append(Component.translatable(
|
||||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||||
path.toString()
|
path.toString()
|
||||||
));
|
));
|
||||||
|
|
||||||
source.sendSuccess(() -> component, true);
|
source.sendSuccess(() -> component, true);
|
||||||
} else {
|
|
||||||
//generate
|
|
||||||
for (Animation value : AnimationRegistry.getAnimations().values()) {
|
|
||||||
AnimJson.Writer.stream(animationPath, value).syntax();
|
|
||||||
}
|
|
||||||
//send message
|
|
||||||
MutableComponent component = Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
|
||||||
"anim", "Server"
|
|
||||||
).withStyle(ChatFormatting.GREEN);
|
|
||||||
component.append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
|
||||||
animationPath.toString()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
source.sendFailure(Component.translatable(
|
source.sendFailure(Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
|
@ -118,8 +75,7 @@ public class GenerateJsonCommand {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
try {
|
try {
|
||||||
//clear path
|
//clear path
|
||||||
Path animationPath = getAnimationPath(source);
|
JsonHelper.getHelper(source.getServer()).clearPath();
|
||||||
clearPath(animationPath);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
source.sendFailure(Component.translatable(
|
source.sendFailure(Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
|
@ -134,8 +90,10 @@ public class GenerateJsonCommand {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
try {
|
try {
|
||||||
//generate
|
//generate
|
||||||
Path animationPath = getAnimationPath(source);
|
JsonHelper helper = JsonHelper.getHelper(source.getServer());
|
||||||
Path path = AnimJson.Writer.syntaxExample(animationPath);
|
Path path = helper.generateExample();
|
||||||
|
if(path == null) throw new Exception();
|
||||||
|
|
||||||
//send message
|
//send message
|
||||||
MutableComponent component = Component.translatable(
|
MutableComponent component = Component.translatable(
|
||||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||||
|
|
@ -154,15 +112,4 @@ public class GenerateJsonCommand {
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get animation path
|
|
||||||
* @param source command source
|
|
||||||
* @return path
|
|
||||||
*/
|
|
||||||
private static Path getAnimationPath(CommandSourceStack source) {
|
|
||||||
MinecraftServer server = source.getServer();
|
|
||||||
Path dataPackPath = server.getWorldPath(LevelResource.DATAPACK_DIR);
|
|
||||||
return dataPackPath.resolve("animation");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.linearpast.sccore.animation.command;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
|
public class ListServerCommand {
|
||||||
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||||
|
animCommand.then(literal("list")
|
||||||
|
.then(literal("layers").executes(ListServerCommand::listLayers))
|
||||||
|
.then(literal("serverAnimations")
|
||||||
|
.executes(ListServerCommand::listAnimations)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int listAnimations(CommandContext<CommandSourceStack> context) {
|
||||||
|
try {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
List<ResourceLocation> list = AnimationRegistry.getAnimations().keySet().stream().toList();
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.LIST_ANIMATION_RESOURCE.getKey(),
|
||||||
|
"Server", "Animations", getString(list)
|
||||||
|
), false);
|
||||||
|
return 1;
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int listLayers(CommandContext<CommandSourceStack> context) {
|
||||||
|
try {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
List<ResourceLocation> list = AnimationRegistry.getLayers().keySet().stream().toList();
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.LIST_ANIMATION_RESOURCE.getKey(),
|
||||||
|
"Server", "Layers", getString(list)
|
||||||
|
), false);
|
||||||
|
return 1;
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Component getString(List<ResourceLocation> list) {
|
||||||
|
MutableComponent component = Component.empty();
|
||||||
|
Random random = new Random(System.currentTimeMillis());
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
component.append(Component.literal(list.get(i).toString()).withStyle(randomColor(random)));
|
||||||
|
if(i < list.size()-1){
|
||||||
|
component.append(", ").withStyle(ChatFormatting.WHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
component.append(".").withStyle(Style.EMPTY.withColor(ChatFormatting.RED));
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ChatFormatting randomColor(Random random){
|
||||||
|
int i = random.nextInt(14) + 1;
|
||||||
|
ChatFormatting byId = ChatFormatting.getById(i);
|
||||||
|
return byId == null ? ChatFormatting.WHITE : byId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
package com.linearpast.sccore.animation.command;
|
package com.linearpast.sccore.animation.command;
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
import com.linearpast.sccore.animation.command.exception.ApiBackException;
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.*;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
import net.minecraft.ChatFormatting;
|
import net.minecraft.ChatFormatting;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
|
@ -18,6 +19,7 @@ import net.minecraft.network.chat.MutableComponent;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
@ -25,9 +27,13 @@ import java.util.Set;
|
||||||
import static net.minecraft.commands.Commands.argument;
|
import static net.minecraft.commands.Commands.argument;
|
||||||
import static net.minecraft.commands.Commands.literal;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
public class PlayAnimCommand {
|
public class PlayCommand {
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
||||||
RequiredArgumentBuilder<CommandSourceStack, String> animCommandParam = argument("layer", AnimationLayerArgument.layer())
|
animCommand
|
||||||
|
.then(literal("play")
|
||||||
|
.then(argument("players", EntityArgument.players())
|
||||||
|
.requires(cs -> cs.hasPermission(2))
|
||||||
|
.then(argument("layer", AnimationLayerArgument.layer())
|
||||||
.then(argument("animation", AnimationArgument.animation())
|
.then(argument("animation", AnimationArgument.animation())
|
||||||
.executes(context -> playAnimation(context, false))
|
.executes(context -> playAnimation(context, false))
|
||||||
.then(argument("withRide", BoolArgumentType.bool())
|
.then(argument("withRide", BoolArgumentType.bool())
|
||||||
|
|
@ -40,26 +46,33 @@ public class PlayAnimCommand {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
animCommand
|
)
|
||||||
.then(literal("playSelf")
|
)
|
||||||
.then(animCommandParam))
|
.then(literal("self")
|
||||||
.then(literal("play")
|
.then(argument("layer", AnimationLayerArgument.layer())
|
||||||
.then(argument("players", EntityArgument.players())
|
.then(argument("animation", AnimationArgument.animation())
|
||||||
.requires(cs -> cs.hasPermission(2))
|
.executes(context -> playAnimation(context, false))
|
||||||
.then(animCommandParam)
|
.then(argument("withRide", BoolArgumentType.bool())
|
||||||
|
.executes(context -> playAnimation(
|
||||||
|
context, BoolArgumentType.getBool(context, "withRide")
|
||||||
))
|
))
|
||||||
.then(literal("remove")
|
)
|
||||||
.executes(PlayAnimCommand::clearAnimation)
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.then(literal("clear")
|
||||||
|
.executes(PlayCommand::clearAnimation)
|
||||||
.then(argument("players", EntityArgument.players())
|
.then(argument("players", EntityArgument.players())
|
||||||
.requires(cs -> cs.hasPermission(2))
|
.requires(cs -> cs.hasPermission(2))
|
||||||
.executes(PlayAnimCommand::clearAnimation)
|
.executes(PlayCommand::clearAnimation)
|
||||||
.then(argument("layer", AnimationLayerArgument.layer())
|
.then(argument("layer", AnimationLayerArgument.layer())
|
||||||
.executes(PlayAnimCommand::removeAnimation)
|
.executes(PlayCommand::removeAnimation)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.then(argument("layer", AnimationLayerArgument.layer())
|
.then(argument("layer", AnimationLayerArgument.layer())
|
||||||
.executes(PlayAnimCommand::removeAnimation)
|
.executes(PlayCommand::removeAnimation)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -67,56 +80,43 @@ public class PlayAnimCommand {
|
||||||
private static int playAnimation(CommandContext<CommandSourceStack> context, boolean withRide) {
|
private static int playAnimation(CommandContext<CommandSourceStack> context, boolean withRide) {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
try {
|
try {
|
||||||
Collection<ServerPlayer> players = null;
|
Collection<ServerPlayer> targets = new ArrayList<>();
|
||||||
ServerPlayer player = null;
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
try {players = EntityArgument.getPlayers(context, "players");}
|
try { targets.addAll(EntityArgument.getPlayers(context, "players"));}
|
||||||
catch (Exception ignored) { player = source.getPlayerOrException(); }
|
catch (Exception ignored) {}
|
||||||
String animation = AnimationArgument.getAnimation(context, "animation");
|
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
||||||
String layer = AnimationLayerArgument.getLayer(context, "layer");
|
String animString = AnimationArgument.getAnimation(context, "animation");
|
||||||
ResourceLocation layerLocation = new ResourceLocation(layer);
|
ResourceLocation layer = new ResourceLocation(layerString);
|
||||||
ResourceLocation animLocation = new ResourceLocation(animation);
|
ResourceLocation anim = new ResourceLocation(animString);
|
||||||
boolean animationPresent = AnimationUtils.isAnimationPresent(animLocation);
|
|
||||||
boolean layerPresent = AnimationUtils.isAnimationLayerPresent(layerLocation);
|
|
||||||
if(!animationPresent) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_NOT_PRESENT.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(!layerPresent) {
|
|
||||||
source.sendFailure(Component.literal(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_LAYER_NOT_PRESENT.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//play with players
|
//play with players
|
||||||
if(players != null) {
|
IAnimationHelper<?, ?> helper = HelperGetterFromAnimation.create(anim).getHelper();
|
||||||
Set<ServerPlayer> playerSet = Set.copyOf(players);
|
if (helper == null) throw new ApiBackException(ApiBack.RESOURCE_NOT_FOUND);
|
||||||
Collection<ServerPlayer> finalPlayers = players;
|
AnimationData animationData = helper.getAnimation(anim);
|
||||||
|
if(animationData == null) throw new ApiBackException(ApiBack.RESOURCE_NOT_FOUND);
|
||||||
|
if(!targets.isEmpty()) {
|
||||||
|
Set<ServerPlayer> playerSet = Set.copyOf(targets);
|
||||||
playerSet.forEach(p -> {
|
playerSet.forEach(p -> {
|
||||||
if(withRide) {
|
if(withRide) {
|
||||||
boolean forced = false;
|
boolean forced = false;
|
||||||
try { forced = BoolArgumentType.getBool(context, "forced");}
|
try { forced = BoolArgumentType.getBool(context, "forced");}
|
||||||
catch (Exception ignored) {}
|
catch (Exception ignored) {}
|
||||||
if(AnimationUtils.playAnimationWithRide(p, layerLocation, animLocation, forced)) {
|
ApiBack back = helper.playAnimationWithRide(p, layer, animationData, forced);
|
||||||
finalPlayers.remove(p);
|
if(back == ApiBack.SUCCESS) targets.remove(p);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (AnimationUtils.playAnimation(p, layerLocation, animLocation)) {
|
ApiBack back = helper.playAnimation(p, layer, animationData);
|
||||||
finalPlayers.remove(p);
|
if (back == ApiBack.SUCCESS) targets.remove(p);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
int successNum = playerSet.size() - players.size();
|
int successNum = playerSet.size() - targets.size();
|
||||||
if(successNum > 0) {
|
if(successNum > 0) {
|
||||||
source.sendSuccess(() -> Component.translatable(
|
source.sendSuccess(() -> Component.translatable(
|
||||||
ModLang.TranslatableMessage.PLAY_ANIMATION_SUCCESS.getKey(),
|
ModLang.TranslatableMessage.PLAY_ANIMATION_SUCCESS.getKey(),
|
||||||
successNum
|
successNum
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
}
|
}
|
||||||
List<ServerPlayer> list = players.stream().toList();
|
List<ServerPlayer> list = targets.stream().toList();
|
||||||
if(!list.isEmpty()) {
|
if(!list.isEmpty()) {
|
||||||
MutableComponent failPlayers = Component.literal("");
|
MutableComponent failPlayers = Component.literal("");
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
|
@ -131,70 +131,56 @@ public class PlayAnimCommand {
|
||||||
failPlayers
|
failPlayers
|
||||||
).withStyle(ChatFormatting.RED));
|
).withStyle(ChatFormatting.RED));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//play with self
|
|
||||||
if(player != null) {
|
|
||||||
if(withRide) {
|
|
||||||
boolean forced = false;
|
|
||||||
try { forced = BoolArgumentType.getBool(context, "forced");}
|
|
||||||
catch (Exception ignored) {}
|
|
||||||
AnimationUtils.playAnimationWithRide(player, layerLocation, animLocation, forced);
|
|
||||||
} else {
|
} else {
|
||||||
AnimationUtils.playAnimation(player, layerLocation, animLocation);
|
//play with self
|
||||||
}
|
ApiBack back;
|
||||||
|
RawAnimationHelper instance = RawAnimationHelper.INSTANCE;
|
||||||
|
if(withRide) back = instance.playAnimationWithRide(player, layer, animationData, false);
|
||||||
|
else back = instance.playAnimation(player, layer, animationData);
|
||||||
|
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
source.sendSuccess(() -> Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
source.sendFailure(Component.translatable(
|
source.sendFailure(Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
).withStyle(ChatFormatting.RED));
|
).withStyle(ChatFormatting.RED));
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int removeAnimation(CommandContext<CommandSourceStack> context) {
|
private static int removeAnimation(CommandContext<CommandSourceStack> context) {
|
||||||
CommandSourceStack source = context.getSource();
|
CommandSourceStack source = context.getSource();
|
||||||
try {
|
try {
|
||||||
Collection<ServerPlayer> players = null;
|
Collection<ServerPlayer> targets = new ArrayList<>();
|
||||||
ServerPlayer player = null;
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
try {players = EntityArgument.getPlayers(context, "players");}
|
try { targets.addAll(EntityArgument.getPlayers(context, "players"));}
|
||||||
catch (Exception ignored) { player = source.getPlayerOrException(); }
|
catch (Exception ignored) {}
|
||||||
String layer = AnimationLayerArgument.getLayer(context, "layer");
|
String layer = AnimationLayerArgument.getLayer(context, "layer");
|
||||||
ResourceLocation layerLocation = new ResourceLocation(layer);
|
ResourceLocation layerLocation = new ResourceLocation(layer);
|
||||||
boolean layerPresent = AnimationUtils.isAnimationLayerPresent(layerLocation);
|
|
||||||
if(!layerPresent) {
|
|
||||||
source.sendFailure(Component.literal(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_LAYER_NOT_PRESENT.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//remove with players
|
//remove with players
|
||||||
if(players != null) {
|
AnimationHelper instance = AnimationHelper.INSTANCE;
|
||||||
Set<ServerPlayer> playerSet = Set.copyOf(players);
|
if(!targets.isEmpty()) {
|
||||||
Collection<ServerPlayer> finalPlayers = players;
|
Set<ServerPlayer> playerSet = Set.copyOf(targets);
|
||||||
playerSet.forEach(p -> {
|
playerSet.forEach(p -> {
|
||||||
if(p.getVehicle() instanceof AnimationRideEntity rideEntity && rideEntity.getLayer().equals(layerLocation)) {
|
ApiBack back = instance.removeAnimation(p, layerLocation);
|
||||||
p.unRide();
|
if (back == ApiBack.SUCCESS) targets.remove(p);
|
||||||
finalPlayers.remove(p);
|
|
||||||
}
|
|
||||||
if (AnimationUtils.removeAnimation(p, layerLocation)) {
|
|
||||||
finalPlayers.remove(p);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
int successNum = playerSet.size() - players.size();
|
int successNum = playerSet.size() - targets.size();
|
||||||
if(successNum > 0) {
|
if(successNum > 0) {
|
||||||
source.sendSuccess(() -> Component.translatable(
|
source.sendSuccess(() -> Component.translatable(
|
||||||
ModLang.TranslatableMessage.REMOVE_ANIMATION_SUCCESS.getKey(),
|
ModLang.TranslatableMessage.REMOVE_ANIMATION_SUCCESS.getKey(),
|
||||||
successNum
|
successNum
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
}
|
}
|
||||||
List<ServerPlayer> list = players.stream().toList();
|
List<ServerPlayer> list = targets.stream().toList();
|
||||||
if(!list.isEmpty()) {
|
if(!list.isEmpty()) {
|
||||||
MutableComponent failPlayers = Component.literal("");
|
MutableComponent failPlayers = Component.literal("");
|
||||||
for (int i = 0; i < list.size(); i++) {
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
|
@ -209,26 +195,24 @@ public class PlayAnimCommand {
|
||||||
failPlayers
|
failPlayers
|
||||||
).withStyle(ChatFormatting.RED));
|
).withStyle(ChatFormatting.RED));
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
ApiBack back = instance.removeAnimation(player, layerLocation);
|
||||||
|
if (back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
//remove with self
|
|
||||||
if(player != null) {
|
|
||||||
if(player.getVehicle() instanceof AnimationRideEntity rideEntity && rideEntity.getLayer().equals(layerLocation)) {
|
|
||||||
player.unRide();
|
|
||||||
}
|
|
||||||
AnimationUtils.removeAnimation(player, layerLocation);
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
source.sendSuccess(() -> Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
}
|
}
|
||||||
|
return 1;
|
||||||
|
} catch (ApiBackException e){
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
source.sendFailure(Component.translatable(
|
source.sendFailure(Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
).withStyle(ChatFormatting.RED));
|
).withStyle(ChatFormatting.RED));
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int clearAnimation(CommandContext<CommandSourceStack> context) {
|
private static int clearAnimation(CommandContext<CommandSourceStack> context) {
|
||||||
|
|
@ -237,22 +221,23 @@ public class PlayAnimCommand {
|
||||||
Collection<ServerPlayer> players;
|
Collection<ServerPlayer> players;
|
||||||
try {players = EntityArgument.getPlayers(context, "players");}
|
try {players = EntityArgument.getPlayers(context, "players");}
|
||||||
catch (Exception ignored) { players = Set.of(source.getPlayerOrException()); }
|
catch (Exception ignored) { players = Set.of(source.getPlayerOrException()); }
|
||||||
Set.copyOf(players).forEach(player -> {
|
Set.copyOf(players).forEach(player -> IHelperGetter.HELPERS.forEach(
|
||||||
if(player.getVehicle() instanceof AnimationRideEntity) {
|
helper -> {
|
||||||
player.unRide();
|
helper.clearAnimations(player);
|
||||||
|
helper.detachAnimation(player);
|
||||||
}
|
}
|
||||||
AnimationUtils.clearAnimation(player);
|
));
|
||||||
});
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
source.sendSuccess(() -> Component.translatable(
|
||||||
ModLang.TranslatableMessage.CLEAR_ANIMATIONS.getKey()
|
ModLang.TranslatableMessage.CLEAR_ANIMATIONS.getKey()
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
return 1;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
source.sendFailure(Component.translatable(
|
source.sendFailure(Component.translatable(
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
).withStyle(ChatFormatting.RED));
|
).withStyle(ChatFormatting.RED));
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.command;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
|
||||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.commands.arguments.EntityArgument;
|
|
||||||
import net.minecraft.network.chat.ClickEvent;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.Style;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request target player play animation.
|
|
||||||
*/
|
|
||||||
public class RequestAnimCommand {
|
|
||||||
private static final Map<UUID, Long> lastRequestedMap = new HashMap<>();
|
|
||||||
record InviteRecord(long time, ResourceLocation layer, ResourceLocation animation, boolean withRide, boolean isForce) {}
|
|
||||||
private static final Map<UUID, Map<UUID, InviteRecord>> invites = new HashMap<>();
|
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
|
||||||
animCommand.then(literal("request")
|
|
||||||
.then(argument("player", EntityArgument.player()).then(
|
|
||||||
argument("layer", AnimationLayerArgument.layer())
|
|
||||||
.then(argument("animation", AnimationArgument.animation())
|
|
||||||
.requires(cs -> cs.hasPermission(2))
|
|
||||||
.executes(context -> invite(context, false))
|
|
||||||
.then(argument("withRide", BoolArgumentType.bool())
|
|
||||||
.executes(context -> invite(
|
|
||||||
context, BoolArgumentType.getBool(context, "withRide")
|
|
||||||
))
|
|
||||||
.then(argument("forced", BoolArgumentType.bool())
|
|
||||||
.executes(context -> invite(
|
|
||||||
context, BoolArgumentType.getBool(context, "withRide"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
))
|
|
||||||
.then(literal("accept")
|
|
||||||
.then(argument("player", EntityArgument.player())
|
|
||||||
.executes(RequestAnimCommand::accept)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int invite(CommandContext<CommandSourceStack> context, boolean withRide) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
//get info
|
|
||||||
boolean force = false;
|
|
||||||
try {
|
|
||||||
force = BoolArgumentType.getBool(context, "force");
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
ServerPlayer player = source.getPlayerOrException();
|
|
||||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
|
||||||
|
|
||||||
//cooldown
|
|
||||||
Long lastRequested = lastRequestedMap.getOrDefault(player.getUUID(), null);
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
int requestCooldown = ModConfigs.Server.requestCooldown.get() * 1000;
|
|
||||||
if(!(lastRequested == null || now - lastRequested > requestCooldown)) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_COOLDOWN.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
lastRequestedMap.put(player.getUUID(), now);
|
|
||||||
|
|
||||||
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
|
||||||
String animString = AnimationArgument.getAnimation(context, "animation");
|
|
||||||
ResourceLocation layer = new ResourceLocation(layerString);
|
|
||||||
ResourceLocation anim = new ResourceLocation(animString);
|
|
||||||
|
|
||||||
//test info present
|
|
||||||
boolean animationPresent = AnimationUtils.isAnimationPresent(anim);
|
|
||||||
boolean animationLayerPresent = AnimationUtils.isAnimationLayerPresent(layer);
|
|
||||||
if(!animationLayerPresent || !animationPresent) throw new Exception();
|
|
||||||
|
|
||||||
//update static cache
|
|
||||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), new HashMap<>());
|
|
||||||
inviteRecordMap.put(target.getUUID(), new InviteRecord(System.currentTimeMillis(), layer, anim, force, withRide));
|
|
||||||
invites.put(player.getUUID(), inviteRecordMap);
|
|
||||||
|
|
||||||
//click event
|
|
||||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
|
||||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim request accept " + player.getName().getString())
|
|
||||||
).withUnderlined(true);
|
|
||||||
|
|
||||||
//send message
|
|
||||||
target.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.REQUESTED_MESSAGE.getKey(),
|
|
||||||
player.getName().copy(),
|
|
||||||
anim.toString()
|
|
||||||
).append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
|
||||||
).setStyle(pStyle)));
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.REQUEST_MESSAGE.getKey()
|
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int accept(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
ServerPlayer target = source.getPlayerOrException();
|
|
||||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
|
||||||
|
|
||||||
//get request record and test
|
|
||||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), null);
|
|
||||||
if(inviteRecordMap == null) throw new Exception();
|
|
||||||
InviteRecord inviteRecord = inviteRecordMap.getOrDefault(target.getUUID(), null);
|
|
||||||
if(inviteRecord == null) throw new Exception();
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
Integer requestDuration = ModConfigs.Server.requestDuration.get();
|
|
||||||
|
|
||||||
//test if expired
|
|
||||||
if(now - inviteRecord.time > requestDuration * 1000 || requestDuration == 0) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_REQUEST_EXPIRED.getKey(),
|
|
||||||
requestDuration
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.REQUEST_EXPIRED.getKey(),
|
|
||||||
target.getName().copy(),
|
|
||||||
requestDuration
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
inviteRecordMap.remove(target.getUUID());
|
|
||||||
invites.put(player.getUUID(), inviteRecordMap);
|
|
||||||
boolean withRide = inviteRecord.withRide;
|
|
||||||
|
|
||||||
//play
|
|
||||||
if(withRide) {
|
|
||||||
AnimationUtils.playAnimationWithRide(target, inviteRecord.layer, inviteRecord.animation, inviteRecord.isForce);
|
|
||||||
}else {
|
|
||||||
AnimationUtils.playAnimation(target, inviteRecord.layer, inviteRecord.animation);
|
|
||||||
}
|
|
||||||
|
|
||||||
//send message
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ACCEPT_REQUEST_SUCCESS.getKey()
|
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
|
||||||
player.sendSystemMessage(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.REQUEST_SUCCESS.getKey(),
|
|
||||||
target.getName().copy()
|
|
||||||
).withStyle(ChatFormatting.GREEN));
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,140 @@
|
||||||
|
package com.linearpast.sccore.animation.command;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||||
|
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||||
|
import com.linearpast.sccore.animation.command.exception.ApiBackException;
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.HelperGetterFromAnimation;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IHelperGetter;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.commands.arguments.EntityArgument;
|
||||||
|
import net.minecraft.network.chat.ClickEvent;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.Commands.argument;
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request target player play animation.
|
||||||
|
*/
|
||||||
|
public class RequestCommand {
|
||||||
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||||
|
animCommand.then(literal("request")
|
||||||
|
.then(argument("player", EntityArgument.player()).then(
|
||||||
|
argument("layer", AnimationLayerArgument.layer())
|
||||||
|
.then(argument("animation", AnimationArgument.animation())
|
||||||
|
.requires(cs -> cs.hasPermission(2))
|
||||||
|
.executes(context -> request(context, false))
|
||||||
|
.then(argument("withRide", BoolArgumentType.bool())
|
||||||
|
.executes(context -> request(
|
||||||
|
context, BoolArgumentType.getBool(context, "withRide")
|
||||||
|
))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
.then(literal("acceptRequest")
|
||||||
|
.then(argument("player", EntityArgument.player())
|
||||||
|
.executes(RequestCommand::acceptRequest)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int request(CommandContext<CommandSourceStack> context, boolean withRide) {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
try {
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||||
|
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
||||||
|
String animString = AnimationArgument.getAnimation(context, "animation");
|
||||||
|
ResourceLocation layer = new ResourceLocation(layerString);
|
||||||
|
ResourceLocation anim = new ResourceLocation(animString);
|
||||||
|
|
||||||
|
IAnimationHelper<?, ?> helper = HelperGetterFromAnimation.create(anim).getHelper();
|
||||||
|
if (helper == null) throw new ApiBackException(ApiBack.RESOURCE_NOT_FOUND);
|
||||||
|
AnimationData animationData;
|
||||||
|
if(helper.isAnimationPresent(anim)) animationData = helper.getAnimation(anim);
|
||||||
|
else animationData = RawAnimationData.create(anim);
|
||||||
|
|
||||||
|
ApiBack back = helper.request(player, target, layer, animationData, withRide);
|
||||||
|
if(back == ApiBack.COOLDOWN) {
|
||||||
|
int cooldown = ModConfigs.Server.requestCooldown.get();
|
||||||
|
throw ApiBackException.withCooldown(cooldown);
|
||||||
|
}
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
|
//click event
|
||||||
|
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
||||||
|
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim request acceptRequest " + player.getName().getString())
|
||||||
|
).withUnderlined(true);
|
||||||
|
|
||||||
|
//send message
|
||||||
|
target.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.REQUESTED_MESSAGE.getKey(),
|
||||||
|
player.getName().copy(),
|
||||||
|
anim.toString()
|
||||||
|
).append(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
||||||
|
).setStyle(pStyle)));
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.REQUEST_MESSAGE.getKey()
|
||||||
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
return 1;
|
||||||
|
} catch (ApiBackException e) {
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
|
} catch (Exception e) {
|
||||||
|
source.sendFailure(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int acceptRequest(CommandContext<CommandSourceStack> context) {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
try {
|
||||||
|
ServerPlayer player = source.getPlayerOrException();
|
||||||
|
ServerPlayer requestor = EntityArgument.getPlayer(context, "requestor");
|
||||||
|
|
||||||
|
//play
|
||||||
|
ApiBack back = ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
for (IAnimationHelper<?, ?> helper : IHelperGetter.HELPERS) {
|
||||||
|
back = helper.acceptRequest(player, requestor);
|
||||||
|
if(back == ApiBack.SUCCESS) break;
|
||||||
|
}
|
||||||
|
if(back != ApiBack.SUCCESS) throw new ApiBackException(back);
|
||||||
|
|
||||||
|
//send message
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ACCEPT_REQUEST_SUCCESS.getKey()
|
||||||
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
requestor.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.REQUEST_SUCCESS.getKey(),
|
||||||
|
player.getName().copy()
|
||||||
|
).withStyle(ChatFormatting.GREEN));
|
||||||
|
return 1;
|
||||||
|
} catch (ApiBackException e) {
|
||||||
|
source.sendFailure(e.getCommandFailBack().withStyle(ChatFormatting.RED));
|
||||||
|
} catch (Exception e) {
|
||||||
|
source.sendFailure(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package com.linearpast.sccore.animation.command.argument;
|
package com.linearpast.sccore.animation.command.argument;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import com.linearpast.sccore.animation.register.RawAnimationRegistry;
|
||||||
import com.mojang.brigadier.StringReader;
|
import com.mojang.brigadier.StringReader;
|
||||||
import com.mojang.brigadier.arguments.ArgumentType;
|
import com.mojang.brigadier.arguments.ArgumentType;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
|
@ -13,6 +14,9 @@ import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.SharedSuggestionProvider;
|
import net.minecraft.commands.SharedSuggestionProvider;
|
||||||
import net.minecraft.network.chat.Component;
|
import net.minecraft.network.chat.Component;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.fml.DistExecutor;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
@ -28,13 +32,22 @@ public class AnimationArgument implements ArgumentType<String> {
|
||||||
animation -> Component.literal("Unknow animation : " + animation.toString())
|
animation -> Component.literal("Unknow animation : " + animation.toString())
|
||||||
);
|
);
|
||||||
|
|
||||||
private final Supplier<Set<String>> animationNames;
|
private static Supplier<Set<String>> animationNames;
|
||||||
public AnimationArgument() {
|
public AnimationArgument() {
|
||||||
this.animationNames = AnimationArgument::getAnimationNames;
|
resetAnimationNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetAnimationNames() {
|
||||||
|
Set<String> set = new HashSet<>(getAnimationNames());
|
||||||
|
Set<String> strings = DistExecutor.unsafeCallWhenOn(Dist.CLIENT, () ->
|
||||||
|
AnimationArgument::getAnimationNamesClient
|
||||||
|
);
|
||||||
|
if (strings != null && !strings.isEmpty()) set.addAll(strings);
|
||||||
|
animationNames = () -> set;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> getAnimationNames(){
|
private static Set<String> getAnimationNames(){
|
||||||
HashSet<String> set = new HashSet<>();
|
Set<String> set = new HashSet<>();
|
||||||
AnimationRegistry.getAnimations().forEach((key, value) -> {
|
AnimationRegistry.getAnimations().forEach((key, value) -> {
|
||||||
String name = value.getName();
|
String name = value.getName();
|
||||||
if(name != null && !set.contains(name)) {
|
if(name != null && !set.contains(name)) {
|
||||||
|
|
@ -44,13 +57,22 @@ public class AnimationArgument implements ArgumentType<String> {
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
private static Set<String> getAnimationNamesClient() {
|
||||||
|
Set<String> set = new HashSet<>();
|
||||||
|
RawAnimationRegistry.getAnimations().keySet().forEach(location ->
|
||||||
|
set.add(location.toString())
|
||||||
|
);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
public static AnimationArgument animation() {
|
public static AnimationArgument animation() {
|
||||||
return new AnimationArgument();
|
return new AnimationArgument();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static ResourceLocation getAnimationByName(String name) {
|
private static ResourceLocation getAnimationByName(String name) {
|
||||||
for (Animation animation : AnimationRegistry.getAnimations().values()) {
|
for (GenericAnimationData animation : AnimationRegistry.getAnimations().values()) {
|
||||||
if (Objects.equals(animation.getName(), name)) {
|
if (Objects.equals(animation.getName(), name)) {
|
||||||
return animation.getKey();
|
return animation.getKey();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.command.client;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
|
||||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
|
||||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
||||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.client.Minecraft;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.network.chat.ClickEvent;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.MutableComponent;
|
|
||||||
import net.minecraft.network.chat.Style;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.Comparator;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
public class GenerateJsonClientCommand {
|
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
|
||||||
animCommand.then(literal("jsonClient")
|
|
||||||
.then(argument("path", StringArgumentType.string())
|
|
||||||
.suggests((context, builder) -> {
|
|
||||||
try {
|
|
||||||
File gameDirectory = Minecraft.getInstance().gameDirectory;
|
|
||||||
Path animation = gameDirectory.toPath().resolve(SnowyCrescentCore.MODID).resolve("animation");
|
|
||||||
if(!animation.toFile().exists()) {
|
|
||||||
Files.createDirectories(animation);
|
|
||||||
}
|
|
||||||
String replace = animation.toString().replace("\\", "\\\\");
|
|
||||||
builder.suggest("\"" + replace + "\"");
|
|
||||||
return builder.buildFuture();
|
|
||||||
} catch (Exception e) { return builder.buildFuture(); }
|
|
||||||
})
|
|
||||||
.then(literal("clearFile").executes(GenerateJsonClientCommand::clearJson))
|
|
||||||
.then(literal("generate")
|
|
||||||
.then(literal("anim")
|
|
||||||
.then(literal("example").executes(GenerateJsonClientCommand::generateExample))
|
|
||||||
.executes(context -> generateJson(context, false, false))
|
|
||||||
.then(argument("reset", BoolArgumentType.bool())
|
|
||||||
.executes(context ->
|
|
||||||
generateJson(context, false, BoolArgumentType.getBool(context, "reset"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(literal("layer")
|
|
||||||
.executes(context -> generateJson(context, true, false))
|
|
||||||
.then(argument("reset", BoolArgumentType.bool())
|
|
||||||
.executes(context ->
|
|
||||||
generateJson(context, true, BoolArgumentType.getBool(context, "reset"))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void clearPath(Path dir) throws IOException {
|
|
||||||
if (!Files.exists(dir)) return;
|
|
||||||
try (var pathStream = Files.walk(dir)) {
|
|
||||||
pathStream.sorted(Comparator.reverseOrder()).forEach(path -> {
|
|
||||||
try {
|
|
||||||
Files.delete(path);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (RuntimeException ignored) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int generateJson(CommandContext<CommandSourceStack> context, boolean isLayer, boolean isReset) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
String pathString = StringArgumentType.getString(context, "path");
|
|
||||||
Path animationPath = Minecraft.getInstance().gameDirectory.toPath().resolve(pathString).resolve("animation");
|
|
||||||
if (!Files.exists(animationPath)) {
|
|
||||||
try {Files.createDirectories(animationPath);}
|
|
||||||
catch (IOException e) { throw new RuntimeException(e); }
|
|
||||||
}
|
|
||||||
if(isReset) clearPath(animationPath);
|
|
||||||
if(isLayer) {
|
|
||||||
Path path = AnimLayerJson.Writer.syntaxImmediately(animationPath);
|
|
||||||
MutableComponent component = Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
|
||||||
"layer", "Client"
|
|
||||||
);
|
|
||||||
Style style = Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, animationPath.toString()))
|
|
||||||
.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true);
|
|
||||||
component.append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
|
||||||
path.toString()
|
|
||||||
).setStyle(style));
|
|
||||||
source.sendSuccess(() -> component, true);
|
|
||||||
} else {
|
|
||||||
for (Animation value : AnimationRegistry.getAnimations().values()) {
|
|
||||||
AnimJson.Writer.stream(animationPath, value).syntax();
|
|
||||||
}
|
|
||||||
MutableComponent component = Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
|
||||||
"anim", "Client"
|
|
||||||
);
|
|
||||||
Style style = Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, animationPath.toString()))
|
|
||||||
.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true);
|
|
||||||
component.append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
|
||||||
animationPath.toString()
|
|
||||||
).withStyle(style));
|
|
||||||
source.sendSuccess(() -> component, true);
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int clearJson(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
String pathString = StringArgumentType.getString(context, "path");
|
|
||||||
Path animationPath = Minecraft.getInstance().gameDirectory.toPath().resolve(pathString).resolve("animation");
|
|
||||||
clearPath(animationPath);
|
|
||||||
source.sendSuccess(() -> Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
|
||||||
), true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int generateExample(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
String pathString = StringArgumentType.getString(context, "path");
|
|
||||||
Path animationPath = Minecraft.getInstance().gameDirectory.toPath().resolve(pathString);
|
|
||||||
Path path = AnimJson.Writer.syntaxExample(animationPath);
|
|
||||||
MutableComponent component = Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
|
||||||
"anim example", "Client"
|
|
||||||
);
|
|
||||||
Style style = Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, path.toString()))
|
|
||||||
.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true);
|
|
||||||
component.append(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
|
||||||
path.toString()
|
|
||||||
).setStyle(style));
|
|
||||||
source.sendSuccess(() -> component, true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.translatable(
|
|
||||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
|
||||||
).withStyle(ChatFormatting.RED));
|
|
||||||
SnowyCrescentCore.log.error(e.getMessage());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
package com.linearpast.sccore.animation.command.client;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.command.ListServerCommand;
|
||||||
|
import com.linearpast.sccore.animation.register.RawAnimationRegistry;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class ListClientCommand {
|
||||||
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||||
|
animCommand.then(literal("list").then(literal("clientAnimations")
|
||||||
|
.executes(ListClientCommand::listAnimations))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int listAnimations(CommandContext<CommandSourceStack> context) {
|
||||||
|
try {
|
||||||
|
CommandSourceStack source = context.getSource();
|
||||||
|
List<ResourceLocation> list = RawAnimationRegistry.getAnimations().keySet().stream().toList();
|
||||||
|
source.sendSuccess(() -> Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.LIST_ANIMATION_RESOURCE.getKey(),
|
||||||
|
"Client", "Animations", ListServerCommand.getString(list)
|
||||||
|
), false);
|
||||||
|
return 1;
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.linearpast.sccore.animation.command.client;
|
package com.linearpast.sccore.animation.command.client;
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import com.linearpast.sccore.core.datagen.ModLang;
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
import com.mojang.brigadier.context.CommandContext;
|
||||||
|
|
@ -16,9 +16,9 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import static net.minecraft.commands.Commands.literal;
|
import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class RefreshAnimCommand {
|
public class RefreshCommand {
|
||||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
||||||
animCommand.then(literal("refresh").executes(RefreshAnimCommand::refresh));
|
animCommand.then(literal("refresh").executes(RefreshCommand::refresh));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int refresh(CommandContext<CommandSourceStack> ctx){
|
private static int refresh(CommandContext<CommandSourceStack> ctx){
|
||||||
|
|
@ -27,7 +27,7 @@ public class RefreshAnimCommand {
|
||||||
Minecraft instance = Minecraft.getInstance();
|
Minecraft instance = Minecraft.getInstance();
|
||||||
LocalPlayer player = instance.player;
|
LocalPlayer player = instance.player;
|
||||||
if(player == null) throw new RuntimeException();
|
if(player == null) throw new RuntimeException();
|
||||||
AnimationUtils.refreshAnimation(player);
|
AnimationHelper.INSTANCE.refreshAnimation(player);
|
||||||
source.sendSuccess(() -> Component.translatable(
|
source.sendSuccess(() -> Component.translatable(
|
||||||
ModLang.TranslatableMessage.REFRESH_ANIMATIONS.getKey()
|
ModLang.TranslatableMessage.REFRESH_ANIMATIONS.getKey()
|
||||||
).withStyle(ChatFormatting.GREEN), true);
|
).withStyle(ChatFormatting.GREEN), true);
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.linearpast.sccore.animation.command.exception;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.MutableComponent;
|
||||||
|
|
||||||
|
public class ApiBackException extends Exception {
|
||||||
|
private final ApiBack apiBack;
|
||||||
|
private Object[] args;
|
||||||
|
public ApiBackException(ApiBack apiBack) {
|
||||||
|
this.apiBack = apiBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiBackException(ApiBack apiBack, Object... args) {
|
||||||
|
this.apiBack = apiBack;
|
||||||
|
this.args = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiBackException withCooldown(Integer cooldown) {
|
||||||
|
return new ApiBackException(ApiBack.COOLDOWN, cooldown);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ApiBackException withOutRange(Integer distance) {
|
||||||
|
return new ApiBackException(ApiBack.OUT_RANGE, distance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableComponent getCommandFailBack() {
|
||||||
|
if(args != null && args.length > 0) {
|
||||||
|
return Component.translatable(getLang(), args);
|
||||||
|
} else {
|
||||||
|
return Component.translatable(getLang());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLang() {
|
||||||
|
return switch (apiBack) {
|
||||||
|
case FAIL -> ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey();
|
||||||
|
case UNSUPPORTED -> ModLang.TranslatableMessage.ANIMATION_OPERATION_UNSUPPORTED.getKey();
|
||||||
|
case COOLDOWN -> ModLang.TranslatableMessage.ANIMATION_COOLDOWN.getKey();
|
||||||
|
case OUT_RANGE -> ModLang.TranslatableMessage.ANIMATION_OUT_RANGE.getKey();
|
||||||
|
case OPERATION_EXPIRE -> ModLang.TranslatableMessage.ANIMATION_EXPIRE.getKey();
|
||||||
|
case RESOURCE_NOT_FOUND -> ModLang.TranslatableMessage.ANIMATION_RESOURCE_NOT_FOUND.getKey();
|
||||||
|
case SUCCESS -> ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey();
|
||||||
|
case BE_CANCELLED -> ModLang.TranslatableMessage.ANIMATION_OPERATION_CANCELLED.getKey();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.linearpast.sccore.animation.command.exception;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.chat.Style;
|
||||||
|
|
||||||
|
public class CommandComponentException extends Exception {
|
||||||
|
private final Component component;
|
||||||
|
private final boolean isCommandFail;
|
||||||
|
public CommandComponentException(ModLang.TranslatableMessage message, Object ... args) {
|
||||||
|
super("Expected command exception.");
|
||||||
|
this.component = Component.translatable(
|
||||||
|
message.getKey(),
|
||||||
|
args
|
||||||
|
).withStyle(ChatFormatting.RED);
|
||||||
|
this.isCommandFail = true;
|
||||||
|
}
|
||||||
|
public CommandComponentException(ModLang.TranslatableMessage message, Style style, Object ... args) {
|
||||||
|
super("Expected command exception.");
|
||||||
|
this.component = Component.translatable(
|
||||||
|
message.getKey(),
|
||||||
|
args
|
||||||
|
).withStyle(style);
|
||||||
|
this.isCommandFail = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getCommandFailBack() {
|
||||||
|
return isCommandFail ? Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey(),
|
||||||
|
component
|
||||||
|
).withStyle(ChatFormatting.RED) : component;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.linearpast.sccore.animation.data;
|
||||||
|
|
||||||
|
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||||
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.ListTag;
|
||||||
|
import net.minecraft.nbt.StringTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.INBTSerializable;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AnimationData implements INBTSerializable<CompoundTag> {
|
||||||
|
protected ResourceLocation key;
|
||||||
|
protected @Nullable Ride ride;
|
||||||
|
|
||||||
|
public ResourceLocation getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimationData withRide(Ride ride) {
|
||||||
|
this.ride = ride;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public KeyframeAnimation getAnimation() {
|
||||||
|
return PlayerAnimationRegistry.getAnimation(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Ride getRide() {
|
||||||
|
return ride;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag serializeNBT() {
|
||||||
|
CompoundTag tag = new CompoundTag();
|
||||||
|
tag.putString("key", key.toString());
|
||||||
|
if (ride != null) {
|
||||||
|
CompoundTag rideTag = new CompoundTag();
|
||||||
|
Vec3 offset = ride.getOffset();
|
||||||
|
rideTag.putDouble("x", offset.x);
|
||||||
|
rideTag.putDouble("y", offset.y);
|
||||||
|
rideTag.putDouble("z", offset.z);
|
||||||
|
rideTag.putInt("existTick", ride.getExistTick());
|
||||||
|
rideTag.putFloat("xRot", ride.getXRot());
|
||||||
|
rideTag.putFloat("yRot", ride.getYRot());
|
||||||
|
List<ResourceLocation> componentAnimations = ride.getComponentAnimations();
|
||||||
|
ListTag listTag = new ListTag();
|
||||||
|
for (ResourceLocation animation : componentAnimations) {
|
||||||
|
listTag.add(StringTag.valueOf(animation.toString()));
|
||||||
|
}
|
||||||
|
rideTag.put("subAnimations", listTag);
|
||||||
|
tag.put("ride", rideTag);
|
||||||
|
}
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deserializeNBT(CompoundTag nbt) {
|
||||||
|
String string = nbt.getString("key");
|
||||||
|
this.key = new ResourceLocation(string);
|
||||||
|
try {
|
||||||
|
if(nbt.contains("ride")) {
|
||||||
|
CompoundTag rideTag = nbt.getCompound("ride");
|
||||||
|
Vec3 offset = new Vec3(
|
||||||
|
rideTag.getDouble("x"),
|
||||||
|
rideTag.getDouble("y"),
|
||||||
|
rideTag.getDouble("z")
|
||||||
|
);
|
||||||
|
int existTick = rideTag.getInt("existTick");
|
||||||
|
float xRot = rideTag.getFloat("xRot");
|
||||||
|
float yRot = rideTag.getFloat("yRot");
|
||||||
|
List<ResourceLocation> componentAnimations = new ArrayList<>();
|
||||||
|
rideTag.getList("subAnimations", 8).forEach(tag ->
|
||||||
|
componentAnimations.add(new ResourceLocation(tag.getAsString()))
|
||||||
|
);
|
||||||
|
this.ride = Ride.create()
|
||||||
|
.withOffset(offset)
|
||||||
|
.withExistTick(existTick)
|
||||||
|
.withXRot(xRot)
|
||||||
|
.withYRot(yRot)
|
||||||
|
.setComponentAnimations(componentAnimations);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
this.ride = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,28 +3,28 @@ package com.linearpast.sccore.animation.data;
|
||||||
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
public class Animation {
|
public class GenericAnimationData extends AnimationData {
|
||||||
private @Nullable String name;
|
private @Nullable String name;
|
||||||
private final ResourceLocation key;
|
|
||||||
private KeyframeAnimation animation;
|
|
||||||
private float heightModifier = 1.0f;
|
private float heightModifier = 1.0f;
|
||||||
private float camYaw;
|
private float camYaw;
|
||||||
private float camPitch;
|
private float camPitch;
|
||||||
private float camRoll;
|
private float camRoll;
|
||||||
private float camY;
|
private float camY;
|
||||||
private @Nullable Animation.LyingType lyingType;
|
private @Nullable GenericAnimationData.LyingType lyingType;
|
||||||
private @Nullable Ride ride;
|
|
||||||
|
|
||||||
Animation(ResourceLocation key) {
|
GenericAnimationData(ResourceLocation key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
}
|
}
|
||||||
|
public GenericAnimationData(){}
|
||||||
|
|
||||||
public static Animation create(ResourceLocation name) {
|
public static GenericAnimationData create(ResourceLocation name) {
|
||||||
return new Animation(name);
|
return new GenericAnimationData(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum LyingType {
|
public enum LyingType {
|
||||||
|
|
@ -52,7 +52,7 @@ public class Animation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withLyingType(@Nullable Animation.LyingType lyingType) {
|
public GenericAnimationData withLyingType(@Nullable GenericAnimationData.LyingType lyingType) {
|
||||||
this.lyingType = lyingType;
|
this.lyingType = lyingType;
|
||||||
if(lyingType == null) return this;
|
if(lyingType == null) return this;
|
||||||
this.camY = -1.3f;
|
this.camY = -1.3f;
|
||||||
|
|
@ -72,37 +72,37 @@ public class Animation {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withHeightModifier(float heightModifier) {
|
public GenericAnimationData withHeightModifier(float heightModifier) {
|
||||||
this.heightModifier = heightModifier;
|
this.heightModifier = heightModifier;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withCamYaw(float camYaw) {
|
public GenericAnimationData withCamYaw(float camYaw) {
|
||||||
this.camYaw = camYaw;
|
this.camYaw = camYaw;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withCamPitch(float camPitch) {
|
public GenericAnimationData withCamPitch(float camPitch) {
|
||||||
this.camPitch = camPitch;
|
this.camPitch = camPitch;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withCamRoll(float camRoll) {
|
public GenericAnimationData withCamRoll(float camRoll) {
|
||||||
this.camRoll = camRoll;
|
this.camRoll = camRoll;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withCamY(float camY) {
|
public GenericAnimationData withCamY(float camY) {
|
||||||
this.camY = camY;
|
this.camY = camY;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withRide(Ride ride) {
|
public GenericAnimationData withRide(Ride ride) {
|
||||||
this.ride = ride;
|
this.ride = ride;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation withName(String name) {
|
public GenericAnimationData withName(String name) {
|
||||||
String regex = "^[a-zA-Z0-9_-]+$";
|
String regex = "^[a-zA-Z0-9_-]+$";
|
||||||
Pattern pattern = Pattern.compile(regex);
|
Pattern pattern = Pattern.compile(regex);
|
||||||
if (!pattern.matcher(name).matches()) {
|
if (!pattern.matcher(name).matches()) {
|
||||||
|
|
@ -131,11 +131,12 @@ public class Animation {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
public KeyframeAnimation getAnimation() {
|
public KeyframeAnimation getAnimation() {
|
||||||
return PlayerAnimationRegistry.getAnimation(key);
|
return PlayerAnimationRegistry.getAnimation(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Animation.LyingType getLyingType() {
|
public @Nullable GenericAnimationData.LyingType getLyingType() {
|
||||||
return lyingType;
|
return lyingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -147,14 +148,6 @@ public class Animation {
|
||||||
return heightModifier;
|
return heightModifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Ride getRide() {
|
|
||||||
return ride;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ResourceLocation getKey() {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable String getName() {
|
public @Nullable String getName() {
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
package com.linearpast.sccore.animation.data;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public class RawAnimationData extends AnimationData{
|
||||||
|
RawAnimationData(ResourceLocation key) {
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
public RawAnimationData(){}
|
||||||
|
|
||||||
|
public static RawAnimationData create(ResourceLocation name) {
|
||||||
|
return new RawAnimationData(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawAnimationData withRide(Ride ride) {
|
||||||
|
this.ride = ride;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ package com.linearpast.sccore.animation.data.util;
|
||||||
|
|
||||||
import com.google.gson.*;
|
import com.google.gson.*;
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.Ride;
|
import com.linearpast.sccore.animation.data.Ride;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
@ -53,16 +53,16 @@ public class AnimJson {
|
||||||
return new Reader(jsonElement);
|
return new Reader(jsonElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation parse() {
|
public GenericAnimationData parse() {
|
||||||
return fromJson();
|
return fromJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation fromJson() {
|
public GenericAnimationData fromJson() {
|
||||||
try {
|
try {
|
||||||
JsonObject json = originElement.getAsJsonObject();
|
JsonObject json = originElement.getAsJsonObject();
|
||||||
Animation animation = Animation.create(new ResourceLocation(json.get(Key).getAsString()));
|
GenericAnimationData animation = GenericAnimationData.create(new ResourceLocation(json.get(Key).getAsString()));
|
||||||
if(json.has(Name)) animation.withName(json.get(Name).getAsString());
|
if(json.has(Name)) animation.withName(json.get(Name).getAsString());
|
||||||
if(json.has(LyingType)) animation.withLyingType(Animation.LyingType.valueOf(json.get(LyingType).getAsString()));
|
if(json.has(LyingType)) animation.withLyingType(GenericAnimationData.LyingType.valueOf(json.get(LyingType).getAsString()));
|
||||||
animation.withHeightModifier(json.get(HeightModifier).getAsFloat())
|
animation.withHeightModifier(json.get(HeightModifier).getAsFloat())
|
||||||
.withCamY(json.get(CamY).getAsFloat())
|
.withCamY(json.get(CamY).getAsFloat())
|
||||||
.withCamPitch(json.get(CamPitch).getAsFloat())
|
.withCamPitch(json.get(CamPitch).getAsFloat())
|
||||||
|
|
@ -100,25 +100,25 @@ public class AnimJson {
|
||||||
public static class Writer {
|
public static class Writer {
|
||||||
private static final String example = "example";
|
private static final String example = "example";
|
||||||
private final @Nullable Path file;
|
private final @Nullable Path file;
|
||||||
private final Animation animation;
|
private final GenericAnimationData animation;
|
||||||
Writer(@Nullable Path file, Animation animation) {
|
Writer(@Nullable Path file, GenericAnimationData animation) {
|
||||||
this.animation = animation;
|
this.animation = animation;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Writer stream(Path path, Animation animation) {
|
public static Writer stream(Path path, GenericAnimationData animation) {
|
||||||
return new Writer(path, animation);
|
return new Writer(path, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Writer stream(Animation animation) {
|
public static Writer stream(GenericAnimationData animation) {
|
||||||
return new Writer(null, animation);
|
return new Writer(null, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Path syntaxExample(Path directory) throws Exception {
|
public static Path syntaxExample(Path directory) throws Exception {
|
||||||
ResourceLocation exampleLocation = new ResourceLocation(SnowyCrescentCore.MODID, Writer.example);
|
ResourceLocation exampleLocation = new ResourceLocation(SnowyCrescentCore.MODID, Writer.example);
|
||||||
Animation example = Animation.create(exampleLocation)
|
GenericAnimationData example = GenericAnimationData.create(exampleLocation)
|
||||||
.withName(Writer.example)
|
.withName(Writer.example)
|
||||||
.withLyingType(Animation.LyingType.RIGHT)
|
.withLyingType(GenericAnimationData.LyingType.RIGHT)
|
||||||
.withHeightModifier(0.3f)
|
.withHeightModifier(0.3f)
|
||||||
.withCamY(-1.3f)
|
.withCamY(-1.3f)
|
||||||
.withCamPitch(-90.0f)
|
.withCamPitch(-90.0f)
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,21 @@
|
||||||
package com.linearpast.sccore.animation.entity;
|
package com.linearpast.sccore.animation.entity;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.Ride;
|
import com.linearpast.sccore.animation.data.Ride;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import com.linearpast.sccore.animation.register.AnimationEntities;
|
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraftforge.network.NetworkHooks;
|
import net.minecraftforge.network.NetworkHooks;
|
||||||
import net.minecraftforge.server.ServerLifecycleHooks;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
@ -28,16 +26,12 @@ public class AnimationRideEntity extends Entity {
|
||||||
this.noPhysics = true;
|
this.noPhysics = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String Animation = "Animation";
|
|
||||||
private static final String PlayerUUID = "PlayerUUID";
|
|
||||||
private static final String Layer = "Layer";
|
|
||||||
|
|
||||||
private final Set<ServerPlayer> players = new HashSet<>();
|
private final Set<ServerPlayer> players = new HashSet<>();
|
||||||
private final Map<ResourceLocation, UUID> animationPair = new HashMap<>();
|
private final Map<ResourceLocation, UUID> animationPair = new HashMap<>();
|
||||||
private Animation animation;
|
private GenericAnimationData animation;
|
||||||
private ServerPlayer player;
|
private ServerPlayer player;
|
||||||
private ResourceLocation layer;
|
private ResourceLocation layer;
|
||||||
public AnimationRideEntity(ServerPlayer pPlayer, ResourceLocation layer, Animation animation) {
|
public AnimationRideEntity(ServerPlayer pPlayer, ResourceLocation layer, GenericAnimationData animation) {
|
||||||
this(pPlayer.level());
|
this(pPlayer.level());
|
||||||
this.player = pPlayer;
|
this.player = pPlayer;
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
|
|
@ -63,7 +57,7 @@ public class AnimationRideEntity extends Entity {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Animation getAnimation() {
|
public GenericAnimationData getAnimation() {
|
||||||
return animation;
|
return animation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,36 +65,10 @@ public class AnimationRideEntity extends Entity {
|
||||||
protected void defineSynchedData() {}
|
protected void defineSynchedData() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void readAdditionalSaveData(@NotNull CompoundTag pCompound) {
|
protected void readAdditionalSaveData(@NotNull CompoundTag pCompound) {}
|
||||||
String string = pCompound.getString(Animation);
|
|
||||||
if(!string.isEmpty()) {
|
|
||||||
ResourceLocation rl = new ResourceLocation(string);
|
|
||||||
Animation anim = AnimationUtils.getAnimation(rl);
|
|
||||||
if(anim != null) {
|
|
||||||
this.animation = anim;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pCompound.contains(PlayerUUID)) {
|
|
||||||
MinecraftServer server = ServerLifecycleHooks.getCurrentServer();
|
|
||||||
if(server != null) {
|
|
||||||
this.player = server.getPlayerList().getPlayer(pCompound.getUUID(PlayerUUID));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(pCompound.contains(Layer)) {
|
|
||||||
this.layer = new ResourceLocation(pCompound.getString(Layer));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addAdditionalSaveData(@NotNull CompoundTag pCompound) {
|
protected void addAdditionalSaveData(@NotNull CompoundTag pCompound) {}
|
||||||
pCompound.putUUID(PlayerUUID, player.getUUID());
|
|
||||||
pCompound.putString(Layer, layer.toString());
|
|
||||||
if(animation != null) {
|
|
||||||
pCompound.putString(Animation, animation.getKey().toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
|
|
@ -134,7 +102,7 @@ public class AnimationRideEntity extends Entity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean create(ServerPlayer pPlayer, ResourceLocation layer, ResourceLocation animation, boolean force) {
|
public static boolean create(ServerPlayer pPlayer, ResourceLocation layer, ResourceLocation animation, boolean force) {
|
||||||
Animation anim = AnimationUtils.getAnimation(animation);
|
GenericAnimationData anim = AnimationHelper.INSTANCE.getAnimation(animation);
|
||||||
if(anim == null) return false;
|
if(anim == null) return false;
|
||||||
if(anim.getRide() == null) return false;
|
if(anim.getRide() == null) return false;
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(pPlayer).orElse(null);
|
IAnimationCapability data = AnimationDataCapability.getCapability(pPlayer).orElse(null);
|
||||||
|
|
@ -195,7 +163,7 @@ public class AnimationRideEntity extends Entity {
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
||||||
if(data == null) return;
|
if(data == null) return;
|
||||||
data.setRiderAnimation(layer, animLocation);
|
data.setRiderAnimation(layer, animLocation);
|
||||||
AnimationUtils.syncAnimation(serverPlayer, player);
|
AnimationHelper.INSTANCE.syncAnimation(serverPlayer, player);
|
||||||
players.add(serverPlayer);
|
players.add(serverPlayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -204,16 +172,16 @@ public class AnimationRideEntity extends Entity {
|
||||||
protected void removePassenger(@NotNull Entity entity) {
|
protected void removePassenger(@NotNull Entity entity) {
|
||||||
super.removePassenger(entity);
|
super.removePassenger(entity);
|
||||||
if(entity instanceof ServerPlayer serverPlayer) {
|
if(entity instanceof ServerPlayer serverPlayer) {
|
||||||
AnimationUtils.removeAnimation(serverPlayer, layer);
|
AnimationHelper.INSTANCE.removeAnimation(serverPlayer, layer);
|
||||||
players.remove(serverPlayer);
|
players.remove(serverPlayer);
|
||||||
new HashMap<>(animationPair).forEach((key, value) -> {
|
new HashMap<>(animationPair).forEach((key, value) -> {
|
||||||
if(Objects.equals(value, serverPlayer.getUUID())) {
|
if(Objects.equals(value, serverPlayer.getUUID())) {
|
||||||
animationPair.put(key, null);
|
animationPair.put(key, null);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
AnimationDataCapability.getCapability(serverPlayer).ifPresent(
|
||||||
if(data == null) return;
|
IAnimationCapability::removeRiderAnimation
|
||||||
data.removeRiderAnimation();
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
package com.linearpast.sccore.animation.entity;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.Ride;
|
||||||
|
import com.linearpast.sccore.animation.helper.RawAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.LivingEntity;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.minecraftforge.network.NetworkHooks;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
public class RawAnimationRideEntity extends Entity {
|
||||||
|
public RawAnimationRideEntity(Level pLevel) {
|
||||||
|
super(AnimationEntities.RIDE.get(), pLevel);
|
||||||
|
this.noPhysics = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Set<ServerPlayer> players = new HashSet<>();
|
||||||
|
private final Map<ResourceLocation, UUID> animationPair = new HashMap<>();
|
||||||
|
private RawAnimationData rawAnimation;
|
||||||
|
private ServerPlayer player;
|
||||||
|
private ResourceLocation layer;
|
||||||
|
public RawAnimationRideEntity(ServerPlayer pPlayer, ResourceLocation layer, RawAnimationData rawAnimation) {
|
||||||
|
this(pPlayer.level());
|
||||||
|
this.player = pPlayer;
|
||||||
|
this.layer = layer;
|
||||||
|
this.rawAnimation = rawAnimation;
|
||||||
|
Ride ride = rawAnimation.getRide();
|
||||||
|
if(ride != null) {
|
||||||
|
List<ResourceLocation> componentAnimations = ride.getComponentAnimations();
|
||||||
|
for (ResourceLocation componentAnimation : componentAnimations) {
|
||||||
|
animationPair.put(componentAnimation, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceLocation getLayer() {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<ServerPlayer> getPlayers() {
|
||||||
|
return players;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerPlayer getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawAnimationData getAnimation() {
|
||||||
|
return rawAnimation;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void defineSynchedData() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void readAdditionalSaveData(@NotNull CompoundTag pCompound) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addAdditionalSaveData(@NotNull CompoundTag pCompound) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
super.tick();
|
||||||
|
if(!this.level().isClientSide) {
|
||||||
|
Ride ride = rawAnimation == null ? null : rawAnimation.getRide();
|
||||||
|
if(!this.getPassengers().contains(player) || (ride != null && ride.getExistTick() > 0 && this.tickCount >= ride.getExistTick())) {
|
||||||
|
this.remove(RemovalReason.DISCARDED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public double getPassengersRidingOffset() {
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean canRide(@NotNull Entity entity) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRiderSit() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Packet<ClientGamePacketListener> getAddEntityPacket(){
|
||||||
|
return NetworkHooks.getEntitySpawningPacket(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static RawAnimationRideEntity create(ServerPlayer pPlayer, ResourceLocation layer, RawAnimationData animation) {
|
||||||
|
if(animation.getRide() == null) return null;
|
||||||
|
RawAnimationDataCapability data = RawAnimationDataCapability.getCapability(pPlayer).orElse(null);
|
||||||
|
if(data == null) return null;
|
||||||
|
data.setRiderAnimation(layer, animation.getKey());
|
||||||
|
RawAnimationRideEntity seat = new RawAnimationRideEntity(pPlayer, layer, animation);
|
||||||
|
float xRot = animation.getRide().getXRot();
|
||||||
|
float yRot = animation.getRide().getYRot();
|
||||||
|
if(xRot == 0 && yRot == 0) seat.setRot(pPlayer.getXRot(), pPlayer.getYRot());
|
||||||
|
else seat.setRot(yRot, xRot);
|
||||||
|
Vec3 pos = pPlayer.position();
|
||||||
|
pos.add(animation.getRide().getOffset());
|
||||||
|
seat.setPos(pos.x, pos.y + 0.35f, pos.z);
|
||||||
|
pPlayer.level().addFreshEntity(seat);
|
||||||
|
pPlayer.startRiding(seat, false);
|
||||||
|
return seat;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void positionRider(@NotNull Entity pPassenger, @NotNull MoveFunction pCallback) {
|
||||||
|
super.positionRider(pPassenger, pCallback);
|
||||||
|
pPassenger.setYBodyRot(this.getYRot());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPassengerTurned(@NotNull Entity pEntityToUpdate) {
|
||||||
|
pEntityToUpdate.setYBodyRot(this.getYRot());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Vec3 getDismountLocationForPassenger(@NotNull LivingEntity entity) {
|
||||||
|
Ride ride = rawAnimation.getRide();
|
||||||
|
if(ride != null) {
|
||||||
|
Vec3 position = entity.position();
|
||||||
|
return position.subtract(ride.getOffset());
|
||||||
|
}
|
||||||
|
return entity.position();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addPassenger(@NotNull Entity entity) {
|
||||||
|
int passengerNum = getPassengers().size();
|
||||||
|
super.addPassenger(entity);
|
||||||
|
if(passengerNum == 0) return;
|
||||||
|
if(entity instanceof ServerPlayer serverPlayer) {
|
||||||
|
Ride ride = rawAnimation.getRide();
|
||||||
|
if(ride == null) return;
|
||||||
|
List<ResourceLocation> componentAnimations = ride.getComponentAnimations();
|
||||||
|
if(componentAnimations.isEmpty()) return;
|
||||||
|
if(passengerNum > componentAnimations.size()) return;
|
||||||
|
ResourceLocation animLocation = null;
|
||||||
|
for (ResourceLocation location : animationPair.keySet()) {
|
||||||
|
if(animationPair.get(location) == null)
|
||||||
|
animLocation = location;
|
||||||
|
}
|
||||||
|
if(animLocation == null) return;
|
||||||
|
animationPair.put(animLocation, serverPlayer.getUUID());
|
||||||
|
RawAnimationDataCapability data = RawAnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
||||||
|
if(data == null) return;
|
||||||
|
data.setRiderAnimation(layer, animLocation);
|
||||||
|
RawAnimationHelper.INSTANCE.syncAnimation(serverPlayer, player);
|
||||||
|
players.add(serverPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removePassenger(@NotNull Entity entity) {
|
||||||
|
super.removePassenger(entity);
|
||||||
|
if(entity instanceof ServerPlayer serverPlayer) {
|
||||||
|
RawAnimationHelper.INSTANCE.removeAnimation(serverPlayer, layer);
|
||||||
|
players.remove(serverPlayer);
|
||||||
|
new HashMap<>(animationPair).forEach((key, value) -> {
|
||||||
|
if(Objects.equals(value, serverPlayer.getUUID())) {
|
||||||
|
animationPair.put(key, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
RawAnimationDataCapability.getCapability(serverPlayer).ifPresent(
|
||||||
|
RawAnimationDataCapability::removeRiderAnimation
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canAddPassenger(@NotNull Entity pPassenger) {
|
||||||
|
if(!(pPassenger instanceof ServerPlayer)) return false;
|
||||||
|
int size = players.size();
|
||||||
|
Ride ride = rawAnimation.getRide();
|
||||||
|
if(ride == null) return false;
|
||||||
|
int maxSize = ride.getComponentAnimations().size();
|
||||||
|
boolean flag1 = size < maxSize;
|
||||||
|
boolean flag2 = !(pPassenger.getVehicle() instanceof AnimationRideEntity);
|
||||||
|
return flag1 && flag2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,22 +1,32 @@
|
||||||
package com.linearpast.sccore.animation.event;
|
package com.linearpast.sccore.animation.event;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||||
|
import com.linearpast.sccore.animation.entity.RawAnimationRideEntity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
public class PlayerTickEvent {
|
public class PlayerTickEvent {
|
||||||
|
@SubscribeEvent
|
||||||
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event) {
|
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event) {
|
||||||
if (event.side.isServer() && event.phase == TickEvent.Phase.END) {
|
if (event.side.isServer() && event.phase == TickEvent.Phase.END) {
|
||||||
if(event.player.tickCount % 20 == 0) {
|
if(event.player.tickCount % 20 == 0) {
|
||||||
Player player = event.player;
|
Player player = event.player;
|
||||||
if(!(player.getVehicle() instanceof AnimationRideEntity)){
|
if(!(player.getVehicle() instanceof AnimationRideEntity)){
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
AnimationDataCapability.getCapability(player).ifPresent(capability -> {
|
||||||
if(data == null) return;
|
if(capability.getRiderAnimLayer() != null) {
|
||||||
if(data.getRiderAnimLayer() != null) {
|
capability.removeRiderAnimation();
|
||||||
data.removeRiderAnimation();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if(!(player.getVehicle() instanceof RawAnimationRideEntity)){
|
||||||
|
RawAnimationDataCapability.getCapability(player).ifPresent(capability -> {
|
||||||
|
if(capability.getRiderAnimLayer() != null) {
|
||||||
|
capability.removeRiderAnimation();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
package com.linearpast.sccore.animation.event.client;
|
package com.linearpast.sccore.animation.event.client;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import dev.kosmx.playerAnim.core.util.MathHelper;
|
import dev.kosmx.playerAnim.core.util.MathHelper;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.player.LocalPlayer;
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import net.minecraftforge.client.event.ViewportEvent;
|
import net.minecraftforge.client.event.ViewportEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ public class CameraAnglesModify {
|
||||||
private static float currentPitch = 0.0F;
|
private static float currentPitch = 0.0F;
|
||||||
private static float currentRoll = 0.0F;
|
private static float currentRoll = 0.0F;
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
public static void changeCameraView(ViewportEvent.ComputeCameraAngles event){
|
public static void changeCameraView(ViewportEvent.ComputeCameraAngles event){
|
||||||
Minecraft minecraft = Minecraft.getInstance();
|
Minecraft minecraft = Minecraft.getInstance();
|
||||||
|
|
||||||
|
|
@ -30,10 +32,10 @@ public class CameraAnglesModify {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||||
if(data == null) return;
|
if(data == null) return;
|
||||||
Animation animation = null;
|
GenericAnimationData animation = null;
|
||||||
try {
|
try {
|
||||||
animation = data.getAnimations().values().stream()
|
animation = data.getAnimations().values().stream()
|
||||||
.map(AnimationUtils::getAnimation)
|
.map(AnimationHelper.INSTANCE::getAnimation)
|
||||||
.min(Comparator.comparingDouble(anim -> {
|
.min(Comparator.comparingDouble(anim -> {
|
||||||
if (anim == null) return 1.0f;
|
if (anim == null) return 1.0f;
|
||||||
return anim.getHeightModifier();
|
return anim.getHeightModifier();
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,30 @@
|
||||||
package com.linearpast.sccore.animation.event.client;
|
package com.linearpast.sccore.animation.event.client;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import net.minecraft.client.player.AbstractClientPlayer;
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import net.minecraftforge.event.TickEvent;
|
import net.minecraftforge.event.TickEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public class ClientPlayerTick {
|
public class ClientPlayerEvent {
|
||||||
|
@SubscribeEvent
|
||||||
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
|
public static void onPlayerTick(TickEvent.PlayerTickEvent event) {
|
||||||
if (event.side.isClient() && event.phase == TickEvent.Phase.START) {
|
if (event.side.isClient() && event.phase == TickEvent.Phase.START) {
|
||||||
Player player = event.player;
|
Player player = event.player;
|
||||||
if(player.tickCount % 10 != 0) return;
|
if(player.tickCount % 10 != 0) return;
|
||||||
if (!(player instanceof AbstractClientPlayer clientPlayer)) return;
|
if (!(player instanceof AbstractClientPlayer clientPlayer)) return;
|
||||||
AnimationUtils.refreshAnimation(clientPlayer);
|
AnimationHelper.INSTANCE.refreshAnimation(clientPlayer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<Runnable, Map.Entry<Integer, Integer>> runs = new HashMap<>();
|
public static Map<Runnable, Map.Entry<Integer, Integer>> runs = new HashMap<>();
|
||||||
|
@SubscribeEvent
|
||||||
public static void delayRuns(TickEvent.PlayerTickEvent event) {
|
public static void delayRuns(TickEvent.PlayerTickEvent event) {
|
||||||
if (event.side.isClient() && event.phase == TickEvent.Phase.END) {
|
if (event.side.isClient() && event.phase == TickEvent.Phase.END) {
|
||||||
Map.copyOf(runs).forEach((runnable, countMap) -> {
|
Map.copyOf(runs).forEach((runnable, countMap) -> {
|
||||||
|
|
@ -3,8 +3,10 @@ package com.linearpast.sccore.animation.event.client;
|
||||||
import com.linearpast.sccore.animation.entity.renderer.AnimationRideRenderer;
|
import com.linearpast.sccore.animation.entity.renderer.AnimationRideRenderer;
|
||||||
import com.linearpast.sccore.animation.register.AnimationEntities;
|
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||||
import net.minecraftforge.client.event.EntityRenderersEvent;
|
import net.minecraftforge.client.event.EntityRenderersEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
public class EntityRendererRegisterEvent {
|
public class EntityRendererRegisterEvent {
|
||||||
|
@SubscribeEvent
|
||||||
public static void registerEntityRenderer(EntityRenderersEvent.RegisterRenderers event) {
|
public static void registerEntityRenderer(EntityRenderersEvent.RegisterRenderers event) {
|
||||||
event.registerEntityRenderer(AnimationEntities.RIDE.get(), AnimationRideRenderer::new);
|
event.registerEntityRenderer(AnimationEntities.RIDE.get(), AnimationRideRenderer::new);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
package com.linearpast.sccore.animation.event.create;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.eventbus.api.Cancelable;
|
||||||
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
|
import net.minecraftforge.fml.LogicalSide;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
@Cancelable
|
||||||
|
@Event.HasResult
|
||||||
|
public class AnimationEvent extends Event {
|
||||||
|
public final LogicalSide side;
|
||||||
|
|
||||||
|
AnimationEvent(LogicalSide side) {
|
||||||
|
this.side = side;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
APPLY, INVITE, REQUEST
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Send extends AnimationEvent {
|
||||||
|
private int validTick;
|
||||||
|
private int cooldownTick;
|
||||||
|
public final Type type;
|
||||||
|
public Send(LogicalSide side, int validTick, int cooldownTick, Type type) {
|
||||||
|
super(side);
|
||||||
|
this.validTick = validTick;
|
||||||
|
this.cooldownTick = cooldownTick;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValidTick() {
|
||||||
|
return validTick;
|
||||||
|
}
|
||||||
|
public int getCooldownTick() {
|
||||||
|
return cooldownTick;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setValidTick(int validTick) {
|
||||||
|
this.validTick = validTick;
|
||||||
|
}
|
||||||
|
public void setCooldownTick(int cooldownTick) {
|
||||||
|
this.cooldownTick = cooldownTick;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Accept extends AnimationEvent {
|
||||||
|
private int validDistance;
|
||||||
|
public final Type type;
|
||||||
|
public Accept(Type type) {
|
||||||
|
super(LogicalSide.SERVER);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
public Accept(Type type, int validDistance) {
|
||||||
|
this(type);
|
||||||
|
this.validDistance = validDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getValidDistance() {
|
||||||
|
return validDistance;
|
||||||
|
}
|
||||||
|
public void setValidDistance(int validDistance) {
|
||||||
|
this.validDistance = validDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Play extends AnimationEvent {
|
||||||
|
private final @Nullable Player player;
|
||||||
|
private final ResourceLocation layer;
|
||||||
|
private final AnimationData animation;
|
||||||
|
public Play(LogicalSide side, @Nullable Player player, ResourceLocation layer, AnimationData animation) {
|
||||||
|
super(side);
|
||||||
|
this.player = player;
|
||||||
|
this.layer = layer;
|
||||||
|
this.animation = animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
public ResourceLocation getLayer() {
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
public AnimationData getAnimation() {
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Join extends AnimationEvent {
|
||||||
|
private final Player player;
|
||||||
|
private final Player target;
|
||||||
|
private boolean force;
|
||||||
|
public Join(Player player, Player target, boolean force) {
|
||||||
|
super(LogicalSide.SERVER);
|
||||||
|
this.player = player;
|
||||||
|
this.target = target;
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Player getPlayer() {
|
||||||
|
return player;
|
||||||
|
}
|
||||||
|
public Player getTarget() {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
public boolean isForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setForce(boolean force) {
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.event.create;
|
|
||||||
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraftforge.eventbus.api.Event;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* You can listen this event to invite an animation layer <br>
|
|
||||||
* It is only useful in server
|
|
||||||
*/
|
|
||||||
public class AnimationLayerRegisterEvent extends Event {
|
|
||||||
private final Map<ResourceLocation, Integer> layers = new HashMap<>();
|
|
||||||
|
|
||||||
public Map<ResourceLocation, Integer> getLayers() {
|
|
||||||
return layers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerLayer(ResourceLocation key, Integer value) {
|
|
||||||
layers.put(key, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +1,50 @@
|
||||||
package com.linearpast.sccore.animation.event.create;
|
package com.linearpast.sccore.animation.event.create;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.register.RawAnimationRegistry;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraftforge.eventbus.api.Event;
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
|
||||||
* You can listen this event to invite an animation <br>
|
|
||||||
* It is only useful in server
|
|
||||||
*/
|
|
||||||
public class AnimationRegisterEvent extends Event {
|
public class AnimationRegisterEvent extends Event {
|
||||||
private final Map<ResourceLocation, Animation> animations = new HashMap<>();
|
public static class Layer extends AnimationRegisterEvent {
|
||||||
|
private final Map<ResourceLocation, Integer> layers = new HashMap<>();
|
||||||
|
|
||||||
public Map<ResourceLocation, Animation> getAnimations() {
|
public Map<ResourceLocation, Integer> getLayers() {
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerLayer(ResourceLocation key, Integer value) {
|
||||||
|
layers.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Animation extends AnimationRegisterEvent {
|
||||||
|
private final Map<ResourceLocation, GenericAnimationData> animations = new HashMap<>();
|
||||||
|
|
||||||
|
public Map<ResourceLocation, GenericAnimationData> getAnimations() {
|
||||||
return new HashMap<>(animations);
|
return new HashMap<>(animations);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerAnimation(ResourceLocation location, Animation animation) {
|
public void registerAnimation(ResourceLocation location, GenericAnimationData animation) {
|
||||||
animations.put(location, animation);
|
animations.put(location, animation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RawAnimation extends AnimationRegisterEvent {
|
||||||
|
private final Map<ResourceLocation, RawAnimationData> animations = new HashMap<>();
|
||||||
|
|
||||||
|
public Map<ResourceLocation, RawAnimationData> getAnimations() {
|
||||||
|
return new HashMap<>(animations);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerAnimation(ResourceLocation location, RawAnimationData animation) {
|
||||||
|
if (RawAnimationRegistry.validateLocation(location)) {
|
||||||
|
animations.put(location, animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,211 @@
|
||||||
|
package com.linearpast.sccore.animation.helper;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import com.linearpast.sccore.animation.utils.AnimationUtils;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation Util. May be you can call it Api.
|
||||||
|
*/
|
||||||
|
public class AnimationHelper implements IAnimationHelper<GenericAnimationData, IAnimationCapability> {
|
||||||
|
public static final AnimationHelper INSTANCE = new AnimationHelper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the LyingType when there are animations which playing on player. <br>
|
||||||
|
* And It will return the first which be found.
|
||||||
|
* @param player Target player
|
||||||
|
* @return The first LyingType it find.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public GenericAnimationData.LyingType getSideView(Player player) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||||
|
if(data == null) return null;
|
||||||
|
GenericAnimationData.LyingType lyingType = null;
|
||||||
|
for (ResourceLocation value : data.getAnimations().values()) {
|
||||||
|
GenericAnimationData animation = getAnimation(value);
|
||||||
|
if(animation == null) return null;
|
||||||
|
GenericAnimationData.LyingType type = animation.getLyingType();
|
||||||
|
if(type == null) continue;
|
||||||
|
switch (type) {
|
||||||
|
case FRONT,BACK -> {}
|
||||||
|
case LEFT,RIGHT -> lyingType = animation.getLyingType();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return lyingType;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the HeightModifier when there are animations which playing on player. <br>
|
||||||
|
* And It will return the first which be found.
|
||||||
|
* @param player Target player
|
||||||
|
* @return The first HeightModifier it find.
|
||||||
|
*/
|
||||||
|
public float getHeightModifier(Player player) {
|
||||||
|
Float result = ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||||
|
if (data == null) return 1.0f;
|
||||||
|
float heightModifier = 1.0f;
|
||||||
|
for (ResourceLocation value : data.getAnimations().values()) {
|
||||||
|
GenericAnimationData animation = getAnimation(value);
|
||||||
|
if (animation == null) continue;
|
||||||
|
float animationHeightModifier = animation.getHeightModifier();
|
||||||
|
heightModifier = Math.min(heightModifier, animationHeightModifier);
|
||||||
|
}
|
||||||
|
return heightModifier;
|
||||||
|
});
|
||||||
|
return result == null ? 1.0f : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable GenericAnimationData getAnimation(ResourceLocation location) {
|
||||||
|
return AnimationRegistry.getAnimations().getOrDefault(location, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable GenericAnimationData getAnimation(CompoundTag tag) {
|
||||||
|
return new GenericAnimationData(){{deserializeNBT(tag);}};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable IAnimationCapability getCapability(Player player) {
|
||||||
|
return AnimationDataCapability.getCapability(player).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAnimations(ServerPlayer serverPlayer) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
Optional.ofNullable(getCapability(serverPlayer)).ifPresent(IAnimationCapability::clearAnimations);
|
||||||
|
detachAnimation(serverPlayer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAnimationPresent(ResourceLocation location) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationRegistry.getAnimations().containsKey(location));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack detachAnimation(ServerPlayer player) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(player.getVehicle() instanceof AnimationRideEntity) {
|
||||||
|
player.stopRiding();
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
}
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack joinAnimationServer(ServerPlayer player, ServerPlayer target, boolean force) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
Entity vehicle = target.getVehicle();
|
||||||
|
if(vehicle instanceof AnimationRideEntity) {
|
||||||
|
boolean result = player.startRiding(vehicle, force);
|
||||||
|
return result ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
}
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void refreshAnimation(AbstractClientPlayer clientPlayer) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
IAnimationCapability data = getCapability(clientPlayer);
|
||||||
|
if(data == null) return;
|
||||||
|
Set<ResourceLocation> oldLayers = new HashSet<>(data.getAnimations().keySet());
|
||||||
|
for (ResourceLocation layer : Set.copyOf(oldLayers)) {
|
||||||
|
if (AnimationUtils.isClientAnimationStop(clientPlayer, layer)) {
|
||||||
|
removeAnimation(clientPlayer, layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ResourceLocation getAnimationPlaying(Player player, @Nullable ResourceLocation layer) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
IAnimationCapability data = getCapability(player);
|
||||||
|
if(data == null) return null;
|
||||||
|
if(layer == null){
|
||||||
|
for (ResourceLocation value : data.getAnimations().values()) {
|
||||||
|
if(value != null) return value;
|
||||||
|
}
|
||||||
|
} else if (isAnimationLayerPresent(layer)) {
|
||||||
|
if(data.isAnimationPresent(layer)){
|
||||||
|
return data.getAnimation(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack removeAnimation(@NotNull ServerPlayer serverPlayer, ResourceLocation layer) {
|
||||||
|
boolean result = ANIMATION_RUNNER.testLoadedAndCall(() -> Optional.ofNullable(getCapability(serverPlayer))
|
||||||
|
.map(data -> data.removeAnimation(layer)).orElse(false));
|
||||||
|
return result ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack playAnimationWithRide(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animation, boolean force) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
ResourceLocation key = animation.getKey();
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(key))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
if(animation.getRide() == null)
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
if(player instanceof FakePlayer)
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
boolean flag = player.getVehicle() != null;
|
||||||
|
if(flag && force) player.unRide();
|
||||||
|
else if(flag) return ApiBack.UNSUPPORTED;
|
||||||
|
boolean result = AnimationRideEntity.create(player, layer, key, force);
|
||||||
|
return result ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack playAnimationServer(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animation) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
ResourceLocation key = animation.getKey();
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(key))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
if(player instanceof FakePlayer)
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
Boolean flag = Optional.ofNullable(getCapability(player)).map(data ->
|
||||||
|
data.mergeAnimation(layer, key)).orElse(false);
|
||||||
|
return flag ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApiBack playAnimation(@NotNull ServerPlayer player, ResourceLocation layer, ResourceLocation animation) {
|
||||||
|
return playAnimation(player, layer, getAnimation(animation));
|
||||||
|
}
|
||||||
|
public ApiBack playAnimationWithRide(@NotNull ServerPlayer player, ResourceLocation layer, ResourceLocation animation, boolean force) {
|
||||||
|
return playAnimationWithRide(player, layer, getAnimation(animation), force);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
package com.linearpast.sccore.animation.helper;
|
||||||
|
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
|
||||||
|
public class HelperGetterFromAnimation implements IHelperGetter {
|
||||||
|
private final ResourceLocation location;
|
||||||
|
|
||||||
|
public HelperGetterFromAnimation(ResourceLocation location) {
|
||||||
|
this.location = location;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IHelperGetter create(ResourceLocation location) {
|
||||||
|
return new HelperGetterFromAnimation(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(IAnimationHelper<?, ?> helper) {
|
||||||
|
return helper.isAnimationPresent(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,637 @@
|
||||||
|
package com.linearpast.sccore.animation.helper;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.event.PlayerTickEvent;
|
||||||
|
import com.linearpast.sccore.animation.event.client.CameraAnglesModify;
|
||||||
|
import com.linearpast.sccore.animation.event.client.ClientPlayerEvent;
|
||||||
|
import com.linearpast.sccore.animation.event.client.EntityRendererRegisterEvent;
|
||||||
|
import com.linearpast.sccore.animation.event.create.AnimationEvent;
|
||||||
|
import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
||||||
|
import com.linearpast.sccore.animation.network.toserver.*;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationCapabilities;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationChannels;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import com.linearpast.sccore.animation.utils.AnimationUtils;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
||||||
|
import com.linearpast.sccore.core.ModChannel;
|
||||||
|
import com.linearpast.sccore.core.ModLazyRun;
|
||||||
|
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||||
|
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||||
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.eventbus.api.Event;
|
||||||
|
import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
|
import net.minecraftforge.fml.LogicalSide;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Animation helper interface
|
||||||
|
* @param <D> Animation data
|
||||||
|
* @param <C> Capability
|
||||||
|
*/
|
||||||
|
@SuppressWarnings({"UnusedReturnValue", "unused"})
|
||||||
|
public interface IAnimationHelper<D extends AnimationData, C extends ICapabilitySync<?>>{
|
||||||
|
String AnimModId = "playeranimator";
|
||||||
|
/**
|
||||||
|
* Lazy runner
|
||||||
|
*/
|
||||||
|
ModLazyRun ANIMATION_RUNNER = new ModLazyRun(AnimModId) {
|
||||||
|
@Override
|
||||||
|
public void addCommonListener(IEventBus forgeBus, IEventBus modBus) {
|
||||||
|
AnimationEntities.register(modBus);
|
||||||
|
forgeBus.register(AnimationRegistry.class);
|
||||||
|
forgeBus.register(PlayerTickEvent.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addClientListener(IEventBus forgeBus, IEventBus modBus) {
|
||||||
|
modBus.register(EntityRendererRegisterEvent.class);
|
||||||
|
forgeBus.register(CameraAnglesModify.class);
|
||||||
|
forgeBus.register(ClientPlayerEvent.class);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Cache info record, not persistent
|
||||||
|
record ApplyAnimationRecord(UUID target, int expireTick) {}
|
||||||
|
record InviteAnimationRecord(ResourceLocation layer, AnimationData animation, int expireTick, List<UUID> targets) {}
|
||||||
|
record RequestAnimationRecord(ResourceLocation layer, AnimationData animation, int expireTick, UUID target, boolean isRide) {}
|
||||||
|
|
||||||
|
//Apply & invite & request history record
|
||||||
|
Map<UUID, ApplyAnimationRecord> applyMap = new ConcurrentHashMap<>();
|
||||||
|
Map<UUID, InviteAnimationRecord> inviteMap = new ConcurrentHashMap<>();
|
||||||
|
Map<UUID, RequestAnimationRecord> requestMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
//Last apply & invite & request tick map
|
||||||
|
Map<UUID, Integer> lastApplyTickMap = new ConcurrentHashMap<>();
|
||||||
|
Map<UUID, Integer> lastInviteTickMap = new ConcurrentHashMap<>();
|
||||||
|
Map<UUID, Integer> lastRequestTickMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Equal to {@link AnimationRegistry#getLayers()}
|
||||||
|
* @return Resource location set
|
||||||
|
*/
|
||||||
|
default Set<ResourceLocation> getLayers() {
|
||||||
|
return Set.copyOf(AnimationRegistry.getLayers().keySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get animation by location
|
||||||
|
* @param location location
|
||||||
|
* @return Animation data
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
D getAnimation(ResourceLocation location);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get animation by Tag (deserializeNBT)
|
||||||
|
* @param tag tag
|
||||||
|
* @return Animation data
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
D getAnimation(CompoundTag tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get capability
|
||||||
|
* @param player player
|
||||||
|
* @return Capability
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
C getCapability(Player player);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To register handler
|
||||||
|
* @param forgeBus Forge event bus
|
||||||
|
* @param modBus Mod event bus
|
||||||
|
*/
|
||||||
|
static void register(IEventBus forgeBus, IEventBus modBus){
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
AnimationCapabilities.registerAnimationCapability();
|
||||||
|
AnimationChannels.registerChannel();
|
||||||
|
});
|
||||||
|
ANIMATION_RUNNER.testLoadedAndAddListener(forgeBus, modBus);
|
||||||
|
}
|
||||||
|
|
||||||
|
//clear animations
|
||||||
|
void clearAnimations(ServerPlayer serverPlayer);
|
||||||
|
//according to location, judge if animation is present
|
||||||
|
boolean isAnimationPresent(ResourceLocation location);
|
||||||
|
//stop riding
|
||||||
|
ApiBack detachAnimation(ServerPlayer player);
|
||||||
|
//start ride
|
||||||
|
ApiBack joinAnimationServer(ServerPlayer player, ServerPlayer target, boolean force);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger event and let implementation class handle
|
||||||
|
* @param player player
|
||||||
|
* @param target target
|
||||||
|
* @param force is force
|
||||||
|
* @return Api back
|
||||||
|
*/
|
||||||
|
default ApiBack joinAnimation(ServerPlayer player, ServerPlayer target, boolean force){
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
AnimationEvent.Join playEvent = new AnimationEvent.Join(player, target, force);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(playEvent);
|
||||||
|
Event.Result eventResult = playEvent.getResult();
|
||||||
|
if(post || eventResult == Event.Result.DENY) return ApiBack.BE_CANCELLED;
|
||||||
|
return joinAnimationServer(player, target, playEvent.isForce());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync animation tick to client
|
||||||
|
* @param player Player
|
||||||
|
* @param target Target player
|
||||||
|
*/
|
||||||
|
default void syncAnimation(ServerPlayer player, ServerPlayer target) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID()), player);
|
||||||
|
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID()), target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sync animation tick on client
|
||||||
|
* @param player Player
|
||||||
|
* @param target Target player
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default void syncAnimation(AbstractClientPlayer player, AbstractClientPlayer target) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationUtils.syncAnimation(player, target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh animation throw capability
|
||||||
|
* @param clientPlayer player
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
void refreshAnimation(AbstractClientPlayer clientPlayer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refresh animation on client, it will not sync to capability
|
||||||
|
* @param clientPlayer player
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default void refreshAnimationUnsafe(AbstractClientPlayer clientPlayer) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
Set<ResourceLocation> oldLayers = new HashSet<>(AnimationRegistry.getLayers().keySet());
|
||||||
|
for (ResourceLocation layer : Set.copyOf(oldLayers)) {
|
||||||
|
if (AnimationUtils.isClientAnimationStop(clientPlayer, layer)) {
|
||||||
|
removeAnimation(clientPlayer, layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if layer exist and has been invite.
|
||||||
|
* @param layer Target layer
|
||||||
|
* @return If layer exist and has been invited
|
||||||
|
*/
|
||||||
|
default boolean isAnimationLayerPresent(ResourceLocation layer) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> getLayers().contains(layer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get animation which is playing now on player. <br>
|
||||||
|
* If layer is null, it will return the first playing animation which can be found.
|
||||||
|
* @param player Target player
|
||||||
|
* @param layer Target layer
|
||||||
|
* @return Playing animation resource location
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
ResourceLocation getAnimationPlaying(Player player, @Nullable ResourceLocation layer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove animation.
|
||||||
|
* @param player Target player
|
||||||
|
* @param layer Target layer
|
||||||
|
* @return If success
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default ApiBack removeAnimation(@Nullable AbstractClientPlayer player, ResourceLocation layer) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
AnimationUtils.removeAnimation(player, layer);
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ApiBack removeAnimation(@NotNull ServerPlayer serverPlayer, ResourceLocation layer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* Play animation with ride. Player will ride an entity, then play animation.
|
||||||
|
* When player unride, animation will be remove.
|
||||||
|
* If player is riding and the "force" is false, it will return false
|
||||||
|
* </pre>
|
||||||
|
* @param player Target player
|
||||||
|
* @param layer Target layer
|
||||||
|
* @param animation Animation
|
||||||
|
* @param force If force to ride and play animation
|
||||||
|
* @return If success
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default ApiBack playAnimationWithRide(@Nullable AbstractClientPlayer player, ResourceLocation layer, ResourceLocation animation, boolean force) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(isAnimationLayerPresent(layer) && isAnimationPresent(animation))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
UUID uuid = player == null ? null : player.getUUID();
|
||||||
|
AnimationData anim = getAnimation(animation);
|
||||||
|
if(anim == null || anim.getRide() == null) return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
ModChannel.sendToServer(new PlayAnimationRidePacket(anim, layer, animation, uuid, force));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ApiBack playAnimationWithRide(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animationTag, boolean force);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* Play animation.
|
||||||
|
* If run in Dist.CLIENT, player can be null, it will play animation only client.
|
||||||
|
* If animation be null, it will remove animation on layer.
|
||||||
|
* </pre>
|
||||||
|
* @param player Target player
|
||||||
|
* @param layer Target layer
|
||||||
|
* @param animation Animation
|
||||||
|
* @return If success
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default ApiBack playAnimation(@Nullable AbstractClientPlayer player, ResourceLocation layer, ResourceLocation animation) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(isAnimationLayerPresent(layer) && isAnimationPresent(animation))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
UUID uuid = player == null ? null : player.getUUID();
|
||||||
|
AnimationData anim = getAnimation(animation);
|
||||||
|
if(anim == null) return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
|
||||||
|
AnimationEvent.Play playEvent = new AnimationEvent.Play(
|
||||||
|
LogicalSide.CLIENT,
|
||||||
|
player,
|
||||||
|
layer,
|
||||||
|
anim
|
||||||
|
);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(playEvent);
|
||||||
|
Event.Result eventResult = playEvent.getResult();
|
||||||
|
if(post || eventResult == Event.Result.DENY) return ApiBack.BE_CANCELLED;
|
||||||
|
ModChannel.sendToServer(new PlayAnimationPacket(anim, layer, animation, uuid));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger event and let implementation class handle
|
||||||
|
* @param player player
|
||||||
|
* @param layer target layer
|
||||||
|
* @param animation animation
|
||||||
|
* @return Api back
|
||||||
|
*/
|
||||||
|
default ApiBack playAnimation(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animation){
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
AnimationEvent.Play playEvent = new AnimationEvent.Play(LogicalSide.SERVER, player, layer, animation);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(playEvent);
|
||||||
|
Event.Result eventResult = playEvent.getResult();
|
||||||
|
if(post || eventResult == Event.Result.DENY) return ApiBack.BE_CANCELLED;
|
||||||
|
return playAnimationServer(player, layer, animation);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ApiBack playAnimationServer(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request animation
|
||||||
|
*/
|
||||||
|
default ApiBack request(ServerPlayer player, ServerPlayer target, ResourceLocation layer, AnimationData animation, boolean isRide) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(animation.getKey()))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
int tickCount = player.server.getTickCount();
|
||||||
|
UUID playerUUID = player.getUUID();
|
||||||
|
UUID targetUUID = target.getUUID();
|
||||||
|
|
||||||
|
int origin = ModConfigs.Server.requestValidTime.get() * 20;
|
||||||
|
int cooldown = ModConfigs.Server.requestCooldown.get() * 20;
|
||||||
|
AnimationEvent.Send sendEvent = new AnimationEvent.Send(LogicalSide.SERVER, origin, cooldown, AnimationEvent.Type.APPLY);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(sendEvent);
|
||||||
|
if(post) return ApiBack.BE_CANCELLED;
|
||||||
|
Event.Result eventResult = sendEvent.getResult();
|
||||||
|
switch (eventResult) {
|
||||||
|
case DENY : return ApiBack.BE_CANCELLED;
|
||||||
|
case DEFAULT : {
|
||||||
|
//Test if is not in cooldown
|
||||||
|
int lastTick = lastRequestTickMap.getOrDefault(playerUUID, 0);
|
||||||
|
if(Math.max(tickCount - sendEvent.getCooldownTick(), 0) >= lastTick) {
|
||||||
|
lastRequestTickMap.put(playerUUID, tickCount);
|
||||||
|
} else return ApiBack.COOLDOWN;
|
||||||
|
}
|
||||||
|
case ALLOW : {
|
||||||
|
//Add to cache, done
|
||||||
|
int expireTick = sendEvent.getValidTick() + tickCount;
|
||||||
|
requestMap.put(playerUUID, new RequestAnimationRecord(layer, animation, expireTick, targetUUID, isRide));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
}
|
||||||
|
default: return ApiBack.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client request
|
||||||
|
* @param target target
|
||||||
|
* @param layer layer
|
||||||
|
* @param animation animation
|
||||||
|
* @return Api back
|
||||||
|
*/
|
||||||
|
default ApiBack request(AbstractClientPlayer target, ResourceLocation layer, ResourceLocation animation) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(animation))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
KeyframeAnimation keyframeAnimation = PlayerAnimationRegistry.getAnimation(animation);
|
||||||
|
if(keyframeAnimation == null) return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
D data = getAnimation(animation);
|
||||||
|
if(data == null) return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
AnimationEvent.Send sendEvent = new AnimationEvent.Send(
|
||||||
|
LogicalSide.CLIENT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
AnimationEvent.Type.REQUEST
|
||||||
|
);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(sendEvent);
|
||||||
|
Event.Result eventResult = sendEvent.getResult();
|
||||||
|
if(post || eventResult == Event.Result.DENY) return ApiBack.BE_CANCELLED;
|
||||||
|
ModChannel.sendToServer(new RequestAnimationPacket(data, layer, target.getUUID()));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Accept Request
|
||||||
|
*/
|
||||||
|
default ApiBack acceptRequest(ServerPlayer player, ServerPlayer requestor) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
UUID requestorUUID = requestor.getUUID();
|
||||||
|
RequestAnimationRecord record = requestMap.getOrDefault(requestorUUID, null);
|
||||||
|
if (record == null) return ApiBack.UNSUPPORTED;
|
||||||
|
UUID uuid = player.getUUID();
|
||||||
|
if (!record.target().equals(uuid)) return ApiBack.UNSUPPORTED;
|
||||||
|
|
||||||
|
AnimationEvent.Accept acceptEvent = new AnimationEvent.Accept(AnimationEvent.Type.REQUEST, 0);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(acceptEvent);
|
||||||
|
if(post) return ApiBack.BE_CANCELLED;
|
||||||
|
Event.Result eventResult = acceptEvent.getResult();
|
||||||
|
switch (eventResult) {
|
||||||
|
case DENY : return ApiBack.BE_CANCELLED;
|
||||||
|
case DEFAULT : {
|
||||||
|
//Test if is in valid time
|
||||||
|
int tickCount = requestor.server.getTickCount();
|
||||||
|
if (tickCount >= record.expireTick()) {
|
||||||
|
requestMap.remove(requestorUUID);
|
||||||
|
return ApiBack.OPERATION_EXPIRE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ALLOW : {
|
||||||
|
//done
|
||||||
|
ApiBack back;
|
||||||
|
if(record.isRide()) back = playAnimationWithRide(player, record.layer(), record.animation(), false);
|
||||||
|
else back = playAnimation(player, record.layer(), record.animation());
|
||||||
|
if(back == ApiBack.SUCCESS) requestMap.remove(requestorUUID);
|
||||||
|
return back;
|
||||||
|
}
|
||||||
|
default: return ApiBack.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send apply to join animation on server side
|
||||||
|
*/
|
||||||
|
default ApiBack apply(ServerPlayer player, ServerPlayer target) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
int tickCount = player.server.getTickCount();
|
||||||
|
|
||||||
|
int origin = ModConfigs.Server.applyValidTime.get() * 20;
|
||||||
|
int cooldown = ModConfigs.Server.applyCooldown.get() * 20;
|
||||||
|
AnimationEvent.Send sendEvent = new AnimationEvent.Send(
|
||||||
|
LogicalSide.SERVER,
|
||||||
|
origin,
|
||||||
|
cooldown,
|
||||||
|
AnimationEvent.Type.APPLY
|
||||||
|
);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(sendEvent);
|
||||||
|
if(post) return ApiBack.BE_CANCELLED;
|
||||||
|
Event.Result eventResult = sendEvent.getResult();
|
||||||
|
switch (eventResult) {
|
||||||
|
case DENY : return ApiBack.BE_CANCELLED;
|
||||||
|
case DEFAULT : {
|
||||||
|
//Test if is not in cooldown
|
||||||
|
int lastTick = lastApplyTickMap.getOrDefault(player.getUUID(), 0);
|
||||||
|
if(Math.max(tickCount - sendEvent.getCooldownTick(), 0) >= lastTick) {
|
||||||
|
lastApplyTickMap.put(player.getUUID(), tickCount);
|
||||||
|
} else return ApiBack.COOLDOWN;
|
||||||
|
}
|
||||||
|
case ALLOW : {
|
||||||
|
//Add to cache, done
|
||||||
|
int expireTick = sendEvent.getValidTick() + tickCount;
|
||||||
|
applyMap.put(player.getUUID(), new ApplyAnimationRecord(target.getUUID(), expireTick));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
}
|
||||||
|
default: return ApiBack.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send apply to join animation on client side. <br>
|
||||||
|
* It will send network packet and work on server side.
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default ApiBack apply(AbstractClientPlayer target) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
AnimationEvent.Send sendEvent = new AnimationEvent.Send(
|
||||||
|
LogicalSide.CLIENT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
AnimationEvent.Type.APPLY
|
||||||
|
);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(sendEvent);
|
||||||
|
Event.Result eventResult = sendEvent.getResult();
|
||||||
|
if(post || eventResult == Event.Result.DENY) return ApiBack.BE_CANCELLED;
|
||||||
|
ModChannel.sendToServer(new ApplyAnimationPacket(target.getUUID()));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player accept join apply.
|
||||||
|
* @param player Acceptor
|
||||||
|
* @param applier Applier
|
||||||
|
* @return If accept and riding success
|
||||||
|
*/
|
||||||
|
default ApiBack acceptApply(ServerPlayer player, ServerPlayer applier) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
ApplyAnimationRecord record = applyMap.getOrDefault(applier.getUUID(), null);
|
||||||
|
if (record == null) return ApiBack.UNSUPPORTED;
|
||||||
|
UUID uuid = player.getUUID();
|
||||||
|
if (!record.target().equals(uuid)) return ApiBack.UNSUPPORTED;
|
||||||
|
|
||||||
|
int maxDistance = ModConfigs.Server.applyValidDistance.get();
|
||||||
|
AnimationEvent.Accept acceptEvent = new AnimationEvent.Accept(AnimationEvent.Type.APPLY, maxDistance);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(acceptEvent);
|
||||||
|
if(post) return ApiBack.BE_CANCELLED;
|
||||||
|
Event.Result eventResult = acceptEvent.getResult();
|
||||||
|
switch (eventResult) {
|
||||||
|
case DENY : return ApiBack.BE_CANCELLED;
|
||||||
|
case DEFAULT : {
|
||||||
|
//Test if is in valid distance
|
||||||
|
int validDistance = acceptEvent.getValidDistance();
|
||||||
|
if(player.distanceToSqr(applier) > validDistance * validDistance) {
|
||||||
|
return ApiBack.OUT_RANGE;
|
||||||
|
}
|
||||||
|
int tickCount = applier.server.getTickCount();
|
||||||
|
if (tickCount > record.expireTick()) {
|
||||||
|
applyMap.remove(applier.getUUID());
|
||||||
|
return ApiBack.OPERATION_EXPIRE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ALLOW : {
|
||||||
|
//done
|
||||||
|
ApiBack back = joinAnimation(applier, player, false);
|
||||||
|
if(back == ApiBack.SUCCESS) applyMap.remove(applier.getUUID());
|
||||||
|
return back;
|
||||||
|
}
|
||||||
|
default: return ApiBack.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send invite on server side.
|
||||||
|
* @param player Sender
|
||||||
|
* @param animation Raw animation info
|
||||||
|
* @param layer Target layer
|
||||||
|
* @param targets Be invited players
|
||||||
|
*/
|
||||||
|
default ApiBack invite(ServerPlayer player, ResourceLocation layer, AnimationData animation, Collection<UUID> targets) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(animation.getKey()))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
int tickCount = player.server.getTickCount();
|
||||||
|
|
||||||
|
int origin = ModConfigs.Server.inviteValidTime.get() * 20;
|
||||||
|
int cooldown = ModConfigs.Server.inviteCooldown.get() * 20;
|
||||||
|
AnimationEvent.Send sendEvent = new AnimationEvent.Send(
|
||||||
|
LogicalSide.SERVER,
|
||||||
|
origin,
|
||||||
|
cooldown,
|
||||||
|
AnimationEvent.Type.INVITE
|
||||||
|
);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(sendEvent);
|
||||||
|
if(post) return ApiBack.BE_CANCELLED;
|
||||||
|
Event.Result eventResult = sendEvent.getResult();
|
||||||
|
switch (eventResult) {
|
||||||
|
case DENY : return ApiBack.BE_CANCELLED;
|
||||||
|
case DEFAULT : {
|
||||||
|
//Test if is not in cooldown
|
||||||
|
int lastTick = lastInviteTickMap.getOrDefault(player.getUUID(), 0);
|
||||||
|
if(Math.max(tickCount - sendEvent.getCooldownTick(), 0) >= lastTick) {
|
||||||
|
lastInviteTickMap.put(player.getUUID(), tickCount);
|
||||||
|
} else return ApiBack.COOLDOWN;
|
||||||
|
}
|
||||||
|
case ALLOW : {
|
||||||
|
//Add to cache, done
|
||||||
|
int expireTick = sendEvent.getValidTick() + tickCount;
|
||||||
|
inviteMap.put(player.getUUID(), new InviteAnimationRecord(layer, animation, expireTick, new ArrayList<>(targets)));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
}
|
||||||
|
default: return ApiBack.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send invite on client side. <br>
|
||||||
|
* It will send network packet and work on server side.
|
||||||
|
* @param animation Raw animation info
|
||||||
|
* @param layer Target layer
|
||||||
|
* @param targets Be invited players
|
||||||
|
* @return If send to server successfully.
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
default ApiBack invite(ResourceLocation layer, ResourceLocation animation, AbstractClientPlayer ... targets){
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(animation))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
KeyframeAnimation keyframeAnimation = PlayerAnimationRegistry.getAnimation(animation);
|
||||||
|
if(keyframeAnimation == null) return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
Set<UUID> list = Arrays.stream(targets).map(AbstractClientPlayer::getUUID).collect(Collectors.toSet());
|
||||||
|
D data = getAnimation(animation);
|
||||||
|
if(data == null) return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
AnimationEvent.Send sendEvent = new AnimationEvent.Send(
|
||||||
|
LogicalSide.CLIENT,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
AnimationEvent.Type.INVITE
|
||||||
|
);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(sendEvent);
|
||||||
|
Event.Result eventResult = sendEvent.getResult();
|
||||||
|
if(post || eventResult == Event.Result.DENY) return ApiBack.BE_CANCELLED;
|
||||||
|
ModChannel.sendToServer(new InviteAnimationPacket(data, layer, list));
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Player accept invite
|
||||||
|
* @param player Acceptor
|
||||||
|
* @param inviter Inviter
|
||||||
|
* @return If accept and riding success.
|
||||||
|
*/
|
||||||
|
default ApiBack acceptInvite(ServerPlayer player, ServerPlayer inviter) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
InviteAnimationRecord record = inviteMap.getOrDefault(inviter.getUUID(), null);
|
||||||
|
if(record == null) return ApiBack.UNSUPPORTED;
|
||||||
|
UUID uuid = player.getUUID();
|
||||||
|
if (!record.targets().contains(uuid)) return ApiBack.UNSUPPORTED;
|
||||||
|
|
||||||
|
int maxDistance = ModConfigs.Server.inviteValidDistance.get();
|
||||||
|
AnimationEvent.Accept acceptEvent = new AnimationEvent.Accept(AnimationEvent.Type.INVITE, maxDistance);
|
||||||
|
boolean post = MinecraftForge.EVENT_BUS.post(acceptEvent);
|
||||||
|
if(post) return ApiBack.BE_CANCELLED;
|
||||||
|
Event.Result eventResult = acceptEvent.getResult();
|
||||||
|
switch (eventResult) {
|
||||||
|
case DENY : return ApiBack.BE_CANCELLED;
|
||||||
|
case DEFAULT : {
|
||||||
|
//Test if is in valid distance
|
||||||
|
int validDistance = acceptEvent.getValidDistance();
|
||||||
|
if(player.distanceToSqr(inviter) > validDistance * validDistance) {
|
||||||
|
return ApiBack.OUT_RANGE;
|
||||||
|
}
|
||||||
|
int tickCount = inviter.server.getTickCount();
|
||||||
|
if(tickCount >= record.expireTick()) {
|
||||||
|
inviteMap.remove(inviter.getUUID());
|
||||||
|
return ApiBack.OPERATION_EXPIRE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case ALLOW : {
|
||||||
|
//done
|
||||||
|
playAnimationWithRide(inviter, record.layer(), record.animation(), false);
|
||||||
|
if(record.targets().isEmpty()) inviteMap.remove(inviter.getUUID());
|
||||||
|
ApiBack back = joinAnimation(player, inviter, false);
|
||||||
|
if(back == ApiBack.SUCCESS) record.targets().remove(uuid);
|
||||||
|
return back;
|
||||||
|
}
|
||||||
|
default: return ApiBack.UNSUPPORTED;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
package com.linearpast.sccore.animation.helper;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public interface IHelperGetter {
|
||||||
|
/**
|
||||||
|
* Get helper
|
||||||
|
*/
|
||||||
|
Set<IAnimationHelper<?, ?>> HELPERS = new LinkedHashSet<>(){{
|
||||||
|
add(AnimationHelper.INSTANCE);
|
||||||
|
add(RawAnimationHelper.INSTANCE);
|
||||||
|
}};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see IHelperGetter#filter
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
default IAnimationHelper<?, ?> getHelper() {
|
||||||
|
for (IAnimationHelper<?, ?> helper : HELPERS) {
|
||||||
|
if (filter(helper)) {
|
||||||
|
return helper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean filter(IAnimationHelper<?, ?> helper);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,93 @@
|
||||||
|
package com.linearpast.sccore.animation.helper;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||||
|
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.world.level.storage.LevelResource;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public class JsonHelper {
|
||||||
|
private final MinecraftServer server;
|
||||||
|
JsonHelper(MinecraftServer server) {
|
||||||
|
this.server = server;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JsonHelper getHelper(MinecraftServer server) {
|
||||||
|
return new JsonHelper(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get animation path
|
||||||
|
* @return path
|
||||||
|
*/
|
||||||
|
private Path getAnimationPath() {
|
||||||
|
Path dataPackPath = server.getWorldPath(LevelResource.DATAPACK_DIR);
|
||||||
|
return dataPackPath.resolve("animation");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete directories
|
||||||
|
* @throws IOException Exception
|
||||||
|
*/
|
||||||
|
public void clearPath() throws IOException {
|
||||||
|
Path animationPath = getAnimationPath();
|
||||||
|
if (!Files.exists(animationPath)) return;
|
||||||
|
try (var pathStream = Files.walk(animationPath)) {
|
||||||
|
pathStream.sorted(Comparator.reverseOrder()).forEach(path -> {
|
||||||
|
try {
|
||||||
|
Files.delete(path);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (RuntimeException ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate all json from server animation
|
||||||
|
* @param isLayer If layer
|
||||||
|
* @param isReset If reset
|
||||||
|
* @return Generate path
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Path generateJson(boolean isLayer, boolean isReset) {
|
||||||
|
try {
|
||||||
|
Path animationPath = getAnimationPath();
|
||||||
|
if (!Files.exists(animationPath)) {
|
||||||
|
try {Files.createDirectories(animationPath);}
|
||||||
|
catch (IOException e) { throw new RuntimeException(e); }
|
||||||
|
}
|
||||||
|
if(isReset) clearPath();
|
||||||
|
|
||||||
|
if(isLayer) {
|
||||||
|
return AnimLayerJson.Writer.syntaxImmediately(animationPath);
|
||||||
|
} else {
|
||||||
|
for (GenericAnimationData value : AnimationRegistry.getAnimations().values()) {
|
||||||
|
AnimJson.Writer.stream(animationPath, value).syntax();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return animationPath;
|
||||||
|
} catch (Exception ignored){}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate example json
|
||||||
|
* @return Example json path
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public Path generateExample() {
|
||||||
|
try {
|
||||||
|
Path animationPath = getAnimationPath();
|
||||||
|
return AnimJson.Writer.syntaxExample(animationPath);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,169 @@
|
||||||
|
package com.linearpast.sccore.animation.helper;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.entity.RawAnimationRideEntity;
|
||||||
|
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
||||||
|
import com.linearpast.sccore.animation.register.RawAnimationRegistry;
|
||||||
|
import com.linearpast.sccore.animation.utils.AnimationUtils;
|
||||||
|
import com.linearpast.sccore.animation.utils.ApiBack;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.util.FakePlayer;
|
||||||
|
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class RawAnimationHelper implements IAnimationHelper<RawAnimationData, RawAnimationDataCapability> {
|
||||||
|
public static final RawAnimationHelper INSTANCE = new RawAnimationHelper();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger raw animation registry. <br>
|
||||||
|
* It will clear all have been registered raw animation, then trigger register event. <br>
|
||||||
|
* If you need dynamic register, see {@link RawAnimationRegistry#register}, but it will reset when registry call register event. <br>
|
||||||
|
* If you need static register, you can add listener to {@link AnimationRegisterEvent.RawAnimation}
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void triggerRegistry() {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(RawAnimationRegistry::triggerRegistry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable RawAnimationData getAnimation(ResourceLocation location) {
|
||||||
|
if(FMLEnvironment.dist == Dist.CLIENT) {
|
||||||
|
return RawAnimationRegistry.getAnimations().getOrDefault(location, null);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable RawAnimationData getAnimation(CompoundTag tag) {
|
||||||
|
return new RawAnimationData(){{deserializeNBT(tag);}};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable RawAnimationDataCapability getCapability(Player player) {
|
||||||
|
return RawAnimationDataCapability.getCapability(player).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearAnimations(ServerPlayer serverPlayer) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
Optional.ofNullable(getCapability(serverPlayer)).ifPresent(RawAnimationDataCapability::clearAnimations);
|
||||||
|
detachAnimation(serverPlayer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAnimationPresent(ResourceLocation location) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack detachAnimation(ServerPlayer player) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(player.getVehicle() instanceof RawAnimationRideEntity) {
|
||||||
|
player.stopRiding();
|
||||||
|
return ApiBack.SUCCESS;
|
||||||
|
}
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack joinAnimationServer(ServerPlayer player, ServerPlayer target, boolean force) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
Entity vehicle = target.getVehicle();
|
||||||
|
if(vehicle instanceof RawAnimationRideEntity) {
|
||||||
|
boolean result = player.startRiding(vehicle, force);
|
||||||
|
return result ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
}
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public void refreshAnimation(AbstractClientPlayer clientPlayer) {
|
||||||
|
ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||||
|
RawAnimationDataCapability data = getCapability(clientPlayer);
|
||||||
|
if(data == null) return;
|
||||||
|
Set<ResourceLocation> oldLayers = new HashSet<>(data.getAnimations().keySet());
|
||||||
|
for (ResourceLocation layer : Set.copyOf(oldLayers)) {
|
||||||
|
if (AnimationUtils.isClientAnimationStop(clientPlayer, layer)) {
|
||||||
|
removeAnimation(clientPlayer, layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ResourceLocation getAnimationPlaying(Player player, @Nullable ResourceLocation layer) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
RawAnimationDataCapability data = getCapability(player);
|
||||||
|
if(data == null) return null;
|
||||||
|
if(layer == null){
|
||||||
|
for (ResourceLocation value : data.getAnimations().values()) {
|
||||||
|
if(value != null) return value;
|
||||||
|
}
|
||||||
|
} else if (isAnimationLayerPresent(layer)) {
|
||||||
|
if(data.isAnimationPresent(layer)){
|
||||||
|
return data.getAnimation(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack removeAnimation(@NotNull ServerPlayer serverPlayer, ResourceLocation layer) {
|
||||||
|
boolean result = ANIMATION_RUNNER.testLoadedAndCall(() -> Optional.ofNullable(getCapability(serverPlayer))
|
||||||
|
.map(data -> data.removeAnimation(layer)).orElse(false));
|
||||||
|
return result ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack playAnimationWithRide(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animation, boolean force) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
if(!isAnimationLayerPresent(layer))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
if(animation.getRide() == null)
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
if(player instanceof FakePlayer)
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
boolean flag = player.getVehicle() != null;
|
||||||
|
if(flag && force) player.unRide();
|
||||||
|
else if(flag) return ApiBack.UNSUPPORTED;
|
||||||
|
if(!(animation instanceof RawAnimationData data))
|
||||||
|
return ApiBack.UNSUPPORTED;
|
||||||
|
RawAnimationRideEntity rawAnimationRideEntity = RawAnimationRideEntity.create(player, layer, data);
|
||||||
|
boolean result = rawAnimationRideEntity != null;
|
||||||
|
return result ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ApiBack playAnimationServer(@NotNull ServerPlayer player, ResourceLocation layer, AnimationData animation) {
|
||||||
|
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
ResourceLocation key = animation.getKey();
|
||||||
|
if(!isAnimationLayerPresent(layer) || !isAnimationPresent(key))
|
||||||
|
return ApiBack.RESOURCE_NOT_FOUND;
|
||||||
|
if(player instanceof FakePlayer) return ApiBack.UNSUPPORTED;
|
||||||
|
Boolean flag = Optional.ofNullable(getCapability(player)).map(data ->
|
||||||
|
data.mergeAnimation(layer, key)).orElse(false);
|
||||||
|
return flag ? ApiBack.SUCCESS : ApiBack.FAIL;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.linearpast.sccore.animation.network;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IHelperGetter;
|
||||||
|
import com.linearpast.sccore.animation.helper.RawAnimationHelper;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public abstract class HelperGetterPacket implements IHelperGetter {
|
||||||
|
/**
|
||||||
|
* Override it to filter helper in network packet
|
||||||
|
* @param helper helper
|
||||||
|
* @return Is right helper
|
||||||
|
*/
|
||||||
|
public boolean filter(IAnimationHelper<?, ?> helper) {
|
||||||
|
if(helper instanceof AnimationHelper animationHelper) {
|
||||||
|
ResourceLocation animation = getAnimation();
|
||||||
|
if(animation != null) return animationHelper.isAnimationPresent(animation);
|
||||||
|
} else if (helper instanceof RawAnimationHelper rawHelper) {
|
||||||
|
CompoundTag tag = getAnimationTag();
|
||||||
|
if(tag != null) return rawHelper.getAnimation(tag) != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selectable to override it
|
||||||
|
* @return Animation loacation
|
||||||
|
* @see HelperGetterPacket#filter
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected ResourceLocation getAnimation() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selectable to override it
|
||||||
|
* @return Animation data
|
||||||
|
* @see HelperGetterPacket#filter
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
protected CompoundTag getAnimationTag() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
package com.linearpast.sccore.animation.network.toclient;
|
package com.linearpast.sccore.animation.network.toclient;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
|
import com.linearpast.sccore.animation.utils.AnimationUtils;
|
||||||
|
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
||||||
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
||||||
import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
|
@ -13,15 +14,14 @@ import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
||||||
public AnimationCapabilityPacket(CompoundTag data) {
|
public AnimationCapabilityPacket(ICapabilitySync<Player> packet) {
|
||||||
super(data);
|
super(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnimationCapabilityPacket(FriendlyByteBuf buf) {
|
public AnimationCapabilityPacket(FriendlyByteBuf buf) {
|
||||||
|
|
@ -36,18 +36,14 @@ public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
||||||
if (level == null) return;
|
if (level == null) return;
|
||||||
CompoundTag nbt = getData();
|
CompoundTag nbt = getData();
|
||||||
Player player = level.getPlayerByUUID(nbt.getUUID(SimplePlayerCapabilitySync.OwnerUUID));
|
Player player = level.getPlayerByUUID(nbt.getUUID(SimplePlayerCapabilitySync.OwnerUUID));
|
||||||
|
if(player == null) return;
|
||||||
try {
|
try {
|
||||||
IAnimationCapability data = getCapability(player);
|
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||||
testPlayAnimations((AbstractClientPlayer) player, nbt, data);
|
testPlayAnimations((AbstractClientPlayer) player, nbt, data);
|
||||||
syncData(nbt, data);
|
syncData(nbt, data);
|
||||||
}catch (Exception ignored) {}
|
}catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable IAnimationCapability getCapability(Player player) {
|
|
||||||
return AnimationDataCapability.getCapability(player).orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void testPlayAnimations(AbstractClientPlayer player, CompoundTag tag, IAnimationCapability data) {
|
private void testPlayAnimations(AbstractClientPlayer player, CompoundTag tag, IAnimationCapability data) {
|
||||||
if(data == null) return;
|
if(data == null) return;
|
||||||
ResourceLocation oldRiderAnimLayer = data.getRiderAnimLayer();
|
ResourceLocation oldRiderAnimLayer = data.getRiderAnimLayer();
|
||||||
|
|
@ -56,8 +52,8 @@ public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
||||||
if(!Objects.equals(oldRiderAnimLayer, newRiderAnimLayer)) {
|
if(!Objects.equals(oldRiderAnimLayer, newRiderAnimLayer)) {
|
||||||
String riderAnimationString = tag.getString(AnimationDataCapability.RideAnimation);
|
String riderAnimationString = tag.getString(AnimationDataCapability.RideAnimation);
|
||||||
ResourceLocation newRiderAnimation = riderAnimationString.isEmpty() ? null : new ResourceLocation(riderAnimationString);
|
ResourceLocation newRiderAnimation = riderAnimationString.isEmpty() ? null : new ResourceLocation(riderAnimationString);
|
||||||
if(oldRiderAnimLayer != null) AnimationPlayer.playAnimation(player, oldRiderAnimLayer, null);
|
if(oldRiderAnimLayer != null) AnimationUtils.playAnimation(player, oldRiderAnimLayer, null);
|
||||||
if(newRiderAnimLayer != null) AnimationPlayer.playAnimation(player, newRiderAnimLayer, newRiderAnimation);
|
if(newRiderAnimLayer != null) AnimationUtils.playAnimation(player, newRiderAnimLayer, newRiderAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<ResourceLocation> oldLayerSet = new HashSet<>(data.getAnimations().keySet());
|
Set<ResourceLocation> oldLayerSet = new HashSet<>(data.getAnimations().keySet());
|
||||||
|
|
@ -68,15 +64,12 @@ public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
||||||
ResourceLocation newAnimLocation = newAnimString.isEmpty() ? null : new ResourceLocation(newAnimString);
|
ResourceLocation newAnimLocation = newAnimString.isEmpty() ? null : new ResourceLocation(newAnimString);
|
||||||
ResourceLocation oldAnimLocation = data.getAnimation(newLayerLocation);
|
ResourceLocation oldAnimLocation = data.getAnimation(newLayerLocation);
|
||||||
if (!Objects.equals(newAnimLocation, oldAnimLocation)) {
|
if (!Objects.equals(newAnimLocation, oldAnimLocation)) {
|
||||||
AnimationPlayer.playAnimation(player, newLayerLocation, newAnimLocation);
|
AnimationUtils.playAnimation(player, newLayerLocation, newAnimLocation);
|
||||||
}
|
}
|
||||||
oldLayerSet.remove(newLayerLocation);
|
oldLayerSet.remove(newLayerLocation);
|
||||||
}
|
}
|
||||||
for (ResourceLocation oldLayerLocation : oldLayerSet) {
|
for (ResourceLocation oldLayerLocation : oldLayerSet) {
|
||||||
AnimationPlayer.playAnimation(player, oldLayerLocation, null);
|
AnimationUtils.playAnimation(player, oldLayerLocation, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ package com.linearpast.sccore.animation.network.toclient;
|
||||||
|
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
|
@ -31,7 +31,7 @@ public record AnimationJsonPacket(String json, boolean isLayer) {
|
||||||
Map<ResourceLocation, Integer> parse = AnimLayerJson.Reader.stream(element).parse();
|
Map<ResourceLocation, Integer> parse = AnimLayerJson.Reader.stream(element).parse();
|
||||||
parse.forEach(AnimationRegistry.ClientCache::cacheAddAnimationLayer);
|
parse.forEach(AnimationRegistry.ClientCache::cacheAddAnimationLayer);
|
||||||
} else {
|
} else {
|
||||||
Animation animation = AnimJson.Reader.stream(element).parse();
|
GenericAnimationData animation = AnimJson.Reader.stream(element).parse();
|
||||||
AnimationRegistry.ClientCache.cacheAddAnimation(animation.getKey(), animation);
|
AnimationRegistry.ClientCache.cacheAddAnimation(animation.getKey(), animation);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,74 @@
|
||||||
|
package com.linearpast.sccore.animation.network.toclient;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.utils.AnimationUtils;
|
||||||
|
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
||||||
|
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
||||||
|
import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class RawAnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
||||||
|
public RawAnimationCapabilityPacket(ICapabilitySync<Player> packet) {
|
||||||
|
super(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RawAnimationCapabilityPacket(FriendlyByteBuf buf) {
|
||||||
|
super(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handler(NetworkEvent.Context context) {
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
Minecraft instance = Minecraft.getInstance();
|
||||||
|
ClientLevel level = instance.level;
|
||||||
|
if (level == null) return;
|
||||||
|
CompoundTag nbt = getData();
|
||||||
|
Player player = level.getPlayerByUUID(nbt.getUUID(SimplePlayerCapabilitySync.OwnerUUID));
|
||||||
|
if(player == null) return;
|
||||||
|
try {
|
||||||
|
RawAnimationDataCapability data = RawAnimationDataCapability.getCapability(player).orElse(null);
|
||||||
|
testPlayAnimations((AbstractClientPlayer) player, nbt, data);
|
||||||
|
syncData(nbt, data);
|
||||||
|
}catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testPlayAnimations(AbstractClientPlayer player, CompoundTag tag, RawAnimationDataCapability data) {
|
||||||
|
if(data == null) return;
|
||||||
|
ResourceLocation oldRiderAnimLayer = data.getRiderAnimLayer();
|
||||||
|
String riderAnimLayerString = tag.getString(RawAnimationDataCapability.RideAnimLayer);
|
||||||
|
ResourceLocation newRiderAnimLayer = riderAnimLayerString.isEmpty() ? null : new ResourceLocation(riderAnimLayerString);
|
||||||
|
if(!Objects.equals(oldRiderAnimLayer, newRiderAnimLayer)) {
|
||||||
|
String riderAnimationString = tag.getString(RawAnimationDataCapability.RideAnimation);
|
||||||
|
ResourceLocation newRiderAnimation = riderAnimationString.isEmpty() ? null : new ResourceLocation(riderAnimationString);
|
||||||
|
if(oldRiderAnimLayer != null) AnimationUtils.playAnimation(player, oldRiderAnimLayer, null);
|
||||||
|
if(newRiderAnimLayer != null) AnimationUtils.playAnimation(player, newRiderAnimLayer, newRiderAnimation);
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<ResourceLocation> oldLayerSet = new HashSet<>(data.getAnimations().keySet());
|
||||||
|
CompoundTag animMap = tag.getCompound(RawAnimationDataCapability.AnimMap);
|
||||||
|
for (String newLayerString : animMap.getAllKeys()) {
|
||||||
|
ResourceLocation newLayerLocation = new ResourceLocation(newLayerString);
|
||||||
|
String newAnimString = animMap.getString(newLayerString);
|
||||||
|
ResourceLocation newAnimLocation = newAnimString.isEmpty() ? null : new ResourceLocation(newAnimString);
|
||||||
|
ResourceLocation oldAnimLocation = data.getAnimation(newLayerLocation);
|
||||||
|
if (!Objects.equals(newAnimLocation, oldAnimLocation)) {
|
||||||
|
AnimationUtils.playAnimation(player, newLayerLocation, newAnimLocation);
|
||||||
|
}
|
||||||
|
oldLayerSet.remove(newLayerLocation);
|
||||||
|
}
|
||||||
|
for (ResourceLocation oldLayerLocation : oldLayerSet) {
|
||||||
|
AnimationUtils.playAnimation(player, oldLayerLocation, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.linearpast.sccore.animation.network.toclient;
|
package com.linearpast.sccore.animation.network.toclient;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
import com.linearpast.sccore.animation.event.client.ClientPlayerEvent;
|
||||||
import com.linearpast.sccore.animation.event.client.ClientPlayerTick;
|
import com.linearpast.sccore.animation.utils.AnimationUtils;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.client.player.AbstractClientPlayer;
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
|
@ -39,8 +39,8 @@ public class SyncAnimationPacket {
|
||||||
if(level == null) return;
|
if(level == null) return;
|
||||||
AbstractClientPlayer player = (AbstractClientPlayer) level.getPlayerByUUID(playerUUID);
|
AbstractClientPlayer player = (AbstractClientPlayer) level.getPlayerByUUID(playerUUID);
|
||||||
AbstractClientPlayer target = (AbstractClientPlayer) level.getPlayerByUUID(targetUUID);
|
AbstractClientPlayer target = (AbstractClientPlayer) level.getPlayerByUUID(targetUUID);
|
||||||
ClientPlayerTick.runs.put(
|
ClientPlayerEvent.runs.put(
|
||||||
() -> AnimationPlayer.syncAnimation(player, target),
|
() -> AnimationUtils.syncAnimation(player, target),
|
||||||
new AbstractMap.SimpleEntry<>(5, 0)
|
new AbstractMap.SimpleEntry<>(5, 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package com.linearpast.sccore.animation.network.toserver;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.network.HelperGetterPacket;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ApplyAnimationPacket extends HelperGetterPacket {
|
||||||
|
private final UUID targetUUID;
|
||||||
|
|
||||||
|
public ApplyAnimationPacket(UUID targetUUID) {
|
||||||
|
this.targetUUID = targetUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApplyAnimationPacket(FriendlyByteBuf buf) {
|
||||||
|
this.targetUUID = buf.readUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encode(FriendlyByteBuf buf) {
|
||||||
|
buf.writeUUID(targetUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||||
|
NetworkEvent.Context context = supplier.get();
|
||||||
|
context.enqueueWork(() -> {
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
ServerPlayer target;
|
||||||
|
ServerPlayer sender = context.getSender();
|
||||||
|
if(sender == null || sender.getServer() == null) return;
|
||||||
|
if(this.targetUUID == null) target = sender;
|
||||||
|
else target = sender.getServer().getPlayerList().getPlayer(this.targetUUID);
|
||||||
|
if(target == null) return;
|
||||||
|
IAnimationHelper<?, ?> helper = getHelper();
|
||||||
|
if(helper == null) return;
|
||||||
|
if(target == sender) return;
|
||||||
|
helper.apply(sender, target);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean filter(IAnimationHelper<?, ?> helper) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.linearpast.sccore.animation.network.toserver;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.network.HelperGetterPacket;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class InviteAnimationPacket extends HelperGetterPacket {
|
||||||
|
private final @Nullable CompoundTag animationTag;
|
||||||
|
private final ResourceLocation layer;
|
||||||
|
private final ResourceLocation animation;
|
||||||
|
private final Collection<UUID> targets;
|
||||||
|
|
||||||
|
public InviteAnimationPacket(AnimationData data, ResourceLocation layer, Collection<UUID> targets) {
|
||||||
|
this.animationTag = data.serializeNBT();
|
||||||
|
this.animation = data.getKey();
|
||||||
|
this.layer = layer;
|
||||||
|
this.targets = targets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InviteAnimationPacket(FriendlyByteBuf buf) {
|
||||||
|
this.animationTag = buf.readNullable(FriendlyByteBuf::readAnySizeNbt);
|
||||||
|
this.layer = buf.readResourceLocation();
|
||||||
|
this.animation = buf.readResourceLocation();
|
||||||
|
this.targets = buf.readList(FriendlyByteBuf::readUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encode(FriendlyByteBuf buf) {
|
||||||
|
buf.writeNullable(animationTag, FriendlyByteBuf::writeNbt);
|
||||||
|
buf.writeResourceLocation(layer);
|
||||||
|
buf.writeResourceLocation(animation);
|
||||||
|
buf.writeCollection(targets, FriendlyByteBuf::writeUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||||
|
NetworkEvent.Context context = supplier.get();
|
||||||
|
context.enqueueWork(() -> {
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
ServerPlayer sender = context.getSender();
|
||||||
|
if(sender == null) return;
|
||||||
|
IAnimationHelper<?, ?> helper = getHelper();
|
||||||
|
if(helper == null) return;
|
||||||
|
AnimationData data = helper.getAnimation(animationTag);
|
||||||
|
if(data == null) return;
|
||||||
|
if(!targets.isEmpty()) helper.invite(sender, layer, data, targets);
|
||||||
|
else helper.playAnimationWithRide(sender, layer, data, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable CompoundTag getAnimationTag() {
|
||||||
|
return animationTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ResourceLocation getAnimation() {
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.linearpast.sccore.animation.network.toserver;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.network.HelperGetterPacket;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class PlayAnimationPacket extends HelperGetterPacket {
|
||||||
|
private final @Nullable CompoundTag animationTag;
|
||||||
|
private final ResourceLocation layer;
|
||||||
|
private final ResourceLocation animation;
|
||||||
|
private final @Nullable UUID uuid;
|
||||||
|
|
||||||
|
public PlayAnimationPacket(AnimationData data, ResourceLocation layer, ResourceLocation animation, @Nullable UUID uuid) {
|
||||||
|
this.animationTag = data.serializeNBT();
|
||||||
|
this.layer = layer;
|
||||||
|
this.animation = animation;
|
||||||
|
this.uuid = uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayAnimationPacket(FriendlyByteBuf buf){
|
||||||
|
this.animationTag = buf.readNullable(FriendlyByteBuf::readAnySizeNbt);
|
||||||
|
this.layer = buf.readResourceLocation();
|
||||||
|
this.animation = buf.readResourceLocation();
|
||||||
|
this.uuid = buf.readNullable(FriendlyByteBuf::readUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encode(FriendlyByteBuf buf){
|
||||||
|
buf.writeNullable(animationTag, FriendlyByteBuf::writeNbt);
|
||||||
|
buf.writeResourceLocation(layer);
|
||||||
|
buf.writeResourceLocation(animation);
|
||||||
|
buf.writeNullable(uuid, FriendlyByteBuf::writeUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Supplier<NetworkEvent.Context> supplier){
|
||||||
|
NetworkEvent.Context context = supplier.get();
|
||||||
|
context.enqueueWork(() -> {
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
ServerPlayer target;
|
||||||
|
ServerPlayer sender = context.getSender();
|
||||||
|
if(sender == null || sender.getServer() == null) return;
|
||||||
|
if(this.uuid == null) target = sender;
|
||||||
|
else target = sender.getServer().getPlayerList().getPlayer(this.uuid);
|
||||||
|
if(target == null) return;
|
||||||
|
IAnimationHelper<?, ?> helper = getHelper();
|
||||||
|
if(helper == null) return;
|
||||||
|
AnimationData data = helper.getAnimation(animationTag);
|
||||||
|
if(data == null) return;
|
||||||
|
if(target == sender) helper.playAnimation(target, layer, data);
|
||||||
|
else helper.request(sender, target, layer, data, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable CompoundTag getAnimationTag() {
|
||||||
|
return animationTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ResourceLocation getAnimation() {
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.network.toserver;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class PlayAnimationRequestPacket {
|
|
||||||
private final ResourceLocation layer;
|
|
||||||
private @Nullable ResourceLocation animation;
|
|
||||||
private @Nullable UUID uuid;
|
|
||||||
public PlayAnimationRequestPacket(@Nullable UUID uuid, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
|
||||||
this.layer = layer;
|
|
||||||
this.animation = animation;
|
|
||||||
this.uuid = uuid;
|
|
||||||
}
|
|
||||||
public PlayAnimationRequestPacket(FriendlyByteBuf buf){
|
|
||||||
this.layer = buf.readResourceLocation();
|
|
||||||
try {
|
|
||||||
this.animation = buf.readResourceLocation();
|
|
||||||
this.uuid = buf.readUUID();
|
|
||||||
} catch (Exception e) {
|
|
||||||
this.animation = null;
|
|
||||||
this.uuid = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public void encode(FriendlyByteBuf buf){
|
|
||||||
buf.writeResourceLocation(layer);
|
|
||||||
if(animation != null) buf.writeResourceLocation(animation);
|
|
||||||
if(uuid != null) buf.writeUUID(uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handle(Supplier<NetworkEvent.Context> supplier){
|
|
||||||
NetworkEvent.Context context = supplier.get();
|
|
||||||
context.enqueueWork(() -> {
|
|
||||||
context.setPacketHandled(true);
|
|
||||||
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
|
||||||
ServerPlayer target;
|
|
||||||
ServerPlayer sender = context.getSender();
|
|
||||||
if(sender == null || sender.getServer() == null) return;
|
|
||||||
if(this.uuid == null) target = sender;
|
|
||||||
else target = sender.getServer().getPlayerList().getPlayer(this.uuid);
|
|
||||||
AnimationPlayer.serverPlayAnimation(target, layer, animation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +1,75 @@
|
||||||
package com.linearpast.sccore.animation.network.toserver;
|
package com.linearpast.sccore.animation.network.toserver;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.network.HelperGetterPacket;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class PlayAnimationRidePacket {
|
public class PlayAnimationRidePacket extends HelperGetterPacket {
|
||||||
|
private final @Nullable CompoundTag animationTag;
|
||||||
private final ResourceLocation layer;
|
private final ResourceLocation layer;
|
||||||
private @Nullable ResourceLocation animation;
|
private final ResourceLocation animation;
|
||||||
|
private final @Nullable UUID uuid;
|
||||||
private final boolean force;
|
private final boolean force;
|
||||||
public PlayAnimationRidePacket(ResourceLocation layer, @Nullable ResourceLocation animation, boolean force) {
|
|
||||||
|
public PlayAnimationRidePacket(AnimationData data, ResourceLocation layer, ResourceLocation animation, @Nullable UUID uuid, boolean force) {
|
||||||
|
this.animationTag = data.serializeNBT();
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
this.animation = animation;
|
this.animation = animation;
|
||||||
|
this.uuid = uuid;
|
||||||
this.force = force;
|
this.force = force;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayAnimationRidePacket(FriendlyByteBuf buf) {
|
public PlayAnimationRidePacket(FriendlyByteBuf buf) {
|
||||||
|
this.animationTag = buf.readNullable(FriendlyByteBuf::readAnySizeNbt);
|
||||||
this.layer = buf.readResourceLocation();
|
this.layer = buf.readResourceLocation();
|
||||||
this.force = buf.readBoolean();
|
|
||||||
try {
|
|
||||||
this.animation = buf.readResourceLocation();
|
this.animation = buf.readResourceLocation();
|
||||||
} catch (Exception e) {
|
this.uuid = buf.readNullable(FriendlyByteBuf::readUUID);
|
||||||
this.animation = null;
|
this.force = buf.readBoolean();
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void encode(FriendlyByteBuf buf) {
|
public void encode(FriendlyByteBuf buf) {
|
||||||
|
buf.writeNullable(animationTag, FriendlyByteBuf::writeNbt);
|
||||||
buf.writeResourceLocation(layer);
|
buf.writeResourceLocation(layer);
|
||||||
buf.writeBoolean(force);
|
|
||||||
if(animation != null) {
|
|
||||||
buf.writeResourceLocation(animation);
|
buf.writeResourceLocation(animation);
|
||||||
}
|
buf.writeNullable(uuid, FriendlyByteBuf::writeUUID);
|
||||||
|
buf.writeBoolean(force);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||||
NetworkEvent.Context context = supplier.get();
|
NetworkEvent.Context context = supplier.get();
|
||||||
context.enqueueWork(() -> {
|
context.enqueueWork(() -> {
|
||||||
context.setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
ServerPlayer target;
|
||||||
ServerPlayer sender = context.getSender();
|
ServerPlayer sender = context.getSender();
|
||||||
if(sender == null) return;
|
if(sender == null || sender.getServer() == null) return;
|
||||||
AnimationPlayer.playAnimationWithRide(sender, layer, animation, force);
|
if(this.uuid == null) target = sender;
|
||||||
}
|
else target = sender.getServer().getPlayerList().getPlayer(this.uuid);
|
||||||
|
if(target == null) return;
|
||||||
|
IAnimationHelper<?, ?> helper = getHelper();
|
||||||
|
if(helper == null) return;
|
||||||
|
AnimationData data = helper.getAnimation(animationTag);
|
||||||
|
if(data == null) return;
|
||||||
|
if(target == sender) helper.playAnimationWithRide(target, layer, data, force);
|
||||||
|
else helper.request(sender, target, layer, data, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable CompoundTag getAnimationTag() {
|
||||||
|
return animationTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ResourceLocation getAnimation() {
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
package com.linearpast.sccore.animation.network.toserver;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
public class RefreshAnimationPacket {
|
|
||||||
private final Set<ResourceLocation> needRemoves;
|
|
||||||
public RefreshAnimationPacket(Set<ResourceLocation> needRemoves) {
|
|
||||||
this.needRemoves = needRemoves;
|
|
||||||
}
|
|
||||||
public RefreshAnimationPacket(FriendlyByteBuf buf) {
|
|
||||||
int i = buf.readInt();
|
|
||||||
needRemoves = new HashSet<>();
|
|
||||||
for (int j = 0; j < i; ++j) {
|
|
||||||
needRemoves.add(buf.readResourceLocation());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void encode(FriendlyByteBuf buf) {
|
|
||||||
buf.writeInt(needRemoves.size());
|
|
||||||
for (ResourceLocation needRemove : needRemoves) {
|
|
||||||
buf.writeResourceLocation(needRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
|
||||||
NetworkEvent.Context context = supplier.get();
|
|
||||||
context.enqueueWork(() -> {
|
|
||||||
context.setPacketHandled(true);
|
|
||||||
ServerPlayer sender = context.getSender();
|
|
||||||
if(sender == null) return;
|
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(sender).orElse(null);
|
|
||||||
if(data == null) return;
|
|
||||||
needRemoves.forEach(data::removeAnimation);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package com.linearpast.sccore.animation.network.toserver;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.animation.data.AnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.network.HelperGetterPacket;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class RequestAnimationPacket extends HelperGetterPacket {
|
||||||
|
private final @Nullable CompoundTag animationTag;
|
||||||
|
private final ResourceLocation layer;
|
||||||
|
private final ResourceLocation animation;
|
||||||
|
private final UUID targetUUID;
|
||||||
|
|
||||||
|
public RequestAnimationPacket(AnimationData data, ResourceLocation layer, UUID targetUUID) {
|
||||||
|
this.animationTag = data.serializeNBT();
|
||||||
|
this.animation = data.getKey();
|
||||||
|
this.layer = layer;
|
||||||
|
this.targetUUID = targetUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequestAnimationPacket(FriendlyByteBuf buf) {
|
||||||
|
this.animationTag = buf.readNullable(FriendlyByteBuf::readAnySizeNbt);
|
||||||
|
this.layer = buf.readResourceLocation();
|
||||||
|
this.animation = buf.readResourceLocation();
|
||||||
|
this.targetUUID = buf.readUUID();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void encode(FriendlyByteBuf buf) {
|
||||||
|
buf.writeNullable(animationTag, FriendlyByteBuf::writeNbt);
|
||||||
|
buf.writeResourceLocation(layer);
|
||||||
|
buf.writeResourceLocation(animation);
|
||||||
|
buf.writeUUID(targetUUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||||
|
NetworkEvent.Context context = supplier.get();
|
||||||
|
context.enqueueWork(() -> {
|
||||||
|
context.setPacketHandled(true);
|
||||||
|
ServerPlayer target;
|
||||||
|
ServerPlayer sender = context.getSender();
|
||||||
|
if(sender == null || sender.getServer() == null) return;
|
||||||
|
if(this.targetUUID == null) target = sender;
|
||||||
|
else target = sender.getServer().getPlayerList().getPlayer(this.targetUUID);
|
||||||
|
if(target == null) return;
|
||||||
|
IAnimationHelper<?, ?> helper = getHelper();
|
||||||
|
if(helper == null) return;
|
||||||
|
AnimationData data = helper.getAnimation(animationTag);
|
||||||
|
if(data == null) return;
|
||||||
|
if(target == sender) return;
|
||||||
|
helper.request(sender, target, layer, data, false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable CompoundTag getAnimationTag() {
|
||||||
|
return animationTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable ResourceLocation getAnimation() {
|
||||||
|
return animation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package com.linearpast.sccore.animation.register;
|
package com.linearpast.sccore.animation.register;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
||||||
|
import com.linearpast.sccore.animation.network.toclient.RawAnimationCapabilityPacket;
|
||||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||||
import com.linearpast.sccore.capability.data.player.PlayerCapabilityRegistry;
|
import com.linearpast.sccore.capability.data.player.PlayerCapabilityRegistry;
|
||||||
import com.linearpast.sccore.capability.network.CapabilityChannel;
|
import com.linearpast.sccore.capability.network.CapabilityChannel;
|
||||||
|
|
@ -27,5 +29,19 @@ public class AnimationCapabilities {
|
||||||
AnimationCapabilityPacket::encode,
|
AnimationCapabilityPacket::encode,
|
||||||
AnimationCapabilityPacket::handle
|
AnimationCapabilityPacket::handle
|
||||||
);
|
);
|
||||||
|
CapabilityUtils.registerPlayerCapabilityWithNetwork(
|
||||||
|
RawAnimationDataCapability.key,
|
||||||
|
new PlayerCapabilityRegistry.CapabilityRecord<>(
|
||||||
|
RawAnimationDataCapability.class,
|
||||||
|
CapabilityManager.get(new CapabilityToken<>() {}),
|
||||||
|
RawAnimationDataCapability.class
|
||||||
|
),
|
||||||
|
channel,
|
||||||
|
ModChannel.getAndAddCid(),
|
||||||
|
RawAnimationCapabilityPacket.class,
|
||||||
|
RawAnimationCapabilityPacket::new,
|
||||||
|
RawAnimationCapabilityPacket::encode,
|
||||||
|
RawAnimationCapabilityPacket::handle
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,44 +3,57 @@ package com.linearpast.sccore.animation.register;
|
||||||
import com.linearpast.sccore.animation.network.toclient.AnimationClientStatusPacket;
|
import com.linearpast.sccore.animation.network.toclient.AnimationClientStatusPacket;
|
||||||
import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
||||||
import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
||||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRequestPacket;
|
import com.linearpast.sccore.animation.network.toserver.*;
|
||||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRidePacket;
|
|
||||||
import com.linearpast.sccore.animation.network.toserver.RefreshAnimationPacket;
|
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
import com.linearpast.sccore.core.ModChannel;
|
||||||
import net.minecraftforge.network.NetworkDirection;
|
import net.minecraftforge.network.NetworkDirection;
|
||||||
|
|
||||||
public class AnimationChannels {
|
public class AnimationChannels {
|
||||||
public static void registerChannel() {
|
public static void registerChannel() {
|
||||||
ModChannel.INSTANCE.messageBuilder(SyncAnimationPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
ModChannel.INSTANCE.messageBuilder(SyncAnimationPacket.class, cid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||||
.decoder(SyncAnimationPacket::new)
|
.decoder(SyncAnimationPacket::new)
|
||||||
.encoder(SyncAnimationPacket::encode)
|
.encoder(SyncAnimationPacket::encode)
|
||||||
.consumerMainThread(SyncAnimationPacket::handle)
|
.consumerMainThread(SyncAnimationPacket::handle)
|
||||||
.add();
|
.add();
|
||||||
ModChannel.INSTANCE.messageBuilder(AnimationJsonPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
ModChannel.INSTANCE.messageBuilder(AnimationJsonPacket.class, cid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||||
.decoder(AnimationJsonPacket::new)
|
.decoder(AnimationJsonPacket::new)
|
||||||
.encoder(AnimationJsonPacket::encode)
|
.encoder(AnimationJsonPacket::encode)
|
||||||
.consumerMainThread(AnimationJsonPacket::handle)
|
.consumerMainThread(AnimationJsonPacket::handle)
|
||||||
.add();
|
.add();
|
||||||
ModChannel.INSTANCE.messageBuilder(AnimationClientStatusPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
ModChannel.INSTANCE.messageBuilder(AnimationClientStatusPacket.class, cid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||||
.decoder(AnimationClientStatusPacket::new)
|
.decoder(AnimationClientStatusPacket::new)
|
||||||
.encoder(AnimationClientStatusPacket::encode)
|
.encoder(AnimationClientStatusPacket::encode)
|
||||||
.consumerMainThread(AnimationClientStatusPacket::handle)
|
.consumerMainThread(AnimationClientStatusPacket::handle)
|
||||||
.add();
|
.add();
|
||||||
|
|
||||||
ModChannel.INSTANCE.messageBuilder(PlayAnimationRequestPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
//To server
|
||||||
.decoder(PlayAnimationRequestPacket::new)
|
ModChannel.INSTANCE.messageBuilder(PlayAnimationPacket.class, cid(), NetworkDirection.PLAY_TO_SERVER)
|
||||||
.encoder(PlayAnimationRequestPacket::encode)
|
.decoder(PlayAnimationPacket::new)
|
||||||
.consumerMainThread(PlayAnimationRequestPacket::handle)
|
.encoder(PlayAnimationPacket::encode)
|
||||||
|
.consumerMainThread(PlayAnimationPacket::handle)
|
||||||
.add();
|
.add();
|
||||||
ModChannel.INSTANCE.messageBuilder(PlayAnimationRidePacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
ModChannel.INSTANCE.messageBuilder(PlayAnimationRidePacket.class, cid(), NetworkDirection.PLAY_TO_SERVER)
|
||||||
.decoder(PlayAnimationRidePacket::new)
|
.decoder(PlayAnimationRidePacket::new)
|
||||||
.encoder(PlayAnimationRidePacket::encode)
|
.encoder(PlayAnimationRidePacket::encode)
|
||||||
.consumerMainThread(PlayAnimationRidePacket::handle)
|
.consumerMainThread(PlayAnimationRidePacket::handle)
|
||||||
.add();
|
.add();
|
||||||
ModChannel.INSTANCE.messageBuilder(RefreshAnimationPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
ModChannel.INSTANCE.messageBuilder(ApplyAnimationPacket.class, cid(), NetworkDirection.PLAY_TO_SERVER)
|
||||||
.decoder(RefreshAnimationPacket::new)
|
.decoder(ApplyAnimationPacket::new)
|
||||||
.encoder(RefreshAnimationPacket::encode)
|
.encoder(ApplyAnimationPacket::encode)
|
||||||
.consumerMainThread(RefreshAnimationPacket::handle)
|
.consumerMainThread(ApplyAnimationPacket::handle)
|
||||||
|
.add();
|
||||||
|
ModChannel.INSTANCE.messageBuilder(InviteAnimationPacket.class, cid(), NetworkDirection.PLAY_TO_SERVER)
|
||||||
|
.decoder(InviteAnimationPacket::new)
|
||||||
|
.encoder(InviteAnimationPacket::encode)
|
||||||
|
.consumerMainThread(InviteAnimationPacket::handle)
|
||||||
|
.add();
|
||||||
|
ModChannel.INSTANCE.messageBuilder(RequestAnimationPacket.class, cid(), NetworkDirection.PLAY_TO_SERVER)
|
||||||
|
.decoder(RequestAnimationPacket::new)
|
||||||
|
.encoder(RequestAnimationPacket::encode)
|
||||||
|
.consumerMainThread(RequestAnimationPacket::handle)
|
||||||
.add();
|
.add();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int cid() {
|
||||||
|
return ModChannel.getAndAddCid();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
package com.linearpast.sccore.animation.register;
|
package com.linearpast.sccore.animation.register;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.command.*;
|
import com.linearpast.sccore.animation.command.*;
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||||
import com.linearpast.sccore.animation.command.client.GenerateJsonClientCommand;
|
import com.linearpast.sccore.animation.command.client.ListClientCommand;
|
||||||
import com.linearpast.sccore.animation.command.client.RefreshAnimCommand;
|
import com.linearpast.sccore.animation.command.client.RefreshCommand;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
import net.minecraft.commands.CommandSourceStack;
|
||||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||||
|
|
@ -17,34 +17,35 @@ import static net.minecraft.commands.Commands.literal;
|
||||||
|
|
||||||
public class AnimationCommands {
|
public class AnimationCommands {
|
||||||
public static void commonCommandRegister(LiteralArgumentBuilder<CommandSourceStack> builder) {
|
public static void commonCommandRegister(LiteralArgumentBuilder<CommandSourceStack> builder) {
|
||||||
if(AnimationUtils.ANIMATION_RUNNER.isModLoaded()){
|
if(IAnimationHelper.ANIMATION_RUNNER.isModLoaded()){
|
||||||
LiteralArgumentBuilder<CommandSourceStack> anim = literal("anim");
|
LiteralArgumentBuilder<CommandSourceStack> anim = literal("anim");
|
||||||
PlayAnimCommand.register(anim);
|
ApplyCommand.register(anim);
|
||||||
RequestAnimCommand.register(anim);
|
InviteCommand.register(anim);
|
||||||
CombineAnimCommand.register(anim);
|
JsonCommand.register(anim);
|
||||||
GenerateJsonCommand.register(anim);
|
ListServerCommand.register(anim);
|
||||||
ApplyJoinAnimCommand.register(anim);
|
PlayCommand.register(anim);
|
||||||
|
RequestCommand.register(anim);
|
||||||
builder.then(anim);
|
builder.then(anim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clientCommandRegister(LiteralArgumentBuilder<CommandSourceStack> builder) {
|
public static void clientCommandRegister(LiteralArgumentBuilder<CommandSourceStack> builder) {
|
||||||
if(AnimationUtils.ANIMATION_RUNNER.isModLoaded()) {
|
if(IAnimationHelper.ANIMATION_RUNNER.isModLoaded()) {
|
||||||
LiteralArgumentBuilder<CommandSourceStack> anim = literal("anim");
|
LiteralArgumentBuilder<CommandSourceStack> anim = literal("anim");
|
||||||
RefreshAnimCommand.register(anim);
|
ListClientCommand.register(anim);
|
||||||
GenerateJsonClientCommand.register(anim);
|
RefreshCommand.register(anim);
|
||||||
builder.then(anim);
|
builder.then(anim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerArguments(DeferredRegister<ArgumentTypeInfo<?, ?>> register) {
|
public static void registerArguments(DeferredRegister<ArgumentTypeInfo<?, ?>> register) {
|
||||||
register.register("animation",
|
register.register("animations",
|
||||||
() -> ArgumentTypeInfos.registerByClass(
|
() -> ArgumentTypeInfos.registerByClass(
|
||||||
AnimationArgument.class,
|
AnimationArgument.class,
|
||||||
SingletonArgumentInfo.contextFree(AnimationArgument::animation)
|
SingletonArgumentInfo.contextFree(AnimationArgument::animation)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
register.register("layer",
|
register.register("layers",
|
||||||
() -> ArgumentTypeInfos.registerByClass(
|
() -> ArgumentTypeInfos.registerByClass(
|
||||||
AnimationLayerArgument.class,
|
AnimationLayerArgument.class,
|
||||||
SingletonArgumentInfo.contextFree(AnimationLayerArgument::layer)
|
SingletonArgumentInfo.contextFree(AnimationLayerArgument::layer)
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,26 @@ package com.linearpast.sccore.animation.register;
|
||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||||
import com.linearpast.sccore.animation.event.create.AnimationLayerRegisterEvent;
|
|
||||||
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
||||||
|
import com.linearpast.sccore.animation.helper.RawAnimationHelper;
|
||||||
import com.linearpast.sccore.animation.mixin.IMixinPlayerAnimationFactoryHolder;
|
import com.linearpast.sccore.animation.mixin.IMixinPlayerAnimationFactoryHolder;
|
||||||
import com.linearpast.sccore.animation.network.toclient.AnimationClientStatusPacket;
|
import com.linearpast.sccore.animation.network.toclient.AnimationClientStatusPacket;
|
||||||
import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
import com.linearpast.sccore.core.ModChannel;
|
||||||
|
import com.linearpast.sccore.utils.ModuleAccess;
|
||||||
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
||||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||||
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
||||||
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
||||||
|
import dev.kosmx.playerAnim.api.layered.modifier.AbstractFadeModifier;
|
||||||
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||||
|
import dev.kosmx.playerAnim.core.util.Ease;
|
||||||
import dev.kosmx.playerAnim.core.util.Pair;
|
import dev.kosmx.playerAnim.core.util.Pair;
|
||||||
import dev.kosmx.playerAnim.impl.animation.AnimationApplier;
|
import dev.kosmx.playerAnim.impl.animation.AnimationApplier;
|
||||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
||||||
|
|
@ -35,6 +40,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||||
|
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
@ -53,10 +59,10 @@ import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
|
|
||||||
public class AnimationRegistry {
|
public class AnimationRegistry {
|
||||||
private static final Map<ResourceLocation, Animation> animations = new HashMap<>();
|
private static final Map<ResourceLocation, GenericAnimationData> animations = new HashMap<>();
|
||||||
private static final Map<ResourceLocation, Integer> layers = new HashMap<>();
|
private static final Map<ResourceLocation, Integer> layers = new HashMap<>();
|
||||||
|
|
||||||
public static Map<ResourceLocation, Animation> getAnimations() {
|
public static Map<ResourceLocation, GenericAnimationData> getAnimations() {
|
||||||
return Map.copyOf(animations);
|
return Map.copyOf(animations);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,7 +71,7 @@ public class AnimationRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public static void registerAnimations(Map<ResourceLocation, Animation> animationMap) {
|
public static void registerAnimations(Map<ResourceLocation, GenericAnimationData> animationMap) {
|
||||||
animations.clear();
|
animations.clear();
|
||||||
animations.putAll(animationMap);
|
animations.putAll(animationMap);
|
||||||
}
|
}
|
||||||
|
|
@ -76,6 +82,7 @@ public class AnimationRegistry {
|
||||||
layers.putAll(layerMap);
|
layers.putAll(layerMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
public static void onServerStarted(ServerStartedEvent event) {
|
public static void onServerStarted(ServerStartedEvent event) {
|
||||||
Path dataPackPath = event.getServer().getWorldPath(LevelResource.DATAPACK_DIR);
|
Path dataPackPath = event.getServer().getWorldPath(LevelResource.DATAPACK_DIR);
|
||||||
Path animationPath = dataPackPath.resolve("animation");
|
Path animationPath = dataPackPath.resolve("animation");
|
||||||
|
|
@ -109,12 +116,12 @@ public class AnimationRegistry {
|
||||||
dataPackPath.resolve("animation"),
|
dataPackPath.resolve("animation"),
|
||||||
path -> path.getFileName().toString().equals("animation.layer.json")
|
path -> path.getFileName().toString().equals("animation.layer.json")
|
||||||
);
|
);
|
||||||
Set<Animation> animationsSet = new HashSet<>();
|
Set<GenericAnimationData> animationsSet = new HashSet<>();
|
||||||
Map<ResourceLocation, Integer> layersMap = new HashMap<>();
|
Map<ResourceLocation, Integer> layersMap = new HashMap<>();
|
||||||
for (Path path : animPaths) {
|
for (Path path : animPaths) {
|
||||||
try {
|
try {
|
||||||
AnimJson.Reader reader = AnimJson.Reader.stream(path);
|
AnimJson.Reader reader = AnimJson.Reader.stream(path);
|
||||||
Animation anim = reader.parse();
|
GenericAnimationData anim = reader.parse();
|
||||||
animationsSet.add(anim);
|
animationsSet.add(anim);
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
SnowyCrescentCore.log.error("Failed to parse animation JSON: {}", path.toString());
|
SnowyCrescentCore.log.error("Failed to parse animation JSON: {}", path.toString());
|
||||||
|
|
@ -131,20 +138,21 @@ public class AnimationRegistry {
|
||||||
}
|
}
|
||||||
|
|
||||||
animations.clear();
|
animations.clear();
|
||||||
AnimationRegisterEvent animationRegisterEvent = new AnimationRegisterEvent();
|
AnimationRegisterEvent.Animation animationRegisterEvent = new AnimationRegisterEvent.Animation();
|
||||||
MinecraftForge.EVENT_BUS.post(animationRegisterEvent);
|
MinecraftForge.EVENT_BUS.post(animationRegisterEvent);
|
||||||
Map<ResourceLocation, Animation> animationMap = animationRegisterEvent.getAnimations();
|
Map<ResourceLocation, GenericAnimationData> animationMap = animationRegisterEvent.getAnimations();
|
||||||
animations.putAll(animationMap);
|
animations.putAll(animationMap);
|
||||||
animations.putAll(animationsSet.stream().collect(Collectors.toMap(Animation::getKey, animation -> animation)));
|
animations.putAll(animationsSet.stream().collect(Collectors.toMap(GenericAnimationData::getKey, animation -> animation)));
|
||||||
|
|
||||||
layers.clear();
|
layers.clear();
|
||||||
AnimationLayerRegisterEvent layerRegisterEvent = new AnimationLayerRegisterEvent();
|
AnimationRegisterEvent.Layer layerRegisterEvent = new AnimationRegisterEvent.Layer();
|
||||||
MinecraftForge.EVENT_BUS.post(layerRegisterEvent);
|
MinecraftForge.EVENT_BUS.post(layerRegisterEvent);
|
||||||
Map<ResourceLocation, Integer> layerMap = layerRegisterEvent.getLayers();
|
Map<ResourceLocation, Integer> layerMap = layerRegisterEvent.getLayers();
|
||||||
layers.putAll(layerMap);
|
layers.putAll(layerMap);
|
||||||
layers.putAll(layersMap);
|
layers.putAll(layersMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SubscribeEvent
|
||||||
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
|
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
|
||||||
if (event.getEntity() instanceof ServerPlayer serverPlayer) {
|
if (event.getEntity() instanceof ServerPlayer serverPlayer) {
|
||||||
MinecraftServer server = serverPlayer.getServer();
|
MinecraftServer server = serverPlayer.getServer();
|
||||||
|
|
@ -156,7 +164,7 @@ public class AnimationRegistry {
|
||||||
catch (IOException e) { return; }
|
catch (IOException e) { return; }
|
||||||
}
|
}
|
||||||
ModChannel.sendToPlayer(new AnimationClientStatusPacket(AnimationClientStatusPacket.Status.ANIM_CACHE_CLEAR), serverPlayer);
|
ModChannel.sendToPlayer(new AnimationClientStatusPacket(AnimationClientStatusPacket.Status.ANIM_CACHE_CLEAR), serverPlayer);
|
||||||
for (Animation value : animations.values()) {
|
for (GenericAnimationData value : animations.values()) {
|
||||||
JsonElement json = AnimJson.Writer.stream(value).toJson();
|
JsonElement json = AnimJson.Writer.stream(value).toJson();
|
||||||
String string = json.toString();
|
String string = json.toString();
|
||||||
ModChannel.sendToPlayer(new AnimationJsonPacket(string, false), serverPlayer);
|
ModChannel.sendToPlayer(new AnimationJsonPacket(string, false), serverPlayer);
|
||||||
|
|
@ -213,10 +221,11 @@ public class AnimationRegistry {
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public static class ClientCache {
|
public static class ClientCache {
|
||||||
private static final Map<ResourceLocation, Animation> animationsCache = new HashMap<>();
|
public static boolean isAnimationRegistered = false;
|
||||||
|
private static final Map<ResourceLocation, GenericAnimationData> animationsCache = new HashMap<>();
|
||||||
private static final Map<ResourceLocation, Integer> layersCache = new HashMap<>();
|
private static final Map<ResourceLocation, Integer> layersCache = new HashMap<>();
|
||||||
|
|
||||||
public static void cacheAddAnimation(ResourceLocation location, Animation animation) {
|
public static void cacheAddAnimation(ResourceLocation location, GenericAnimationData animation) {
|
||||||
animationsCache.put(location, animation);
|
animationsCache.put(location, animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,7 +242,11 @@ public class AnimationRegistry {
|
||||||
.sccore$clearAnimations();
|
.sccore$clearAnimations();
|
||||||
layersCache.clear();
|
layersCache.clear();
|
||||||
}
|
}
|
||||||
case ANIM_REGISTER -> registerAnimations(animationsCache);
|
case ANIM_REGISTER -> {
|
||||||
|
isAnimationRegistered = true;
|
||||||
|
registerAnimations(animationsCache);
|
||||||
|
RawAnimationRegistry.triggerRegistry();
|
||||||
|
}
|
||||||
case LAYER_REGISTER -> {
|
case LAYER_REGISTER -> {
|
||||||
registerLayers(layersCache);
|
registerLayers(layersCache);
|
||||||
layersCache.forEach((key, value) ->
|
layersCache.forEach((key, value) ->
|
||||||
|
|
@ -246,9 +259,14 @@ public class AnimationRegistry {
|
||||||
SnowyCrescentCore.log.error("{} : Level is null", ClientCache.class.getName());
|
SnowyCrescentCore.log.error("{} : Level is null", ClientCache.class.getName());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
ModuleAccess.open(
|
||||||
|
Player.class.getModule(),
|
||||||
|
Player.class.getPackageName(),
|
||||||
|
AnimationRegistry.class.getModule()
|
||||||
|
);
|
||||||
for (AbstractClientPlayer player : level.players()) {
|
for (AbstractClientPlayer player : level.players()) {
|
||||||
try {
|
try {
|
||||||
if (player == null) throw new Exception("player is null");
|
|
||||||
Class<?> playerClass = Player.class;
|
Class<?> playerClass = Player.class;
|
||||||
Field animationStackField = playerClass.getDeclaredField("animationStack");
|
Field animationStackField = playerClass.getDeclaredField("animationStack");
|
||||||
animationStackField.setAccessible(true);
|
animationStackField.setAccessible(true);
|
||||||
|
|
@ -269,24 +287,43 @@ public class AnimationRegistry {
|
||||||
animationApplierField.setAccessible(true);
|
animationApplierField.setAccessible(true);
|
||||||
animationApplierField.set(player, new AnimationApplier(newAnimationStack));
|
animationApplierField.set(player, new AnimationApplier(newAnimationStack));
|
||||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||||
if(data == null) return;
|
if(data == null) continue;
|
||||||
Map<ResourceLocation, ResourceLocation> dataAnimations = data.getAnimations();
|
RawAnimationDataCapability rawData = RawAnimationDataCapability.getCapability(player).orElse(null);
|
||||||
|
if(rawData == null) continue;
|
||||||
|
Map<ResourceLocation, ResourceLocation> dataAnimations = new HashMap<>();
|
||||||
|
dataAnimations.putAll(data.getAnimations());
|
||||||
|
dataAnimations.putAll(rawData.getAnimations());
|
||||||
ResourceLocation riderAnimLayer = data.getRiderAnimLayer();
|
ResourceLocation riderAnimLayer = data.getRiderAnimLayer();
|
||||||
if(riderAnimLayer != null) {
|
if(riderAnimLayer != null) {
|
||||||
dataAnimations.put(riderAnimLayer, data.getRiderAnimation());
|
dataAnimations.put(riderAnimLayer, data.getRiderAnimation());
|
||||||
}
|
}
|
||||||
|
ResourceLocation rawRiderAnimLayer = rawData.getRiderAnimLayer();
|
||||||
|
if(rawRiderAnimLayer != null) {
|
||||||
|
dataAnimations.put(rawRiderAnimLayer, rawData.getRiderAnimation());
|
||||||
|
}
|
||||||
for (ResourceLocation location : dataAnimations.keySet()) {
|
for (ResourceLocation location : dataAnimations.keySet()) {
|
||||||
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||||
.getPlayerAssociatedData(player).get(location);
|
.getPlayerAssociatedData(player).get(location);
|
||||||
if(modifierLayer == null) continue;
|
if(modifierLayer == null) continue;
|
||||||
KeyframeAnimation animation = animations.get(dataAnimations.get(location)).getAnimation();
|
KeyframeAnimation keyframeAnimation;
|
||||||
if(animation == null) continue;
|
ResourceLocation animationLocation = dataAnimations.get(location);
|
||||||
modifierLayer.setAnimation(new KeyframeAnimationPlayer(animation));
|
GenericAnimationData anim = animations.get(animationLocation);
|
||||||
|
if(anim == null) {
|
||||||
|
RawAnimationData rawAnim = RawAnimationHelper.INSTANCE.getAnimation(animationLocation);
|
||||||
|
if(rawAnim == null) return;
|
||||||
|
keyframeAnimation = rawAnim.getAnimation();
|
||||||
|
} else keyframeAnimation = anim.getAnimation();
|
||||||
|
if(keyframeAnimation == null) continue;
|
||||||
|
modifierLayer.replaceAnimationWithFade(
|
||||||
|
AbstractFadeModifier.standardFadeIn(3, Ease.INOUTSINE),
|
||||||
|
new KeyframeAnimationPlayer(keyframeAnimation)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
SnowyCrescentCore.log.error("Failed to register on {} animation layer: {}", player, e.getMessage(), e);
|
SnowyCrescentCore.log.error("Failed to register on {} animation layer: {}", player, e.getMessage(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,64 @@
|
||||||
|
package com.linearpast.sccore.animation.register;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public class RawAnimationRegistry {
|
||||||
|
private static final Map<ResourceLocation, RawAnimationData> animations = new HashMap<>();
|
||||||
|
|
||||||
|
public static Map<ResourceLocation, RawAnimationData> getAnimations() {
|
||||||
|
return Map.copyOf(animations);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerAnimations(Map<ResourceLocation, RawAnimationData> animationMap) {
|
||||||
|
animations.clear();
|
||||||
|
Map.copyOf(animationMap).keySet().forEach(location -> {
|
||||||
|
if(!validateLocation(location)) animations.remove(location);
|
||||||
|
});
|
||||||
|
animations.putAll(animationMap);
|
||||||
|
AnimationArgument.resetAnimationNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean register(ResourceLocation location, RawAnimationData rawAnimation) {
|
||||||
|
if (validateLocation(location)) {
|
||||||
|
animations.put(location, rawAnimation);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void triggerRegistry() {
|
||||||
|
resetAnimations();
|
||||||
|
AnimationRegisterEvent.RawAnimation event = new AnimationRegisterEvent.RawAnimation();
|
||||||
|
MinecraftForge.EVENT_BUS.post(event);
|
||||||
|
registerAnimations(event.getAnimations());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void resetAnimations() {
|
||||||
|
animations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean validateLocation(ResourceLocation location) {
|
||||||
|
try {
|
||||||
|
if(!AnimationRegistry.ClientCache.isAnimationRegistered)
|
||||||
|
throw new RuntimeException("Server animation is not registered!");
|
||||||
|
if(AnimationRegistry.getAnimations().containsKey(location))
|
||||||
|
throw new RuntimeException("Duplicated animation on server: " + location);
|
||||||
|
return true;
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
SnowyCrescentCore.log.error(e.getMessage(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
package com.linearpast.sccore.animation.utils;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.capability.RawAnimationDataCapability;
|
||||||
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.IAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.RawAnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.mixin.IMixinKeyframeAnimationPlayer;
|
||||||
|
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||||
|
import com.linearpast.sccore.core.datagen.ModLang;
|
||||||
|
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||||
|
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
||||||
|
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
||||||
|
import dev.kosmx.playerAnim.api.layered.modifier.AbstractFadeModifier;
|
||||||
|
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||||
|
import dev.kosmx.playerAnim.core.util.Ease;
|
||||||
|
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
||||||
|
import net.minecraft.ChatFormatting;
|
||||||
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
public class AnimationUtils {
|
||||||
|
/**
|
||||||
|
* Test if layer exist animation which is not end. <br>
|
||||||
|
* Only in dist client
|
||||||
|
* @param player Target player
|
||||||
|
* @param layer Target layer
|
||||||
|
* @return True when animation is loop, or currentTick not larger than endTick
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static boolean isClientAnimationNotEnd(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
||||||
|
return IAnimationHelper.ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
try {
|
||||||
|
Set<ResourceLocation> resourceLocations = new HashSet<>();
|
||||||
|
if(layer == null) resourceLocations.addAll(AnimationRegistry.getLayers().keySet());
|
||||||
|
else resourceLocations.add(layer);
|
||||||
|
for (ResourceLocation location : resourceLocations) {
|
||||||
|
ModifierLayer<IAnimation> animationModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||||
|
.getPlayerAssociatedData(player).get(location);
|
||||||
|
if(animationModifierLayer == null) continue;
|
||||||
|
KeyframeAnimationPlayer animation = (KeyframeAnimationPlayer) animationModifierLayer.getAnimation();
|
||||||
|
if(animation == null) return false;
|
||||||
|
int currentTick = animation.getCurrentTick();
|
||||||
|
boolean isLoop = animation.getData().isInfinite;
|
||||||
|
int endTick = animation.getData().endTick;
|
||||||
|
return isLoop || currentTick <= endTick;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test if layer exist animation which is not stop. <br>
|
||||||
|
* Only in dist client
|
||||||
|
* @param player Target player
|
||||||
|
* @param layer Target layer
|
||||||
|
* @return True when the currentTick not larger than stopTick
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static boolean isClientAnimationStop(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
||||||
|
return IAnimationHelper.ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||||
|
try {
|
||||||
|
Set<ResourceLocation> resourceLocations = new HashSet<>();
|
||||||
|
if(layer == null) resourceLocations.addAll(AnimationRegistry.getLayers().keySet());
|
||||||
|
else resourceLocations.add(layer);
|
||||||
|
for (ResourceLocation location : resourceLocations) {
|
||||||
|
ModifierLayer<IAnimation> animationModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||||
|
.getPlayerAssociatedData(player).get(location);
|
||||||
|
if(animationModifierLayer == null) continue;
|
||||||
|
KeyframeAnimationPlayer animation = (KeyframeAnimationPlayer) animationModifierLayer.getAnimation();
|
||||||
|
if(animation == null) return false;
|
||||||
|
int currentTick = animation.getCurrentTick();
|
||||||
|
int stopTick = animation.getStopTick();
|
||||||
|
return currentTick > stopTick;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client sync animation
|
||||||
|
* @param clientPlayer player
|
||||||
|
* @param target target
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static void syncAnimation(AbstractClientPlayer clientPlayer, AbstractClientPlayer target) {
|
||||||
|
AtomicReference<ResourceLocation> clientPlayerLayer = new AtomicReference<>();
|
||||||
|
AtomicReference<ResourceLocation> targetLayer = new AtomicReference<>();
|
||||||
|
clientPlayerLayer.set(null);
|
||||||
|
targetLayer.set(null);
|
||||||
|
AnimationDataCapability.getCapability(clientPlayer).ifPresent(clientPlayerData ->
|
||||||
|
AnimationDataCapability.getCapability(target).ifPresent(targetData -> {
|
||||||
|
clientPlayerLayer.set(clientPlayerData.getRiderAnimLayer());
|
||||||
|
targetLayer.set(targetData.getRiderAnimLayer());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if(clientPlayerLayer.get() == null || targetLayer.get() == null) {
|
||||||
|
RawAnimationDataCapability.getCapability(clientPlayer).ifPresent(clientPlayerData ->
|
||||||
|
RawAnimationDataCapability.getCapability(target).ifPresent(targetData -> {
|
||||||
|
clientPlayerLayer.set(clientPlayerData.getRiderAnimLayer());
|
||||||
|
targetLayer.set(targetData.getRiderAnimLayer());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(clientPlayerLayer.get() == null || targetLayer.get() == null) return;
|
||||||
|
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||||
|
.getPlayerAssociatedData(clientPlayer).get(clientPlayerLayer.get());
|
||||||
|
ModifierLayer<IAnimation> targetModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||||
|
.getPlayerAssociatedData(target).get(targetLayer.get());
|
||||||
|
if(modifierLayer == null || targetModifierLayer == null) return;
|
||||||
|
IMixinKeyframeAnimationPlayer animation = (IMixinKeyframeAnimationPlayer) modifierLayer.getAnimation();
|
||||||
|
KeyframeAnimationPlayer targetAnimation = (KeyframeAnimationPlayer) targetModifierLayer.getAnimation();
|
||||||
|
if(animation == null || targetAnimation == null) return;
|
||||||
|
int currentTick = targetAnimation.getCurrentTick();
|
||||||
|
animation.sccore$setCurrentTick(currentTick);
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* client remove animation
|
||||||
|
* @param clientPlayer player
|
||||||
|
* @param layer layer
|
||||||
|
*/
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static void removeAnimation(@Nullable AbstractClientPlayer clientPlayer, ResourceLocation layer) {
|
||||||
|
playAnimation(clientPlayer, layer, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client play animation
|
||||||
|
* @param clientPlayer player
|
||||||
|
* @param layer layer
|
||||||
|
* @param animation animation
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
public static void playAnimation(@Nullable AbstractClientPlayer clientPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||||
|
try {
|
||||||
|
LocalPlayer localPlayer = Minecraft.getInstance().player;
|
||||||
|
if(clientPlayer == null) clientPlayer = localPlayer;
|
||||||
|
if(clientPlayer == null) return;
|
||||||
|
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||||
|
.getPlayerAssociatedData(clientPlayer).get(layer);
|
||||||
|
if(animation == null) {
|
||||||
|
if(modifierLayer != null) {
|
||||||
|
modifierLayer.replaceAnimationWithFade(
|
||||||
|
AbstractFadeModifier.standardFadeIn(3, Ease.INOUTSINE),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(modifierLayer == null) return;
|
||||||
|
KeyframeAnimation keyframeAnimation;
|
||||||
|
GenericAnimationData anim = AnimationHelper.INSTANCE.getAnimation(animation);
|
||||||
|
if(anim == null) {
|
||||||
|
RawAnimationData rawAnim = RawAnimationHelper.INSTANCE.getAnimation(animation);
|
||||||
|
if(rawAnim == null) return;
|
||||||
|
keyframeAnimation = rawAnim.getAnimation();
|
||||||
|
} else keyframeAnimation = anim.getAnimation();
|
||||||
|
if(keyframeAnimation == null) {
|
||||||
|
if(localPlayer == null) return;
|
||||||
|
localPlayer.sendSystemMessage(Component.translatable(
|
||||||
|
ModLang.TranslatableMessage.ANIMATION_RESOURCE_NOT_FOUND.getKey(),
|
||||||
|
animation.toString()
|
||||||
|
).withStyle(ChatFormatting.RED));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
modifierLayer.replaceAnimationWithFade(
|
||||||
|
AbstractFadeModifier.standardFadeIn(3, Ease.INOUTSINE),
|
||||||
|
new KeyframeAnimationPlayer(keyframeAnimation)
|
||||||
|
);
|
||||||
|
}catch (Exception e) {
|
||||||
|
SnowyCrescentCore.log.error("Failed to play animation : {}", animation, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.linearpast.sccore.animation.utils;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public enum ApiBack {
|
||||||
|
FAIL(0),
|
||||||
|
SUCCESS(1),
|
||||||
|
COOLDOWN(2),
|
||||||
|
RESOURCE_NOT_FOUND(3),
|
||||||
|
OUT_RANGE(4),
|
||||||
|
OPERATION_EXPIRE(5),
|
||||||
|
UNSUPPORTED(6),
|
||||||
|
BE_CANCELLED(7),
|
||||||
|
;
|
||||||
|
public final int value;
|
||||||
|
ApiBack(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isValueOf(int value) {
|
||||||
|
return this.value == value;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static ApiBack valueOf(int value) {
|
||||||
|
ApiBack[] values = ApiBack.values();
|
||||||
|
for (ApiBack v : values) {
|
||||||
|
if (v.isValueOf(value)) {
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ package com.linearpast.sccore.capability.data;
|
||||||
import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
||||||
import com.linearpast.sccore.core.ModChannel;
|
import com.linearpast.sccore.core.ModChannel;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.common.util.INBTSerializable;
|
import net.minecraftforge.common.util.INBTSerializable;
|
||||||
|
|
@ -16,6 +17,8 @@ public interface ICapabilitySync<T extends Entity> extends INBTSerializable<Comp
|
||||||
|
|
||||||
boolean isDirty();
|
boolean isDirty();
|
||||||
|
|
||||||
|
ResourceLocation getKey();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When this method is overridden, the super method should be called at the end
|
* When this method is overridden, the super method should be called at the end
|
||||||
* @param oldData old data
|
* @param oldData old data
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
|
@ -31,12 +30,6 @@ public interface ICapabilityPacket<T extends Entity> {
|
||||||
*/
|
*/
|
||||||
void handler(NetworkEvent.Context context);
|
void handler(NetworkEvent.Context context);
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the corresponding capability from the network packet, usually executed after {@link ICapabilityPacket#syncData}
|
|
||||||
* @param entity Target
|
|
||||||
* @return capability
|
|
||||||
*/
|
|
||||||
@Nullable ICapabilitySync<?> getCapability(T entity);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get tag
|
* Get tag
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
package com.linearpast.sccore.capability.network;
|
package com.linearpast.sccore.capability.network;
|
||||||
|
|
||||||
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
|
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||||
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
||||||
import com.linearpast.sccore.capability.data.entity.SimpleEntityCapabilitySync;
|
import com.linearpast.sccore.capability.data.entity.SimpleEntityCapabilitySync;
|
||||||
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
||||||
|
|
@ -7,25 +9,34 @@ import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.multiplayer.ClientLevel;
|
import net.minecraft.client.multiplayer.ClientLevel;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraftforge.network.NetworkEvent;
|
import net.minecraftforge.network.NetworkEvent;
|
||||||
|
|
||||||
public abstract class SimpleCapabilityPacket<T extends Entity> implements ICapabilityPacket<T> {
|
public class SimpleCapabilityPacket<T extends Entity> implements ICapabilityPacket<T> {
|
||||||
|
private final ResourceLocation key;
|
||||||
private final CompoundTag data;
|
private final CompoundTag data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
* @param data data tag
|
* @param data data tag
|
||||||
*/
|
*/
|
||||||
public SimpleCapabilityPacket(CompoundTag data) {
|
public SimpleCapabilityPacket(ResourceLocation key, CompoundTag data) {
|
||||||
|
this.key = key;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SimpleCapabilityPacket(ICapabilitySync<T> packet) {
|
||||||
|
this.key = packet.getKey();
|
||||||
|
this.data = packet.serializeNBT();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* decoder
|
* decoder
|
||||||
* @param buf buf
|
* @param buf buf
|
||||||
*/
|
*/
|
||||||
public SimpleCapabilityPacket(FriendlyByteBuf buf) {
|
public SimpleCapabilityPacket(FriendlyByteBuf buf) {
|
||||||
|
this.key = buf.readResourceLocation();
|
||||||
this.data = buf.readNbt();
|
this.data = buf.readNbt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,6 +46,7 @@ public abstract class SimpleCapabilityPacket<T extends Entity> implements ICapab
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void encode(FriendlyByteBuf buf) {
|
public void encode(FriendlyByteBuf buf) {
|
||||||
|
buf.writeResourceLocation(key);
|
||||||
buf.writeNbt(data);
|
buf.writeNbt(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +54,6 @@ public abstract class SimpleCapabilityPacket<T extends Entity> implements ICapab
|
||||||
* Default network packet handle, generally sufficient for use
|
* Default network packet handle, generally sufficient for use
|
||||||
* @param context NetworkEvent.Context
|
* @param context NetworkEvent.Context
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public void handler(NetworkEvent.Context context) {
|
public void handler(NetworkEvent.Context context) {
|
||||||
context.setPacketHandled(true);
|
context.setPacketHandled(true);
|
||||||
|
|
@ -59,7 +70,11 @@ public abstract class SimpleCapabilityPacket<T extends Entity> implements ICapab
|
||||||
}
|
}
|
||||||
if(entity == null) return;
|
if(entity == null) return;
|
||||||
try {
|
try {
|
||||||
ICapabilitySync<?> data = getCapability((T) entity);
|
ICapabilitySync<?> data = CapabilityUtils.getCapability(entity, key);
|
||||||
|
if(data == null) {
|
||||||
|
SnowyCrescentCore.log.error("key {} not found when sync capability on entity {}", key, entity);
|
||||||
|
return;
|
||||||
|
}
|
||||||
syncData(nbt, data);
|
syncData(nbt, data);
|
||||||
}catch (Exception ignored) {}
|
}catch (Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ public abstract class ModLazyRun {
|
||||||
try {
|
try {
|
||||||
if(isModLoaded()) return callable.call();
|
if(isModLoaded()) return callable.call();
|
||||||
else return elseCall.call();
|
else return elseCall.call();
|
||||||
}catch(Exception e) {
|
}catch(Exception ignored) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,16 @@ import net.minecraftforge.common.ForgeConfigSpec;
|
||||||
|
|
||||||
public class ModConfigs {
|
public class ModConfigs {
|
||||||
public enum ConfigName {
|
public enum ConfigName {
|
||||||
inviteDuration("inviteDuration"),
|
inviteValidTime("inviteValidTime"),
|
||||||
inviteDistance("inviteDistance"),
|
inviteValidDistance("inviteValidDistance"),
|
||||||
inviteCooldown("inviteCooldown"),
|
inviteCooldown("inviteCooldown"),
|
||||||
requestDuration("requestDuration"),
|
|
||||||
requestCooldown("requestCooldown"),
|
applyValidTime("applyValidTime"),
|
||||||
applyDistance("applyDistance"),
|
applyValidDistance("applyValidDistance"),
|
||||||
applyDuration("applyDuration"),
|
|
||||||
applyCooldown("applyCooldown"),
|
applyCooldown("applyCooldown"),
|
||||||
|
|
||||||
|
requestValidTime("requestValidTime"),
|
||||||
|
requestCooldown("requestCooldown"),
|
||||||
;
|
;
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
@ -27,33 +29,42 @@ public class ModConfigs {
|
||||||
public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||||
public static final ForgeConfigSpec SPEC;
|
public static final ForgeConfigSpec SPEC;
|
||||||
|
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> inviteDuration;
|
//invite
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> inviteDistance;
|
public static final ForgeConfigSpec.ConfigValue<Integer> inviteValidTime;
|
||||||
|
public static final ForgeConfigSpec.ConfigValue<Integer> inviteValidDistance;
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> inviteCooldown;
|
public static final ForgeConfigSpec.ConfigValue<Integer> inviteCooldown;
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> requestDuration;
|
//apply
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> requestCooldown;
|
public static final ForgeConfigSpec.ConfigValue<Integer> applyValidTime;
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> applyDistance;
|
public static final ForgeConfigSpec.ConfigValue<Integer> applyValidDistance;
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> applyDuration;
|
|
||||||
public static final ForgeConfigSpec.ConfigValue<Integer> applyCooldown;
|
public static final ForgeConfigSpec.ConfigValue<Integer> applyCooldown;
|
||||||
|
//request
|
||||||
|
public static final ForgeConfigSpec.ConfigValue<Integer> requestValidTime;
|
||||||
|
public static final ForgeConfigSpec.ConfigValue<Integer> requestCooldown;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
BUILDER.push("Animation");
|
BUILDER.push("Animation");
|
||||||
inviteDuration = BUILDER.comment("Animation invite duration. Ignore when zero. (seconds)")
|
//invite
|
||||||
.defineInRange(ConfigName.inviteDuration.name, 120, 0, Integer.MAX_VALUE);
|
inviteValidTime = BUILDER.comment("Animation invite valid time. Ignore when zero. (seconds)")
|
||||||
inviteDistance = BUILDER.comment("Animation invite max distance. Ignore when zero. (blocks)")
|
.defineInRange(ConfigName.inviteValidTime.name, 120, 0, Integer.MAX_VALUE);
|
||||||
.defineInRange(ConfigName.inviteDistance.name, 6, 0, Integer.MAX_VALUE);
|
inviteValidDistance = BUILDER.comment("Animation invite max distance. Ignore when zero. (blocks)")
|
||||||
|
.defineInRange(ConfigName.inviteValidDistance.name, 6, 0, Integer.MAX_VALUE);
|
||||||
inviteCooldown = BUILDER.comment("Animation invite cooldown. (seconds)")
|
inviteCooldown = BUILDER.comment("Animation invite cooldown. (seconds)")
|
||||||
.defineInRange(ConfigName.inviteCooldown.name, 60, 0, Integer.MAX_VALUE);
|
.defineInRange(ConfigName.inviteCooldown.name, 60, 0, Integer.MAX_VALUE);
|
||||||
requestDuration = BUILDER.comment("Animation request duration. Ignore when zero (seconds)")
|
|
||||||
.defineInRange(ConfigName.requestDuration.name, 120, 0, Integer.MAX_VALUE);
|
//apply
|
||||||
requestCooldown = BUILDER.comment("Animation request cooldown. (seconds)")
|
applyValidTime = BUILDER.comment("Animation apply valid time. Ignore when zero. (seconds)")
|
||||||
.defineInRange(ConfigName.requestCooldown.name, 60, 0, Integer.MAX_VALUE);
|
.defineInRange(ConfigName.applyValidTime.name, 120, 0, Integer.MAX_VALUE);
|
||||||
applyDuration = BUILDER.comment("Animation apply duration. Ignore when zero. (seconds)")
|
applyValidDistance = BUILDER.comment("Animation apply max distance. Ignore when zero. (blocks)")
|
||||||
.defineInRange(ConfigName.applyDuration.name, 120, 0, Integer.MAX_VALUE);
|
.defineInRange(ConfigName.applyValidDistance.name, 6, 0, Integer.MAX_VALUE);
|
||||||
applyDistance = BUILDER.comment("Animation apply max distance. Ignore when zero. (blocks)")
|
|
||||||
.defineInRange(ConfigName.applyDistance.name, 6, 0, Integer.MAX_VALUE);
|
|
||||||
applyCooldown = BUILDER.comment("Animation apply cooldown. (seconds)")
|
applyCooldown = BUILDER.comment("Animation apply cooldown. (seconds)")
|
||||||
.defineInRange(ConfigName.applyCooldown.name, 60, 0, Integer.MAX_VALUE);
|
.defineInRange(ConfigName.applyCooldown.name, 60, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
|
//request
|
||||||
|
requestValidTime = BUILDER.comment("Animation request valid time. Ignore when zero (seconds)")
|
||||||
|
.defineInRange(ConfigName.requestValidTime.name, 120, 0, Integer.MAX_VALUE);
|
||||||
|
requestCooldown = BUILDER.comment("Animation request cooldown. (seconds)")
|
||||||
|
.defineInRange(ConfigName.requestCooldown.name, 60, 0, Integer.MAX_VALUE);
|
||||||
|
|
||||||
BUILDER.pop();
|
BUILDER.pop();
|
||||||
SPEC = BUILDER.build();
|
SPEC = BUILDER.build();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,16 +23,6 @@ public class ModLang {
|
||||||
"命令执行成功。",
|
"命令执行成功。",
|
||||||
"Command run success."
|
"Command run success."
|
||||||
)),
|
)),
|
||||||
ANIMATION_NOT_PRESENT(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".animation_not_present",
|
|
||||||
"动画不存在。",
|
|
||||||
"Animation is not present."
|
|
||||||
)),
|
|
||||||
ANIMATION_LAYER_NOT_PRESENT(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".animation_layer_not_present",
|
|
||||||
"动画层不存在。",
|
|
||||||
"Animation layer is not present."
|
|
||||||
)),
|
|
||||||
PLAY_ANIMATION_FAIL(new LangEntity<>(
|
PLAY_ANIMATION_FAIL(new LangEntity<>(
|
||||||
translationString + command + animation + ".play_animation_fail",
|
translationString + command + animation + ".play_animation_fail",
|
||||||
"在这些玩家上播放动画失败:%s",
|
"在这些玩家上播放动画失败:%s",
|
||||||
|
|
@ -78,26 +68,6 @@ public class ModLang {
|
||||||
"%s§c§l 邀请§r你进行动画:%s。",
|
"%s§c§l 邀请§r你进行动画:%s。",
|
||||||
"%s§c§l invites§r you to animation: %s. "
|
"%s§c§l invites§r you to animation: %s. "
|
||||||
)),
|
)),
|
||||||
ACCEPT_INVITE_EXPIRED(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".accept_invite_expired",
|
|
||||||
"邀请已超时。(%s分钟)",
|
|
||||||
"Invite expired.(%s minute(s))"
|
|
||||||
)),
|
|
||||||
INVITE_EXPIRED(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".invite_expired",
|
|
||||||
"%s 接受了你的动画邀请,但是邀请超时了。(%s分钟)",
|
|
||||||
"%s has accepted your animation invitation but the invitation has expired. (%s minute(s))"
|
|
||||||
)),
|
|
||||||
ACCEPT_INVITE_TOO_FAR(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".accept_invite_too_far",
|
|
||||||
"你们距离太远了。(%s格)",
|
|
||||||
"You are too far apart. (%s block(s))"
|
|
||||||
)),
|
|
||||||
INVITE_TOO_FAR(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".invite_too_far",
|
|
||||||
"%s 接受了你的动画邀请,但你们距离太远了。(%s格)",
|
|
||||||
"%s has accepted your animation invitation but you are too far apart. (%s block(s))"
|
|
||||||
)),
|
|
||||||
ACCEPT_INVITE_SUCCESS(new LangEntity<>(
|
ACCEPT_INVITE_SUCCESS(new LangEntity<>(
|
||||||
translationString + command + animation + ".accept_invite_success",
|
translationString + command + animation + ".accept_invite_success",
|
||||||
"已接受邀请。",
|
"已接受邀请。",
|
||||||
|
|
@ -118,16 +88,6 @@ public class ModLang {
|
||||||
"%s§d§l 请求§r你进行动画:%s。",
|
"%s§d§l 请求§r你进行动画:%s。",
|
||||||
"%s§d§l requests§r you to animation: %s. "
|
"%s§d§l requests§r you to animation: %s. "
|
||||||
)),
|
)),
|
||||||
ACCEPT_REQUEST_EXPIRED(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".accept_request_expired",
|
|
||||||
"请求已超时。(%s分钟)",
|
|
||||||
"Request expired.(%s minute(s))"
|
|
||||||
)),
|
|
||||||
REQUEST_EXPIRED(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".request_expired",
|
|
||||||
"%s 接受了你的动画请求,但是请求超时了。(%s分钟)",
|
|
||||||
"%s has accepted your animation request but the request has expired. (%s minute(s))"
|
|
||||||
)),
|
|
||||||
ACCEPT_REQUEST_SUCCESS(new LangEntity<>(
|
ACCEPT_REQUEST_SUCCESS(new LangEntity<>(
|
||||||
translationString + command + animation + ".accept_request_success",
|
translationString + command + animation + ".accept_request_success",
|
||||||
"已接受请求。",
|
"已接受请求。",
|
||||||
|
|
@ -148,26 +108,6 @@ public class ModLang {
|
||||||
"%s§b§l 申请§r加入动画。",
|
"%s§b§l 申请§r加入动画。",
|
||||||
"%S§b§l Apply for §r to join your animation. "
|
"%S§b§l Apply for §r to join your animation. "
|
||||||
)),
|
)),
|
||||||
ACCEPT_APPLY_EXPIRED(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".accept_apply_expired",
|
|
||||||
"申请已超时。(%s分钟)",
|
|
||||||
"Application expired.(%s minute(s))"
|
|
||||||
)),
|
|
||||||
APPLY_EXPIRED(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".apply_expired",
|
|
||||||
"%s 接受了你的动画申请,但是申请超时了。(%s分钟)",
|
|
||||||
"%s has accepted your animation application but the application has expired. (%s minute(s))"
|
|
||||||
)),
|
|
||||||
ACCEPT_APPLY_TOO_FAR(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".accept_apply_too_far",
|
|
||||||
"你们距离太远了。(%s格)",
|
|
||||||
"You are too far apart. (%s block(s))"
|
|
||||||
)),
|
|
||||||
APPLY_TOO_FAR(new LangEntity<>(
|
|
||||||
translationString + command + animation + ".apply_too_far",
|
|
||||||
"%s 接受了你的动画申请,但你们距离太远了。(%s格)",
|
|
||||||
"%s has accepted your animation application but you are too far apart. (%s block(s))"
|
|
||||||
)),
|
|
||||||
ACCEPT_APPLY_SUCCESS(new LangEntity<>(
|
ACCEPT_APPLY_SUCCESS(new LangEntity<>(
|
||||||
translationString + command + animation + ".accept_apply_success",
|
translationString + command + animation + ".accept_apply_success",
|
||||||
"%s 接受了 %s 的申请。",
|
"%s 接受了 %s 的申请。",
|
||||||
|
|
@ -178,16 +118,6 @@ public class ModLang {
|
||||||
"%s 接受了你的动画申请。",
|
"%s 接受了你的动画申请。",
|
||||||
"%s has accepted your animation application."
|
"%s has accepted your animation application."
|
||||||
)),
|
)),
|
||||||
WITHOUT_ANIMATION_RIDE_ENTITY(new LangEntity<>(
|
|
||||||
translationString + animation + ".without_animation_ride_entity",
|
|
||||||
"命令执行错误,已满人或不支持的动画。",
|
|
||||||
"Command run fail, full or unsupported animations."
|
|
||||||
)),
|
|
||||||
COMMAND_COOLDOWN(new LangEntity<>(
|
|
||||||
translationString + animation + ".command_cooldown",
|
|
||||||
"你不能执行该指令,冷却中:%s 秒。",
|
|
||||||
"You cannot execute this command, cooling down: %s seconds."
|
|
||||||
)),
|
|
||||||
ANIMATION_TO_JSON(new LangEntity<>(
|
ANIMATION_TO_JSON(new LangEntity<>(
|
||||||
translationString + command + animation + ".animation_to_json",
|
translationString + command + animation + ".animation_to_json",
|
||||||
"动画%s已经存储到%s路径:",
|
"动画%s已经存储到%s路径:",
|
||||||
|
|
@ -198,15 +128,40 @@ public class ModLang {
|
||||||
"%s",
|
"%s",
|
||||||
"%s"
|
"%s"
|
||||||
)),
|
)),
|
||||||
UNKNOWN_ANIMATION(new LangEntity<>(
|
LIST_ANIMATION_RESOURCE(new LangEntity<>(
|
||||||
translationString + animation + ".unknown_animation",
|
translationString + command + animation + ".list_animation_resource",
|
||||||
"未知的动画%s,请检查你的资源包是否完整。",
|
"%s侧的%s有:%s",
|
||||||
"Unknown animation %s, please check if your resource packs is complete."
|
"The %2$s on %1$s has : %s"
|
||||||
)),
|
)),
|
||||||
UNSAFE_FILE_DIRECTORY(new LangEntity<>(
|
ANIMATION_EXPIRE(new LangEntity<>(
|
||||||
translationString + command + animation + ".unsafe_file_directory",
|
translationString + command + animation + ".animation_expire",
|
||||||
"你选择的文件路径并不安全",
|
"你不能执行该操作: 已过期。",
|
||||||
"%s"
|
"You cannot perform this operation: It has expired."
|
||||||
|
)),
|
||||||
|
ANIMATION_OUT_RANGE(new LangEntity<>(
|
||||||
|
translationString + command + animation + ".animation_out_range",
|
||||||
|
"你不能执行该操作: 距离不在%s格以内。",
|
||||||
|
"You cannot perform this operation: The distance is not within %s blocks."
|
||||||
|
)),
|
||||||
|
ANIMATION_OPERATION_UNSUPPORTED(new LangEntity<>(
|
||||||
|
translationString + command + animation + ".animation_operation_unsupported",
|
||||||
|
"错误: 不支持这样做。",
|
||||||
|
"Error: Unsupported operation."
|
||||||
|
)),
|
||||||
|
ANIMATION_COOLDOWN(new LangEntity<>(
|
||||||
|
translationString + command + animation + ".animation_cooldown",
|
||||||
|
"你不能执行该操作: 冷却中(%s秒)。",
|
||||||
|
"You cannot perform this operation: Cooling down (%s second(s))."
|
||||||
|
)),
|
||||||
|
ANIMATION_RESOURCE_NOT_FOUND(new LangEntity<>(
|
||||||
|
translationString + command + animation + ".animation_resource_not_found",
|
||||||
|
"错误: 资源未找到,请检查资源或操作是否有误。",
|
||||||
|
"Error: Resource not found, please check if there are any errors in the resource or operation."
|
||||||
|
)),
|
||||||
|
ANIMATION_OPERATION_CANCELLED(new LangEntity<>(
|
||||||
|
translationString + command + animation + ".animation_operation_cancelled",
|
||||||
|
"异常: 操作被取消。",
|
||||||
|
"Exception: Operation cancelled."
|
||||||
)),
|
)),
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
package com.linearpast.sccore.example.animation;
|
package com.linearpast.sccore.example.animation;
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.data.RawAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
|
||||||
import com.linearpast.sccore.animation.data.Ride;
|
import com.linearpast.sccore.animation.data.Ride;
|
||||||
import com.linearpast.sccore.animation.event.create.AnimationLayerRegisterEvent;
|
|
||||||
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
||||||
import com.linearpast.sccore.example.animation.event.ExampleCommandEvent;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import com.linearpast.sccore.example.animation.event.ExamplePlayerAttackEvent;
|
import com.linearpast.sccore.example.animation.event.ExamplePlayerAttackEvent;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraftforge.api.distmarker.Dist;
|
import net.minecraftforge.api.distmarker.Dist;
|
||||||
|
|
@ -14,7 +12,7 @@ import net.minecraftforge.eventbus.api.IEventBus;
|
||||||
import net.minecraftforge.fml.loading.FMLEnvironment;
|
import net.minecraftforge.fml.loading.FMLEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see AnimationUtils
|
* @see AnimationHelper
|
||||||
*/
|
*/
|
||||||
public class ModAnimation {
|
public class ModAnimation {
|
||||||
/**
|
/**
|
||||||
|
|
@ -38,7 +36,7 @@ public class ModAnimation {
|
||||||
* See wiki (If I'm done.)
|
* See wiki (If I'm done.)
|
||||||
* @param event event
|
* @param event event
|
||||||
*/
|
*/
|
||||||
public static void onLayerRegister(AnimationLayerRegisterEvent event) {
|
public static void onLayerRegister(AnimationRegisterEvent.Layer event) {
|
||||||
event.registerLayer(normalLayers, 42);
|
event.registerLayer(normalLayers, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,23 +45,34 @@ public class ModAnimation {
|
||||||
* See wiki (If I'm done.)
|
* See wiki (If I'm done.)
|
||||||
* @param event event
|
* @param event event
|
||||||
*/
|
*/
|
||||||
public static void onAnimationRegister(AnimationRegisterEvent event) {
|
public static void onAnimationRegister(AnimationRegisterEvent.Animation event) {
|
||||||
//You must define corresponding Animation to invite
|
//You must define corresponding Animation to invite
|
||||||
Animation amLTRL = Animation.create(AmLyingToRightLying)
|
// Animation amLTRL = Animation.create(AmLyingToRightLying)
|
||||||
.withLyingType(Animation.LyingType.RIGHT)
|
// .withLyingType(Animation.LyingType.RIGHT)
|
||||||
.withName("Lying-to-Right-Lying");
|
// .withName("Lying-to-Right-Lying");
|
||||||
Animation amSTL = Animation.create(AmStandToLying)
|
// Animation amSTL = Animation.create(AmStandToLying)
|
||||||
.withName("Stand-to-Lying")
|
// .withName("Stand-to-Lying")
|
||||||
.withLyingType(Animation.LyingType.FRONT);
|
// .withLyingType(Animation.LyingType.FRONT);
|
||||||
Animation waltzGentleman = Animation.create(WaltzGentleman)
|
// Animation waltzGentleman = Animation.create(WaltzGentleman)
|
||||||
.withName("Waltz-Gentleman")
|
// .withName("Waltz-Gentleman")
|
||||||
.withRide(Ride.create().addComponentAnimation(WaltzLady));
|
// .withRide(Ride.create().addComponentAnimation(WaltzLady));
|
||||||
Animation waltzLady = Animation.create(WaltzLady)
|
// Animation waltzLady = Animation.create(WaltzLady)
|
||||||
.withName("Waltz-Lady")
|
// .withName("Waltz-Lady")
|
||||||
.withCamYaw(180)
|
// .withCamYaw(180)
|
||||||
.withRide(Ride.create().addComponentAnimation(WaltzGentleman));
|
// .withRide(Ride.create().addComponentAnimation(WaltzGentleman));
|
||||||
|
//
|
||||||
|
// //You can use it to invite an Animation
|
||||||
|
// event.registerAnimation(AmLyingToRightLying, amLTRL);
|
||||||
|
// event.registerAnimation(AmStandToLying, amSTL);
|
||||||
|
// event.registerAnimation(WaltzGentleman, waltzGentleman);
|
||||||
|
// event.registerAnimation(WaltzLady, waltzLady);
|
||||||
|
}
|
||||||
|
|
||||||
//You can use it to invite an Animation
|
public static void onRawAnimationRegister(AnimationRegisterEvent.RawAnimation event) {
|
||||||
|
RawAnimationData amSTL = RawAnimationData.create(AmStandToLying).withRide(Ride.create().withExistTick(100));
|
||||||
|
RawAnimationData amLTRL = RawAnimationData.create(AmLyingToRightLying).withRide(Ride.create().withExistTick(100));
|
||||||
|
RawAnimationData waltzGentleman = RawAnimationData.create(WaltzGentleman).withRide(Ride.create().withExistTick(100).addComponentAnimation(WaltzLady));
|
||||||
|
RawAnimationData waltzLady = RawAnimationData.create(WaltzLady).withRide(Ride.create().withExistTick(100).addComponentAnimation(WaltzGentleman));
|
||||||
event.registerAnimation(AmLyingToRightLying, amLTRL);
|
event.registerAnimation(AmLyingToRightLying, amLTRL);
|
||||||
event.registerAnimation(AmStandToLying, amSTL);
|
event.registerAnimation(AmStandToLying, amSTL);
|
||||||
event.registerAnimation(WaltzGentleman, waltzGentleman);
|
event.registerAnimation(WaltzGentleman, waltzGentleman);
|
||||||
|
|
@ -77,10 +86,11 @@ public class ModAnimation {
|
||||||
forgeBus.addListener(ModAnimation::onAnimationRegister);
|
forgeBus.addListener(ModAnimation::onAnimationRegister);
|
||||||
|
|
||||||
//Try to play animation
|
//Try to play animation
|
||||||
forgeBus.addListener(ExamplePlayerAttackEvent::onPlayerAttack);
|
// forgeBus.addListener(ExamplePlayerAttackEvent::onPlayerAttack);
|
||||||
forgeBus.addListener(ExampleCommandEvent::inviteDance);
|
forgeBus.addListener(ExamplePlayerAttackEvent::rawAnimationAttack);
|
||||||
if(FMLEnvironment.dist == Dist.CLIENT){
|
if(FMLEnvironment.dist == Dist.CLIENT){
|
||||||
forgeBus.addListener(ExamplePlayerAttackEvent::onInputEvent);
|
// forgeBus.addListener(ExamplePlayerAttackEvent::onInputEvent);
|
||||||
|
forgeBus.addListener(ModAnimation::onRawAnimationRegister);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
package com.linearpast.sccore.example.animation.event;
|
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
|
||||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
|
||||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
|
||||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
|
||||||
import com.mojang.brigadier.context.CommandContext;
|
|
||||||
import net.minecraft.ChatFormatting;
|
|
||||||
import net.minecraft.commands.CommandSourceStack;
|
|
||||||
import net.minecraft.commands.arguments.EntityArgument;
|
|
||||||
import net.minecraft.network.chat.ClickEvent;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.chat.Style;
|
|
||||||
import net.minecraft.resources.ResourceLocation;
|
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraftforge.event.RegisterCommandsEvent;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static net.minecraft.commands.Commands.argument;
|
|
||||||
import static net.minecraft.commands.Commands.literal;
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public class ExampleCommandEvent {
|
|
||||||
record InviteRecord(long time, ResourceLocation layer, ResourceLocation animation, boolean isForce){}
|
|
||||||
private static final Map<UUID, Map<UUID, InviteRecord>> invites = new HashMap<>();
|
|
||||||
public static void inviteDance(RegisterCommandsEvent event) {
|
|
||||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dance").then(literal("invite")
|
|
||||||
.then(argument("player", EntityArgument.player())
|
|
||||||
.then(argument("layer", AnimationLayerArgument.layer())
|
|
||||||
.then(argument("anim", AnimationArgument.animation())
|
|
||||||
.executes(ExampleCommandEvent::inviteDance)
|
|
||||||
.then(argument("force", BoolArgumentType.bool())
|
|
||||||
.executes(ExampleCommandEvent::inviteDance)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.then(literal("accept")
|
|
||||||
.then(argument("player", EntityArgument.player())
|
|
||||||
.executes(ExampleCommandEvent::acceptInvite)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
event.getDispatcher().register(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int inviteDance(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
//get info
|
|
||||||
boolean force = false;
|
|
||||||
try {
|
|
||||||
force = BoolArgumentType.getBool(context, "force");
|
|
||||||
} catch (Exception ignored) {}
|
|
||||||
ServerPlayer player = source.getPlayerOrException();
|
|
||||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
|
||||||
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
|
||||||
String animString = AnimationArgument.getAnimation(context, "anim");
|
|
||||||
ResourceLocation layer = new ResourceLocation(layerString);
|
|
||||||
ResourceLocation anim = new ResourceLocation(animString);
|
|
||||||
boolean finalForce = force;
|
|
||||||
|
|
||||||
//test info present
|
|
||||||
boolean animationPresent = AnimationUtils.isAnimationPresent(anim);
|
|
||||||
boolean animationLayerPresent = AnimationUtils.isAnimationLayerPresent(layer);
|
|
||||||
if(!animationLayerPresent || !animationPresent) throw new Exception();
|
|
||||||
|
|
||||||
//update static cache
|
|
||||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), new HashMap<>());
|
|
||||||
inviteRecordMap.put(target.getUUID(), new InviteRecord(System.currentTimeMillis(), layer, anim, finalForce));
|
|
||||||
invites.put(player.getUUID(), inviteRecordMap);
|
|
||||||
|
|
||||||
//send message
|
|
||||||
Component name = player.getName();
|
|
||||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
|
||||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/dance invite accept " + player.getName().getString())
|
|
||||||
);
|
|
||||||
target.sendSystemMessage(name.copy().append("邀请你跳一支舞。").append(Component.literal("单击此处同意.").setStyle(pStyle)));
|
|
||||||
source.sendSuccess(() -> Component.literal("命令执行成功. 已发送邀请").withStyle(ChatFormatting.GREEN), true);
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.literal("Command run fail.").withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int acceptInvite(CommandContext<CommandSourceStack> context) {
|
|
||||||
CommandSourceStack source = context.getSource();
|
|
||||||
try {
|
|
||||||
ServerPlayer target = source.getPlayerOrException();
|
|
||||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
|
||||||
|
|
||||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), null);
|
|
||||||
if(inviteRecordMap == null) throw new Exception();
|
|
||||||
InviteRecord inviteRecord = inviteRecordMap.getOrDefault(target.getUUID(), null);
|
|
||||||
if(inviteRecord == null) throw new Exception();
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
if(now - inviteRecord.time > 120000) {
|
|
||||||
source.sendFailure(Component.literal("邀请已超时(2分钟).").withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(target.getName().copy().append("接受了你的舞蹈邀请. 但是邀请超时了(2分钟).").withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if(player.position().distanceToSqr(target.position()) > 64) {
|
|
||||||
source.sendFailure(Component.literal("你们距离太远了(8格).").withStyle(ChatFormatting.RED));
|
|
||||||
player.sendSystemMessage(target.getName().copy().append("接受了你的舞蹈邀请. 但你们距离太远了(8格).").withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
inviteRecordMap.remove(target.getUUID());
|
|
||||||
invites.put(player.getUUID(), inviteRecordMap);
|
|
||||||
AnimationUtils.startAnimationTogether(player, inviteRecord.layer, inviteRecord.animation, inviteRecord.isForce, target);
|
|
||||||
source.sendSuccess(() -> Component.literal("已接受邀请.").withStyle(ChatFormatting.GREEN), true);
|
|
||||||
player.sendSystemMessage(target.getName().copy().append("已接受你的舞蹈邀请.").withStyle(ChatFormatting.GREEN));
|
|
||||||
} catch (Exception e) {
|
|
||||||
source.sendFailure(Component.literal("Command run fail.").withStyle(ChatFormatting.RED));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
package com.linearpast.sccore.example.animation.event;
|
package com.linearpast.sccore.example.animation.event;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
|
import com.linearpast.sccore.animation.helper.RawAnimationHelper;
|
||||||
import com.linearpast.sccore.example.animation.ModAnimation;
|
import com.linearpast.sccore.example.animation.ModAnimation;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.player.AbstractClientPlayer;
|
||||||
import net.minecraft.client.player.LocalPlayer;
|
import net.minecraft.client.player.LocalPlayer;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
|
@ -24,16 +26,33 @@ public class ExamplePlayerAttackEvent {
|
||||||
Player entity = event.getEntity();
|
Player entity = event.getEntity();
|
||||||
if(entity instanceof ServerPlayer player) {
|
if(entity instanceof ServerPlayer player) {
|
||||||
if(target instanceof Sheep){
|
if(target instanceof Sheep){
|
||||||
ResourceLocation playing = AnimationUtils.getAnimationPlaying(player, ModAnimation.normalLayers);
|
ResourceLocation playing = AnimationHelper.INSTANCE.getAnimationPlaying(player, ModAnimation.normalLayers);
|
||||||
if(playing == null) {
|
if(playing == null) {
|
||||||
AnimationUtils.playAnimation(player, ModAnimation.normalLayers, ModAnimation.AmStandToLying);
|
AnimationHelper.INSTANCE.playAnimation(player, ModAnimation.normalLayers, ModAnimation.AmStandToLying);
|
||||||
} else {
|
} else {
|
||||||
AnimationUtils.playAnimation(player, ModAnimation.normalLayers, null);
|
AnimationHelper.INSTANCE.removeAnimation(player, ModAnimation.normalLayers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void rawAnimationAttack(AttackEntityEvent event) {
|
||||||
|
Entity target = event.getTarget();
|
||||||
|
Player entity = event.getEntity();
|
||||||
|
if(entity instanceof AbstractClientPlayer player && target instanceof AbstractClientPlayer targetPlayer) {
|
||||||
|
if(player == Minecraft.getInstance().player){
|
||||||
|
RawAnimationHelper.INSTANCE.invite(
|
||||||
|
ModAnimation.normalLayers,
|
||||||
|
ModAnimation.WaltzGentleman,
|
||||||
|
targetPlayer
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(entity instanceof ServerPlayer player && target instanceof ServerPlayer targetPlayer) {
|
||||||
|
RawAnimationHelper.INSTANCE.acceptInvite(player, targetPlayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* when press "/", this will run
|
* when press "/", this will run
|
||||||
* @param event event
|
* @param event event
|
||||||
|
|
@ -44,9 +63,9 @@ public class ExamplePlayerAttackEvent {
|
||||||
LocalPlayer player = instance.player;
|
LocalPlayer player = instance.player;
|
||||||
if (player == null) return;
|
if (player == null) return;
|
||||||
if(instance.options.keyCommand.isDown()) {
|
if(instance.options.keyCommand.isDown()) {
|
||||||
ResourceLocation playing = AnimationUtils.getAnimationPlaying(player, ModAnimation.normalLayers);
|
ResourceLocation playing = AnimationHelper.INSTANCE.getAnimationPlaying(player, ModAnimation.normalLayers);
|
||||||
if(playing == null) {
|
if(playing == null) {
|
||||||
AnimationUtils.playAnimationWithRide(null, ModAnimation.normalLayers, ModAnimation.AmLyingToRightLying, true);
|
AnimationHelper.INSTANCE.playAnimationWithRide((AbstractClientPlayer) null, ModAnimation.normalLayers, ModAnimation.AmLyingToRightLying, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.animal.Sheep;
|
import net.minecraft.world.entity.animal.Sheep;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
@ -76,20 +75,32 @@ public class SheepDataCapability extends SimpleEntityCapabilitySync<Sheep> imple
|
||||||
* @see SimpleCapabilityPacket
|
* @see SimpleCapabilityPacket
|
||||||
*/
|
*/
|
||||||
public static class SheepCapabilityPacket extends SimpleCapabilityPacket<Sheep> {
|
public static class SheepCapabilityPacket extends SimpleCapabilityPacket<Sheep> {
|
||||||
public SheepCapabilityPacket(CompoundTag data) {
|
/**
|
||||||
super(data);
|
* You must override the constructor of FriendlyByteBuf
|
||||||
}
|
* @param buf FriendlyByteBuf
|
||||||
|
*/
|
||||||
public SheepCapabilityPacket(FriendlyByteBuf buf) {
|
public SheepCapabilityPacket(FriendlyByteBuf buf) {
|
||||||
super(buf);
|
super(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public @Nullable SheepDataCapability getCapability(Sheep entity) {
|
* More, you must override a constructor to help you create an instance
|
||||||
return SheepDataCapability.getCapability(entity).orElse(null);
|
* @param data Cap data
|
||||||
|
*/
|
||||||
|
public SheepCapabilityPacket(SheepDataCapability data) {
|
||||||
|
super(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the capability key
|
||||||
|
* @return The capability key
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ResourceLocation getKey() {
|
||||||
|
return new ResourceLocation(SnowyCrescentCore.MODID, "sheep_data");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the default network packet, which will be called when sendToClient sends it
|
* Get the default network packet, which will be called when sendToClient sends it
|
||||||
* @return network packet
|
* @return network packet
|
||||||
|
|
@ -97,7 +108,7 @@ public class SheepDataCapability extends SimpleEntityCapabilitySync<Sheep> imple
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public SimpleCapabilityPacket<Sheep> getDefaultPacket() {
|
public SimpleCapabilityPacket<Sheep> getDefaultPacket() {
|
||||||
return new SheepCapabilityPacket(serializeNBT());
|
return new SheepCapabilityPacket(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.linearpast.sccore.mixin;
|
package com.linearpast.sccore.mixin;
|
||||||
|
|
||||||
import com.linearpast.sccore.SnowyCrescentCore;
|
import com.linearpast.sccore.SnowyCrescentCore;
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import net.minecraftforge.fml.ModList;
|
import net.minecraftforge.fml.ModList;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||||
|
|
@ -27,7 +27,7 @@ public class SCCoreMixinPlugin implements IMixinConfigPlugin {
|
||||||
return "runData".equals(System.getProperty("gradle.task"));
|
return "runData".equals(System.getProperty("gradle.task"));
|
||||||
}
|
}
|
||||||
if (mixinClassName.startsWith("com\\.linearpast\\." + SnowyCrescentCore.MODID + "\\.mixin\\.animation")) {
|
if (mixinClassName.startsWith("com\\.linearpast\\." + SnowyCrescentCore.MODID + "\\.mixin\\.animation")) {
|
||||||
return ModList.get().isLoaded(AnimationUtils.AnimModId);
|
return ModList.get().isLoaded(AnimationHelper.AnimModId);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
package com.linearpast.sccore.mixin.animation;
|
package com.linearpast.sccore.mixin.animation;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
|
||||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
@ -36,7 +36,7 @@ public abstract class MixinEntity {
|
||||||
if(data == null) return;
|
if(data == null) return;
|
||||||
Float camYModifier = null;
|
Float camYModifier = null;
|
||||||
for (ResourceLocation value : data.getAnimations().values()) {
|
for (ResourceLocation value : data.getAnimations().values()) {
|
||||||
Animation animation = AnimationUtils.getAnimation(value);
|
GenericAnimationData animation = AnimationHelper.INSTANCE.getAnimation(value);
|
||||||
if(animation == null) continue;
|
if(animation == null) continue;
|
||||||
float animationCamY = animation.getCamY();
|
float animationCamY = animation.getCamY();
|
||||||
if(camYModifier == null) camYModifier = animationCamY;
|
if(camYModifier == null) camYModifier = animationCamY;
|
||||||
|
|
@ -56,7 +56,7 @@ public abstract class MixinEntity {
|
||||||
private void redefinedBoundingBox(CallbackInfoReturnable<AABB> cir){
|
private void redefinedBoundingBox(CallbackInfoReturnable<AABB> cir){
|
||||||
Entity self = Entity.class.cast(this);
|
Entity self = Entity.class.cast(this);
|
||||||
if(self instanceof Player player){
|
if(self instanceof Player player){
|
||||||
float heightModifier = AnimationUtils.getHeightModifier(player);
|
float heightModifier = AnimationHelper.INSTANCE.getHeightModifier(player);
|
||||||
if(heightModifier == 1.0f) return;
|
if(heightModifier == 1.0f) return;
|
||||||
double modifyHeight = 1.8f * heightModifier;
|
double modifyHeight = 1.8f * heightModifier;
|
||||||
cir.setReturnValue(this.bb.setMaxY(modifyHeight + this.bb.minY));
|
cir.setReturnValue(this.bb.setMaxY(modifyHeight + this.bb.minY));
|
||||||
|
|
@ -70,7 +70,7 @@ public abstract class MixinEntity {
|
||||||
private float redefinedBbHeight(float original){
|
private float redefinedBbHeight(float original){
|
||||||
Entity self = Entity.class.cast(this);
|
Entity self = Entity.class.cast(this);
|
||||||
if(self instanceof Player player){
|
if(self instanceof Player player){
|
||||||
float heightModifier = AnimationUtils.getHeightModifier(player);
|
float heightModifier = AnimationHelper.INSTANCE.getHeightModifier(player);
|
||||||
if(heightModifier == 1.0f) return original;
|
if(heightModifier == 1.0f) return original;
|
||||||
return original * heightModifier;
|
return original * heightModifier;
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +87,7 @@ public abstract class MixinEntity {
|
||||||
private void redefinedPose(CallbackInfoReturnable<Pose> cir){
|
private void redefinedPose(CallbackInfoReturnable<Pose> cir){
|
||||||
Entity self = Entity.class.cast(this);
|
Entity self = Entity.class.cast(this);
|
||||||
if(self instanceof Player player){
|
if(self instanceof Player player){
|
||||||
float heightModifier = AnimationUtils.getHeightModifier(player);
|
float heightModifier = AnimationHelper.INSTANCE.getHeightModifier(player);
|
||||||
if(heightModifier == 1.0f) return;
|
if(heightModifier == 1.0f) return;
|
||||||
setPose(Pose.STANDING);
|
setPose(Pose.STANDING);
|
||||||
cir.setReturnValue(Pose.STANDING);
|
cir.setReturnValue(Pose.STANDING);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.linearpast.sccore.mixin.animation.client;
|
package com.linearpast.sccore.mixin.animation.client;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
|
@ -36,7 +36,7 @@ public abstract class MixinEntity {
|
||||||
private void turnPosePlayer(double pYRot, double pXRot, CallbackInfo ci) {
|
private void turnPosePlayer(double pYRot, double pXRot, CallbackInfo ci) {
|
||||||
Entity self = Entity.class.cast(this);
|
Entity self = Entity.class.cast(this);
|
||||||
if(self instanceof Player player){
|
if(self instanceof Player player){
|
||||||
Animation.LyingType lyingType = AnimationUtils.getSideView(player);
|
GenericAnimationData.LyingType lyingType = AnimationHelper.INSTANCE.getSideView(player);
|
||||||
if(lyingType != null && Minecraft.getInstance().options.getCameraType().isFirstPerson()) {
|
if(lyingType != null && Minecraft.getInstance().options.getCameraType().isFirstPerson()) {
|
||||||
float f = (float)pXRot * 0.15F;
|
float f = (float)pXRot * 0.15F;
|
||||||
float f1 = (float)pYRot * 0.15F;
|
float f1 = (float)pYRot * 0.15F;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package com.linearpast.sccore.mixin.animation.client;
|
package com.linearpast.sccore.mixin.animation.client;
|
||||||
|
|
||||||
import com.linearpast.sccore.animation.AnimationUtils;
|
import com.linearpast.sccore.animation.data.GenericAnimationData;
|
||||||
import com.linearpast.sccore.animation.data.Animation;
|
import com.linearpast.sccore.animation.helper.AnimationHelper;
|
||||||
import net.minecraft.client.model.AgeableListModel;
|
import net.minecraft.client.model.AgeableListModel;
|
||||||
import net.minecraft.client.model.ArmedModel;
|
import net.minecraft.client.model.ArmedModel;
|
||||||
import net.minecraft.client.model.HeadedModel;
|
import net.minecraft.client.model.HeadedModel;
|
||||||
|
|
@ -26,7 +26,7 @@ public abstract class MixinHumanoidModel<T extends LivingEntity> extends Ageable
|
||||||
)
|
)
|
||||||
private void modifyHeadRot(T pEntity, float pLimbSwing, float pLimbSwingAmount, float pAgeInTicks, float pNetHeadYaw, float pHeadPitch, CallbackInfo ci){
|
private void modifyHeadRot(T pEntity, float pLimbSwing, float pLimbSwingAmount, float pAgeInTicks, float pNetHeadYaw, float pHeadPitch, CallbackInfo ci){
|
||||||
if(pEntity instanceof Player player){
|
if(pEntity instanceof Player player){
|
||||||
Animation.LyingType lyingType = AnimationUtils.getSideView(player);
|
GenericAnimationData.LyingType lyingType = AnimationHelper.INSTANCE.getSideView(player);
|
||||||
if(lyingType != null) {
|
if(lyingType != null) {
|
||||||
float pitch = pHeadPitch - 90.0f;
|
float pitch = pHeadPitch - 90.0f;
|
||||||
float yaw = pNetHeadYaw * -1.0f;
|
float yaw = pNetHeadYaw * -1.0f;
|
||||||
|
|
|
||||||
355
src/main/java/com/linearpast/sccore/utils/ModuleAccess.java
Normal file
355
src/main/java/com/linearpast/sccore/utils/ModuleAccess.java
Normal file
|
|
@ -0,0 +1,355 @@
|
||||||
|
package com.linearpast.sccore.utils;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassWriter;
|
||||||
|
import org.objectweb.asm.MethodVisitor;
|
||||||
|
import org.objectweb.asm.Opcodes;
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.lang.invoke.MethodHandle;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import java.lang.invoke.MethodType;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This field is a static method in a bridge class.<br/>
|
||||||
|
* The bridge class is generated by static{} statement.<br/>
|
||||||
|
* This method invokes JavaLangAccess::addOpens(Module,String,Module)
|
||||||
|
* to open a package to another module.<br/>
|
||||||
|
* It looks like:
|
||||||
|
* <blockquote><pre>
|
||||||
|
* public static void export(
|
||||||
|
* Object module,
|
||||||
|
* Object packageName,
|
||||||
|
* Object target)
|
||||||
|
* {
|
||||||
|
* SharedSecrets.getJavaLangAccess().addExports(
|
||||||
|
* (Module)module,
|
||||||
|
* (String)packageName,
|
||||||
|
* (Module)target
|
||||||
|
* );
|
||||||
|
* }</pre></blockquote>
|
||||||
|
* This used {@link Proxy} to force access
|
||||||
|
* JavaLangAccess and SharedSecrets.<br/>
|
||||||
|
* This field is null in Java 8.
|
||||||
|
*/
|
||||||
|
public class ModuleAccess extends ClassLoader
|
||||||
|
{
|
||||||
|
|
||||||
|
public static final MethodHandle MODULE;
|
||||||
|
public static final MethodHandle EXPORT;
|
||||||
|
public static final MethodHandle OPEN;
|
||||||
|
public static final MethodHandle READ;
|
||||||
|
public static final MethodHandles.Lookup LOOKUP;
|
||||||
|
|
||||||
|
public ModuleAccess()
|
||||||
|
{
|
||||||
|
super(ModuleAccess.class.getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class<?> loading(byte[] code)
|
||||||
|
{
|
||||||
|
Class<?> clazz = this.defineClass(null, code, 0, code.length);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Class.forName(clazz.getName(), true, this);
|
||||||
|
}
|
||||||
|
catch (ClassNotFoundException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
|
return clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object module(Class<?> clazz)
|
||||||
|
{
|
||||||
|
if (ModuleAccess.MODULE != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return ModuleAccess.MODULE.invoke(clazz);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
exception(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void export(Object module, Object packageName, Object target)
|
||||||
|
{
|
||||||
|
if (ModuleAccess.EXPORT != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ModuleAccess.EXPORT.invokeExact(module, packageName, target);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
exception(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper method of {@link ModuleAccess#OPEN} without any exception.
|
||||||
|
* @param module The module of the class you want to access.
|
||||||
|
* @param packageName The package of the class you want to access.
|
||||||
|
* @param target The module of your class
|
||||||
|
*/
|
||||||
|
public static void open(Object module, Object packageName, Object target)
|
||||||
|
{
|
||||||
|
if (ModuleAccess.OPEN != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ModuleAccess.OPEN.invokeExact(module, packageName, target);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
exception(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void read(Object module, Object target)
|
||||||
|
{
|
||||||
|
if (ModuleAccess.READ != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ModuleAccess.READ.invokeExact(module, target);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
exception(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Throwable> void exception(Throwable t) throws T
|
||||||
|
{
|
||||||
|
throw (T) t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ModuleAccess access = new ModuleAccess();
|
||||||
|
/*
|
||||||
|
* JavaLangAccess class and SharedSecrets class.
|
||||||
|
* In Java 9 and 10, they are in jdk.internal.misc package.
|
||||||
|
* And in higher version, they ar in jdk.internal.access package
|
||||||
|
*/
|
||||||
|
Class<?> JLA;
|
||||||
|
Class<?> shared;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
JLA = Class.forName("jdk.internal.access.JavaLangAccess");
|
||||||
|
shared = Class.forName("jdk.internal.access.SharedSecrets");
|
||||||
|
}
|
||||||
|
catch(ClassNotFoundException ignored)
|
||||||
|
{
|
||||||
|
JLA = Class.forName("jdk.internal.misc.JavaLangAccess");
|
||||||
|
shared = Class.forName("jdk.internal.misc.SharedSecrets");
|
||||||
|
}
|
||||||
|
// Use proxy to force access the package of JavaLangAccess in the module of the proxy object.
|
||||||
|
Object proxy = Proxy.newProxyInstance(access, new Class[]{JLA}, (_1, _2, _3) -> null);
|
||||||
|
String packageName = proxy.getClass().getPackage().getName();
|
||||||
|
// The name of the bridge class is a random UUID.
|
||||||
|
String uuid = 'Z' + UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
|
||||||
|
// In the same package, this class can also access JLA and SS
|
||||||
|
String className = packageName.replace('.', '/') + "/" + uuid;
|
||||||
|
/*
|
||||||
|
* This bridge class looks like:
|
||||||
|
*
|
||||||
|
* package com.sun.proxy.jdk.proxy1;
|
||||||
|
*
|
||||||
|
* import jdk.internal.access.JavaLangAccess;
|
||||||
|
* import jdk.internal.access.SharedSecrets;
|
||||||
|
*
|
||||||
|
* public class Bridge
|
||||||
|
* {
|
||||||
|
* public static void export(Object module, Object packageName, Object open)
|
||||||
|
* {
|
||||||
|
* SharedSecrets.getJavaLangAccess().addExports((Module)module, (String)packageName, (Module)open);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public static void open(Object module, Object packageName, Object open)
|
||||||
|
* {
|
||||||
|
* SharedSecrets.getJavaLangAccess().addOpens((Module)module, (String)packageName, (Module)open);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* public static void read(Object module, Object packageName, Object open)
|
||||||
|
* {
|
||||||
|
* SharedSecrets.getJavaLangAccess().addReads((Module)module, (String)packageName, (Module)open);
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* static
|
||||||
|
* {
|
||||||
|
* Bridge.class.getModule().addExports(
|
||||||
|
* "com.sun.proxy.jdk.proxy1",
|
||||||
|
* Class.forName("org.mve.invoke.ModuleAccess").getModule()
|
||||||
|
* );
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
ClassWriter visitor = new ClassWriter(0);
|
||||||
|
visitor.visit(52, Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, className, null, "java/lang/Object", null);
|
||||||
|
MethodVisitor mv;
|
||||||
|
|
||||||
|
mv = visitor.visitMethod(
|
||||||
|
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||||
|
"open",
|
||||||
|
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V",
|
||||||
|
null, null
|
||||||
|
);
|
||||||
|
mv.visitCode();
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
Opcodes.INVOKESTATIC,
|
||||||
|
shared.getTypeName().replace('.', '/'),
|
||||||
|
"getJavaLangAccess",
|
||||||
|
MethodType.methodType(JLA).toMethodDescriptorString(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
Opcodes.INVOKEINTERFACE,
|
||||||
|
JLA.getTypeName().replace('.', '/'),
|
||||||
|
"addOpens",
|
||||||
|
"(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
mv.visitMaxs(4, 3);
|
||||||
|
mv.visitEnd();
|
||||||
|
|
||||||
|
mv = visitor.visitMethod(
|
||||||
|
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||||
|
"export",
|
||||||
|
"(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V",
|
||||||
|
null, null
|
||||||
|
);
|
||||||
|
mv.visitCode();
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
Opcodes.INVOKESTATIC,
|
||||||
|
shared.getTypeName().replace('.', '/'),
|
||||||
|
"getJavaLangAccess",
|
||||||
|
MethodType.methodType(JLA).toMethodDescriptorString(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/String");
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 2);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
Opcodes.INVOKEINTERFACE,
|
||||||
|
JLA.getTypeName().replace('.', '/'),
|
||||||
|
"addExports",
|
||||||
|
"(Ljava/lang/Module;Ljava/lang/String;Ljava/lang/Module;)V",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
mv.visitMaxs(4, 3);
|
||||||
|
mv.visitEnd();
|
||||||
|
|
||||||
|
mv = visitor.visitMethod(
|
||||||
|
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||||
|
"read",
|
||||||
|
"(Ljava/lang/Object;Ljava/lang/Object;)V",
|
||||||
|
null, null
|
||||||
|
);
|
||||||
|
mv.visitCode();
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
Opcodes.INVOKESTATIC,
|
||||||
|
shared.getTypeName().replace('.', '/'),
|
||||||
|
"getJavaLangAccess",
|
||||||
|
MethodType.methodType(JLA).toMethodDescriptorString(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 0);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
||||||
|
mv.visitVarInsn(Opcodes.ALOAD, 1);
|
||||||
|
mv.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Module");
|
||||||
|
mv.visitMethodInsn(
|
||||||
|
Opcodes.INVOKEINTERFACE,
|
||||||
|
JLA.getTypeName().replace('.', '/'),
|
||||||
|
"addReads",
|
||||||
|
"(Ljava/lang/Module;Ljava/lang/Module;)V",
|
||||||
|
true
|
||||||
|
);
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
mv.visitMaxs(3, 2);
|
||||||
|
mv.visitEnd();
|
||||||
|
|
||||||
|
mv = visitor.visitMethod(Opcodes.ACC_STATIC, "<clinit>", "()V", null, null);
|
||||||
|
mv.visitCode();
|
||||||
|
mv.visitLdcInsn(Type.getType("L" + className + ";"));
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
||||||
|
mv.visitLdcInsn(packageName);
|
||||||
|
mv.visitLdcInsn(ModuleAccess.class.getTypeName());
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Module", "addExports", "(Ljava/lang/String;Ljava/lang/Module;)Ljava/lang/Module;", false);
|
||||||
|
mv.visitInsn(Opcodes.POP);
|
||||||
|
mv.visitLdcInsn(Type.getType("L" + className + ";"));
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
||||||
|
mv.visitLdcInsn(packageName);
|
||||||
|
mv.visitLdcInsn(ModuleAccess.class.getTypeName());
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;", false);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Class", "getModule", "()Ljava/lang/Module;", false);
|
||||||
|
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/Module", "addOpens", "(Ljava/lang/String;Ljava/lang/Module;)Ljava/lang/Module;", false);
|
||||||
|
mv.visitInsn(Opcodes.POP);
|
||||||
|
mv.visitInsn(Opcodes.RETURN);
|
||||||
|
mv.visitMaxs(3, 0);
|
||||||
|
mv.visitEnd();
|
||||||
|
|
||||||
|
visitor.visitEnd();
|
||||||
|
byte[] code = visitor.toByteArray();
|
||||||
|
|
||||||
|
Class<?> clazz = access.loading(code);
|
||||||
|
ModuleAccess.class.getModule().addReads(clazz.getModule());
|
||||||
|
// Use MethodHandle to invoke methods.
|
||||||
|
MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
|
Class<?> moduleClass = Class.forName("java.lang.Module");
|
||||||
|
MODULE = lookup.findVirtual(Class.class, "getModule", MethodType.methodType(moduleClass));
|
||||||
|
EXPORT = lookup.findStatic(
|
||||||
|
clazz,
|
||||||
|
"export",
|
||||||
|
MethodType.methodType(void.class, Object.class, Object.class, Object.class)
|
||||||
|
);
|
||||||
|
OPEN = lookup.findStatic(
|
||||||
|
clazz,
|
||||||
|
"open",
|
||||||
|
MethodType.methodType(void.class, Object.class, Object.class, Object.class)
|
||||||
|
);
|
||||||
|
READ = lookup.findStatic(
|
||||||
|
clazz,
|
||||||
|
"read",
|
||||||
|
MethodType.methodType(void.class, Object.class, Object.class)
|
||||||
|
);
|
||||||
|
|
||||||
|
ModuleAccess.open(MethodHandles.Lookup.class.getModule(), MethodHandles.Lookup.class.getPackageName(), ModuleAccess.class.getModule());
|
||||||
|
Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
|
||||||
|
implLookupField.setAccessible(true);
|
||||||
|
LOOKUP = (MethodHandles.Lookup) implLookupField.get(null);
|
||||||
|
}
|
||||||
|
catch (Throwable t)
|
||||||
|
{
|
||||||
|
exception(t);
|
||||||
|
throw new RuntimeException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user