mirror of
https://github.com/Goodbird-git/Geckolib-Unofficial-1.7.10.git
synced 2026-11-14 01:24:07 +00:00
Initial commit
This commit is contained in:
commit
cf772d97be
368 files changed
+96357
No files matched your search
@@ -0,0 +1,22 @@
|
||||
# This is the universal Text Editor Configuration
|
||||
# for all GTNewHorizons projects
|
||||
# See: https://editorconfig.org/
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{bat,ini}]
|
||||
end_of_line = crlf
|
||||
|
||||
[*.{dtd,json,info,mcmeta,md,sh,svg,xml,xsd,xsl,yaml,yml}]
|
||||
indent_size = 2
|
||||
|
||||
[*.lang]
|
||||
trim_trailing_whitespace = false
|
||||
@@ -0,0 +1,44 @@
|
||||
* text eol=lf
|
||||
|
||||
*.[jJ][aA][rR] binary
|
||||
|
||||
*.[pP][nN][gG] binary
|
||||
*.[jJ][pP][gG] binary
|
||||
*.[jJ][pP][eE][gG] binary
|
||||
*.[gG][iI][fF] binary
|
||||
*.[tT][iI][fF] binary
|
||||
*.[tT][iI][fF][fF] binary
|
||||
*.[iI][cC][oO] binary
|
||||
*.[sS][vV][gG] text
|
||||
*.[eE][pP][sS] binary
|
||||
*.[xX][cC][fF] binary
|
||||
|
||||
*.[kK][aA][rR] binary
|
||||
*.[mM]4[aA] binary
|
||||
*.[mM][iI][dD] binary
|
||||
*.[mM][iI][dD][iI] binary
|
||||
*.[mM][pP]3 binary
|
||||
*.[oO][gG][gG] binary
|
||||
*.[rR][aA] binary
|
||||
|
||||
*.7[zZ] binary
|
||||
*.[gG][zZ] binary
|
||||
*.[tT][aA][rR] binary
|
||||
*.[tT][gG][zZ] binary
|
||||
*.[zZ][iI][pP] binary
|
||||
|
||||
*.[tT][cC][nN] binary
|
||||
*.[sS][oO] binary
|
||||
*.[dD][lL][lL] binary
|
||||
*.[dD][yY][lL][iI][bB] binary
|
||||
*.[pP][sS][dD] binary
|
||||
*.[tT][tT][fF] binary
|
||||
*.[oO][tT][fF] binary
|
||||
|
||||
*.[pP][aA][tT][cC][hH] -text
|
||||
|
||||
*.[bB][aA][tT] text eol=crlf
|
||||
*.[cC][mM][dD] text eol=crlf
|
||||
*.[pP][sS]1 text eol=crlf
|
||||
|
||||
*[aA][uU][tT][oO][gG][eE][nN][eE][rR][aA][tT][eE][dD]* binary
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if ! git diff --name-only HEAD HEAD~1 | grep -qF 'build.gradle'; then
|
||||
new_version="$(date +%s)"
|
||||
sed --in-place "s!^//version:.*!//version: $new_version!g" build.gradle
|
||||
git add build.gradle
|
||||
git commit -m "[ci skip] update build script version to $new_version"
|
||||
git push
|
||||
printf 'Updated buildscript version to %s\n' "$new_version"
|
||||
else
|
||||
printf 'Ignored buildscript version update: no changes detected\n'
|
||||
fi
|
||||
@@ -0,0 +1,13 @@
|
||||
|
||||
name: Build and test
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ master, main ]
|
||||
push:
|
||||
branches: [ master, main ]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/build-and-test.yml@master
|
||||
secrets: inherit
|
||||
@@ -0,0 +1,39 @@
|
||||
# This workflow only meant for the source mod you shouldn't bring it into your own project
|
||||
|
||||
name: Buildscript maintenance
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, main ]
|
||||
paths:
|
||||
- build.gradle
|
||||
workflow_dispatch: { }
|
||||
|
||||
jobs:
|
||||
buildscript-maintenance:
|
||||
runs-on: ubuntu-latest
|
||||
# Avoid running this workflow on forks
|
||||
if: github.repository == 'GTNewHorizons/ExampleMod1.7.10'
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Ensure build script version is up to date
|
||||
id: update-buildscript
|
||||
run: |
|
||||
new_version="$(date +%s)"
|
||||
sed --in-place "1s!^//version:.*!//version: $new_version!g" build.gradle
|
||||
echo "::set-output name=new_version::$new_version"
|
||||
|
||||
- name: Create Pull Request
|
||||
id: create-pull-request
|
||||
uses: peter-evans/create-pull-request@v4
|
||||
with:
|
||||
add-paths: build.gradle
|
||||
commit-message: '[ci skip] update build script version to ${{ steps.update-buildscript.outputs.new_version }}'
|
||||
branch: buildscript-maintenance
|
||||
title: Update build script version to ${{ steps.update-buildscript.outputs.new_version }}
|
||||
body: This pull request is created by the buildscript-maintenance workflow
|
||||
@@ -0,0 +1,86 @@
|
||||
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: Release latest starter and migration packages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, main ]
|
||||
tags: [ '*' ]
|
||||
|
||||
jobs:
|
||||
zip-and-release-packages:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set release version
|
||||
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: Prepare release folder
|
||||
run: |
|
||||
mkdir packages
|
||||
|
||||
- name: Zip starter
|
||||
uses: montudor/action-zip@v1
|
||||
with:
|
||||
args: >
|
||||
zip -r packages/starter.zip . \
|
||||
\
|
||||
-x "*.git/*" \
|
||||
\
|
||||
-x ".github/scripts/update_version" \
|
||||
-x ".github/workflows/buildscript-maintenance.yml" \
|
||||
-x ".github/workflows/release-packages.yml" \
|
||||
\
|
||||
-x "*docs/*" \
|
||||
-x "README.md" \
|
||||
-x "LICENSE" \
|
||||
-x "gtnhShared/*" \
|
||||
\
|
||||
-x "packages/" \
|
||||
-x "packages/starter.zip" \
|
||||
-x "packages/migration.zip"
|
||||
|
||||
- name: Zip migration
|
||||
uses: montudor/action-zip@v1
|
||||
with:
|
||||
args: >
|
||||
zip -r packages/migration.zip . \
|
||||
\
|
||||
-x "*.git/*" \
|
||||
\
|
||||
-x ".github/scripts/update_version" \
|
||||
-x ".github/workflows/buildscript-maintenance.yml" \
|
||||
-x ".github/workflows/release-packages.yml" \
|
||||
\
|
||||
-x "*docs/*" \
|
||||
-x "*src/*" \
|
||||
-x "LICENSE" \
|
||||
-x "README.md" \
|
||||
-x "gtnhShared/*" \
|
||||
\
|
||||
-x "packages/" \
|
||||
-x "packages/starter.zip" \
|
||||
-x "packages/migration.zip"
|
||||
|
||||
- name: Update latest tag
|
||||
uses: "marvinpinto/action-automatic-releases@latest"
|
||||
if: ${{ (github.ref == 'master' || github.ref == 'main') }}
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "latest-packages"
|
||||
prerelease: true
|
||||
title: "Latest starter and migration packages"
|
||||
files: packages/*
|
||||
|
||||
- name: Release named version
|
||||
if: ${{ !(github.ref == 'master' || github.ref == 'main') }}
|
||||
uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
automatic_release_tag: "${{ env.RELEASE_VERSION }}-packages"
|
||||
prerelease: false
|
||||
title: "${{ env.RELEASE_VERSION }} starter and migration packages"
|
||||
files: packages/*
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
name: Release tagged build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [ '*' ]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
release-tags:
|
||||
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/release-tags.yml@master
|
||||
secrets: inherit
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
.gradle
|
||||
.settings
|
||||
/.idea/
|
||||
/.vscode/
|
||||
/run/
|
||||
/build/
|
||||
/eclipse/
|
||||
.classpath
|
||||
.project
|
||||
/bin/
|
||||
/config/
|
||||
/crash-reports/
|
||||
/logs/
|
||||
options.txt
|
||||
/saves/
|
||||
usernamecache.json
|
||||
banned-ips.json
|
||||
banned-players.json
|
||||
eula.txt
|
||||
ops.json
|
||||
server.properties
|
||||
servers.dat
|
||||
usercache.json
|
||||
whitelist.json
|
||||
/out/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
src/main/resources/mixins.*([!.]).json
|
||||
*.bat
|
||||
*.DS_Store
|
||||
!gradlew.bat
|
||||
.factorypath
|
||||
addon.local.gradle
|
||||
addon.local.gradle.kts
|
||||
addon.late.local.gradle
|
||||
addon.late.local.gradle.kts
|
||||
layout.json
|
||||
@@ -0,0 +1,3 @@
|
||||
# Any Github changes require admin approval
|
||||
/.github/** @GTNewHorizons/admin
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Johann Bernhardt
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,80 @@
|
||||
# Example Forge Mod for Minecraft 1.7.10
|
||||
|
||||
[](https://jitpack.io/#GTNewHorizons/ExampleMod1.7.10)
|
||||
[](https://github.com/GTNewHorizons/ExampleMod1.7.10/actions/workflows/build-and-test.yml)
|
||||
|
||||
An example mod for Minecraft 1.7.10 with Forge focussed on a stable, updatable setup.
|
||||
|
||||
### Motivation
|
||||
|
||||
We had our fair share in struggles with build scripts for Minecraft Forge. There are quite a few pitfalls from non-obvious error messages. This Example Project provides you a build system you can adapt to over 90% of Minecraft Forge mods and can easily be updated if need be.
|
||||
|
||||
### Help! I'm stuck!
|
||||
|
||||
We all have been there! Check out our [FAQ](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/docs/FAQ.md). If that doesn't help, please open an issue.
|
||||
|
||||
### Getting started
|
||||
|
||||
Creating mod from scratch:
|
||||
1. Unzip [project starter](https://github.com/GTNewHorizons/ExampleMod1.7.10/releases/download/master-packages/starter.zip) into project directory.
|
||||
2. Replace placeholders in LICENSE-template and rename it to LICENSE, or remove LICENSE-template and put any other license you like on your code. This is an permissive OSS project and we encourage you participate in OSS movement by having permissive license like one in template. You can find out pros and cons of OSS software in [this article](https://www.freecodecamp.org/news/what-is-great-about-developing-open-source-and-what-is-not/)
|
||||
3. Ensure your project is under VCS. For example initialise git repository by running `git init; git commit --message "initialized repository"`.
|
||||
4. Replace placeholders (edit values in gradle.properties, change example package and class names, etc.)
|
||||
5. Run `./gradlew build`
|
||||
6. Make sure to check out the rest sections of this file.
|
||||
7. You are good to go!
|
||||
|
||||
We also have described guidelines for existing mod [migration](docs/migration.md) and [porting](docs/porting.md)
|
||||
|
||||
### Features
|
||||
|
||||
- Updatable: Replace [`build.gradle`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle) with a newer version
|
||||
- Optional API artifact (.jar)
|
||||
- Optional version replacement in Java files
|
||||
- Optional shadowing of dependencies
|
||||
- Simplified setup of Mixin and example
|
||||
- Scala support (add sources under `src/main/scala/` instead of `src/main/java/`)
|
||||
- Optional named developer account for consistent player progression during testing
|
||||
- Boilerplate forge mod as starting point
|
||||
- Improved warnings for pitfalls
|
||||
- Git Tags integration for versioning
|
||||
- [Jitpack](https://jitpack.io) CI
|
||||
- GitHub CI:
|
||||
- Releasing your artifacts on new tags pushed. Push git tag named after version (e.g. 1.0.0) which will trigger a release of artifacts with according names.
|
||||
- Running smoke test for server startup. On any server crash occurring workflow will fail and print the crash log.
|
||||
|
||||
### Files
|
||||
- [`build.gradle`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/build.gradle): This is the core script of the build process. You should not need to tamper with it, unless you are trying to accomplish something out of the ordinary. __Do not touch this file! You will make a future update near impossible if you do so!__
|
||||
- [`gradle.properties`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/gradle.properties): The core configuration file. It includes
|
||||
- [`dependencies.gradle[.kts]`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/dependencies.gradle): Add your mod's dependencies in this file. This is separate from the main build script, so you may replace the [`build.gradle`](https://github.com/SinTh0r4s/ExampleMod1.7.10/blob/main/build.gradle) if an update is available.
|
||||
- [`repositories.gradle[.kts]`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/repositories.gradle): Add your dependencies' repositories. This is separate from the main build script, so you may replace the [`build.gradle`](https://github.com/SinTh0r4s/ExampleMod1.7.10/blob/main/build.gradle) if an update is available.
|
||||
- [`jitpack.yml`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/jitpack.yml): Ensures that your mod is available as import over [Jitpack](https://jitpack.io).
|
||||
- [`.github/workflows/gradle.yml`](https://github.com/GTNewHorizons/ExampleMod1.7.10/blob/main/.github/workflows/gradle.yml): A simple CI script that will build your mod any time it is pushed to `master` or `main` and publish the result as release in your repository. This feature is free with GitHub if your repository is public.
|
||||
|
||||
### Forge's Access Transformers
|
||||
|
||||
You may activate Forge's Access Transformers by defining a configuration file in `gradle.properties`.
|
||||
|
||||
Check out the [`example-access-transformers`](https://github.com/GTNewHorizons/ExampleMod1.7.10/tree/example-access-transformers) brach for a working example!
|
||||
|
||||
__Warning:__ Access Transformers are bugged and will deny you any sources for the decompiled minecraft! Your development environment will still work, but you might face some inconveniences. For example, IntelliJ will not permit searches in dependencies without attached sources.
|
||||
|
||||
### Mixins
|
||||
|
||||
Mixins are usually used to modify vanilla or mod/library in runtime without having to change source code. For example, redirect a call, change visibility or make class implement your interface. It's an advanced topic and most mods don't need to do that.
|
||||
|
||||
You can activate Mixin in 'gradle.properties'. In that case a mixin configuration (usually named `mixins.mymodid.json`) will be generated automatically, and you only have to write the mixins itself. Dependencies are handled as well.
|
||||
Take a look at the examples in [Hodgepodge](https://github.com/GTNewHorizons/Hodgepodge/) and [Angelica](https://github.com/GTNewHorizons/Angelica/pull/8).
|
||||
|
||||
### Advanced
|
||||
|
||||
If your project requires custom gradle commands you may add a `addon.gradle[.kts]` to your project. It will be added automatically to the build script. Although we recommend against it, it is sometimes required. When in doubt, feel free to ask us about it. You may break future updates of this build system!
|
||||
If you need access to properties modified later in the buildscript, you can also use a `addon.late.gradle[.kts]`.
|
||||
For local tweaks that you don't want to commit to Git, like adding extra JVM arguments for testing, use `addon[.late].local.gradle[.kts]`.
|
||||
|
||||
### Feedback wanted
|
||||
|
||||
If you tried out this build script we would love to head your opinion! Is there any feature missing for you? Did something not work? Please open an issue and we will try to resolve it asap!
|
||||
|
||||
Happy modding, \
|
||||
[SinTh0r4s](https://github.com/SinTh0r4s), [TheElan](https://github.com/TheElan) and [basdxz](https://github.com/basdxz)
|
||||
+1608
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,6 @@
|
||||
#
|
||||
# https://help.github.com/articles/dealing-with-line-endings/
|
||||
#
|
||||
# These are explicitly windows files and should use crlf
|
||||
*.bat text eol=crlf
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# eclipse
|
||||
bin
|
||||
*.launch
|
||||
.settings
|
||||
.metadata
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# idea
|
||||
out
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
.idea
|
||||
|
||||
# gradle
|
||||
build
|
||||
.gradle
|
||||
|
||||
# other
|
||||
eclipse
|
||||
run
|
||||
mdmodsrepo
|
||||
|
||||
# Files from Forge MDK
|
||||
forge*changelog.txt
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 GeckoThePecko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,61 @@
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'maven-publish'
|
||||
|
||||
group project.group
|
||||
def snapshotVersion = System.getenv("GITHUB_RUN_NUMBER")
|
||||
version = snapshotVersion == null ? project.version : "SNAPSHOT-" + snapshotVersion
|
||||
archivesBaseName = project.archivesBaseName
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/' }
|
||||
maven {
|
||||
url "https://maven.cloudsmith.io/geckolib3/geckolib/"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.eliotlash.molang:molang:19'
|
||||
implementation 'com.eliotlash.mclib:mclib:19'
|
||||
implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.11'
|
||||
}
|
||||
|
||||
jar {
|
||||
from sourceSets.main.allSource
|
||||
manifest {
|
||||
attributes([
|
||||
"FMLModType" : "LIBRARY",
|
||||
"Specification-Title" : "geckolib",
|
||||
"Specification-Vendor" : "geckolib",
|
||||
"Specification-Version" : "1", // We are version 1 of ourselves
|
||||
"Implementation-Title" : project.name,
|
||||
"Implementation-Version" : "${version}",
|
||||
"Implementation-Vendor" : "geckolib",
|
||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
//classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
//classifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
}
|
||||
|
||||
configurations {
|
||||
runtimeElements {
|
||||
attributes {
|
||||
attribute(Attribute.of("com.gtnewhorizons.retrofuturagradle.obfuscation", String), 'mcp')
|
||||
attribute(Attribute.of("rfgDeobfuscatorTransformed", Boolean), true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#Publishing
|
||||
repsyUrl=https://repo.repsy.io/mvn/gandiber/geckolib
|
||||
version=1.0.14
|
||||
group=software.bernie.geckolib
|
||||
archivesBaseName=geckolib-core
|
||||
com.gtnewhorizons.retrofuturagradle.obfuscation=mcp
|
||||
rfgDeobfuscatorTransformed=true
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
Vendored
+172
@@ -0,0 +1,172 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
if expr "$link" : '/.*' > /dev/null; then
|
||||
PRG="$link"
|
||||
else
|
||||
PRG=`dirname "$PRG"`"/$link"
|
||||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=`basename "$0"`
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS=""
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD="maximum"
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
}
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
}
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "`uname`" in
|
||||
CYGWIN* )
|
||||
cygwin=true
|
||||
;;
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
nonstop=true
|
||||
;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD="$JAVA_HOME/jre/sh/java"
|
||||
else
|
||||
JAVACMD="$JAVA_HOME/bin/java"
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
|
||||
MAX_FD_LIMIT=`ulimit -H -n`
|
||||
if [ $? -eq 0 ] ; then
|
||||
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
|
||||
MAX_FD="$MAX_FD_LIMIT"
|
||||
fi
|
||||
ulimit -n $MAX_FD
|
||||
if [ $? -ne 0 ] ; then
|
||||
warn "Could not set maximum file descriptor limit: $MAX_FD"
|
||||
fi
|
||||
else
|
||||
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
|
||||
fi
|
||||
fi
|
||||
|
||||
# For Darwin, add options to specify how the application appears in the dock
|
||||
if $darwin; then
|
||||
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
|
||||
fi
|
||||
|
||||
# For Cygwin, switch paths to Windows format before running java
|
||||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
SEP=""
|
||||
for dir in $ROOTDIRSRAW ; do
|
||||
ROOTDIRS="$ROOTDIRS$SEP$dir"
|
||||
SEP="|"
|
||||
done
|
||||
OURCYGPATTERN="(^($ROOTDIRS))"
|
||||
# Add a user-defined pattern to the cygpath arguments
|
||||
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
|
||||
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
|
||||
fi
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
i=0
|
||||
for arg in "$@" ; do
|
||||
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
|
||||
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
|
||||
|
||||
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
|
||||
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
|
||||
else
|
||||
eval `echo args$i`="\"$arg\""
|
||||
fi
|
||||
i=$((i+1))
|
||||
done
|
||||
case $i in
|
||||
(0) set -- ;;
|
||||
(1) set -- "$args0" ;;
|
||||
(2) set -- "$args0" "$args1" ;;
|
||||
(3) set -- "$args0" "$args1" "$args2" ;;
|
||||
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
|
||||
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
|
||||
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
|
||||
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
|
||||
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
|
||||
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Escape application args
|
||||
save () {
|
||||
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
|
||||
echo " "
|
||||
}
|
||||
APP_ARGS=$(save "$@")
|
||||
|
||||
# Collect all arguments for the java command, following the shell quoting and substitution rules
|
||||
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
|
||||
|
||||
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
|
||||
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
|
||||
cd "$(dirname "$0")"
|
||||
fi
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+84
@@ -0,0 +1,84 @@
|
||||
@if "%DEBUG%" == "" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem 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=
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if "%ERRORLEVEL%" == "0" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto init
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:init
|
||||
@rem Get command-line arguments, handling Windows variants
|
||||
|
||||
if not "%OS%" == "Windows_NT" goto win9xME_args
|
||||
|
||||
:win9xME_args
|
||||
@rem Slurp the command line arguments.
|
||||
set CMD_LINE_ARGS=
|
||||
set _SKIP=2
|
||||
|
||||
:win9xME_args_slurp
|
||||
if "x%~1" == "x" goto execute
|
||||
|
||||
set CMD_LINE_ARGS=%*
|
||||
|
||||
: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 %CMD_LINE_ARGS%
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if "%ERRORLEVEL%"=="0" goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
|
||||
exit /b 1
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*
|
||||
* The settings file is used to specify which projects to include in your build.
|
||||
*
|
||||
* Detailed information about configuring a multi-project build in Gradle can be found
|
||||
* in the user guide at https://docs.gradle.org/4.10.3/userguide/multi_project_builds.html
|
||||
*/
|
||||
com.gtnewhorizons.retrofuturagradle.obfuscation='mcp'
|
||||
rfgDeobfuscatorTransformed='true'
|
||||
rootProject.name = 'geckolib-core'
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core;
|
||||
|
||||
public enum AnimationState {
|
||||
Running, Transitioning, Stopped;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package software.bernie.geckolib3.core;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
|
||||
public class ConstantValue implements IValue {
|
||||
private final double value;
|
||||
|
||||
public ConstantValue(double value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double get() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static ConstantValue fromDouble(double d) {
|
||||
return new ConstantValue(d);
|
||||
}
|
||||
|
||||
public static ConstantValue fromFloat(float d) {
|
||||
return new ConstantValue(d);
|
||||
}
|
||||
|
||||
public static ConstantValue parseDouble(String s) {
|
||||
return new ConstantValue(Double.parseDouble(s));
|
||||
}
|
||||
|
||||
public static ConstantValue parseFloat(String s) {
|
||||
return new ConstantValue(Float.parseFloat(s));
|
||||
}
|
||||
|
||||
public static ConstantValue subtract(IValue first, IValue second) {
|
||||
return ConstantValue.fromDouble(first.get() - second.get());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
package software.bernie.geckolib3.core;
|
||||
|
||||
import software.bernie.geckolib3.core.manager.AnimationData;
|
||||
import software.bernie.geckolib3.core.manager.AnimationFactory;
|
||||
|
||||
/**
|
||||
* This interface must be applied to any object that wants to be animated
|
||||
*/
|
||||
public interface IAnimatable {
|
||||
void registerControllers(AnimationData data);
|
||||
|
||||
AnimationFactory getFactory();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package software.bernie.geckolib3.core;
|
||||
|
||||
import software.bernie.geckolib3.core.builder.Animation;
|
||||
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
|
||||
import software.bernie.geckolib3.core.processor.AnimationProcessor;
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
|
||||
public interface IAnimatableModel<E> {
|
||||
default double getCurrentTick() {
|
||||
return (System.nanoTime() / 1000000L / 50.0);
|
||||
}
|
||||
|
||||
default void setLivingAnimations(E entity, Integer uniqueID) {
|
||||
this.setLivingAnimations(entity, uniqueID, null);
|
||||
}
|
||||
|
||||
void setLivingAnimations(E entity, Integer uniqueID, AnimationEvent customPredicate);
|
||||
|
||||
AnimationProcessor getAnimationProcessor();
|
||||
|
||||
Animation getAnimation(String name, IAnimatable animatable);
|
||||
|
||||
/**
|
||||
* Gets a bone by name.
|
||||
*
|
||||
* @param boneName The bone name
|
||||
* @return the bone
|
||||
*/
|
||||
default IBone getBone(String boneName) {
|
||||
IBone bone = this.getAnimationProcessor().getBone(boneName);
|
||||
if (bone == null) {
|
||||
throw new RuntimeException("Could not find bone: " + boneName);
|
||||
}
|
||||
return bone;
|
||||
}
|
||||
|
||||
void setMolangQueries(IAnimatable animatable, double currentTick);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package software.bernie.geckolib3.core;
|
||||
|
||||
public interface IAnimationTickable {
|
||||
public void tick();
|
||||
|
||||
public int tickTimer();
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package software.bernie.geckolib3.core;
|
||||
|
||||
public enum PlayState {
|
||||
CONTINUE, STOP
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package software.bernie.geckolib3.core.builder;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import software.bernie.geckolib3.core.builder.ILoopType.EDefaultLoopTypes;
|
||||
import software.bernie.geckolib3.core.keyframe.BoneAnimation;
|
||||
import software.bernie.geckolib3.core.keyframe.EventKeyFrame;
|
||||
import software.bernie.geckolib3.core.keyframe.ParticleEventKeyFrame;
|
||||
|
||||
public class Animation implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
public String animationName;
|
||||
public Double animationLength;
|
||||
public ILoopType loop;
|
||||
public List<BoneAnimation> boneAnimations;
|
||||
public List<EventKeyFrame<String>> soundKeyFrames;
|
||||
public List<ParticleEventKeyFrame> particleKeyFrames;
|
||||
public List<EventKeyFrame<String>> customInstructionKeyframes;
|
||||
|
||||
public Animation() {
|
||||
this.loop = EDefaultLoopTypes.LOOP;
|
||||
this.soundKeyFrames = new ArrayList();
|
||||
this.particleKeyFrames = new ArrayList();
|
||||
this.customInstructionKeyframes = new ArrayList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.builder;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import software.bernie.geckolib3.core.builder.ILoopType.EDefaultLoopTypes;
|
||||
|
||||
/**
|
||||
* This class follows the builder pattern, which means that every method returns
|
||||
* an instance of this class. You can stack method calls, like this:
|
||||
* <code>new AnimationBuilder().addAnimation("jump").addRepeatingAnimation("run", 5");</code>
|
||||
*/
|
||||
public class AnimationBuilder {
|
||||
private List<RawAnimation> animationList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Add a single animation to the queue and overrides the loop setting
|
||||
*
|
||||
* @param animationName The name of the animation. MUST MATCH THE NAME OF THE
|
||||
* ANIMATION IN THE BLOCKBENCH FILE
|
||||
* @param loopType loop
|
||||
* @return An instance of the current animation builder
|
||||
*/
|
||||
public AnimationBuilder addAnimation(String animationName, ILoopType loopType) {
|
||||
animationList.add(new RawAnimation(animationName, loopType));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public AnimationBuilder addAnimation(String animationName, Boolean shouldLoop) {
|
||||
animationList.add(new RawAnimation(animationName, shouldLoop));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a single animation to the queue
|
||||
*
|
||||
* @param animationName The name of the animation. MUST MATCH THE NAME OF THE
|
||||
* ANIMATION IN THE BLOCKBENCH FILE
|
||||
* @return An instance of the current animation builder
|
||||
*/
|
||||
public AnimationBuilder addAnimation(String animationName) {
|
||||
animationList.add(new RawAnimation(animationName, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add multiple animations to the queue and overrides the loop setting to false
|
||||
*
|
||||
* @param animationName The name of the animation. MUST MATCH THE NAME OF THE
|
||||
* ANIMATION IN THE BLOCKBENCH FILE
|
||||
* @param timesToRepeat How many times to add the animation to the queue
|
||||
* @return An instance of the current animation builder
|
||||
*/
|
||||
public AnimationBuilder addRepeatingAnimation(String animationName, int timesToRepeat) {
|
||||
assert timesToRepeat > 0;
|
||||
for (int i = 0; i < timesToRepeat; i++) {
|
||||
addAnimation(animationName, EDefaultLoopTypes.PLAY_ONCE);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public AnimationBuilder playOnce(String animationName) {
|
||||
return this.addAnimation(animationName, EDefaultLoopTypes.PLAY_ONCE);
|
||||
}
|
||||
|
||||
public AnimationBuilder loop(String animationName) {
|
||||
return this.addAnimation(animationName, EDefaultLoopTypes.LOOP);
|
||||
}
|
||||
|
||||
/*
|
||||
* Not implemented yet!
|
||||
*/
|
||||
public AnimationBuilder playAndHold(String animationName) {
|
||||
return this.addAnimation(animationName, EDefaultLoopTypes.HOLD_ON_LAST_FRAME);
|
||||
}
|
||||
|
||||
//Below will use "Wait instructions", basically empty animations that do nothing, not sure if we really need those honestly
|
||||
public AnimationBuilder delayNext(int waitTimeTicks) {
|
||||
throw new UnsupportedOperationException("This isn't implemented yet, sorry!");
|
||||
}
|
||||
|
||||
public AnimationBuilder playAndHoldFor(String animationName, int waitTimeTicks) {
|
||||
this.playAndHold(animationName);
|
||||
return this.delayNext(waitTimeTicks);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all the animations in the animation builder.
|
||||
*
|
||||
* @return An instance of the current animation builder
|
||||
*/
|
||||
public AnimationBuilder clearAnimations() {
|
||||
animationList.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animations currently in this builder.
|
||||
*/
|
||||
public List<RawAnimation> getRawAnimationList() {
|
||||
return animationList;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package software.bernie.geckolib3.core.builder;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface ILoopType extends Serializable {
|
||||
boolean isRepeatingAfterEnd();
|
||||
static final long serialVersionUID = 42L;
|
||||
enum EDefaultLoopTypes implements ILoopType {
|
||||
LOOP(true),
|
||||
PLAY_ONCE,
|
||||
HOLD_ON_LAST_FRAME;
|
||||
|
||||
private final boolean looping;
|
||||
|
||||
EDefaultLoopTypes(boolean looping) {
|
||||
this.looping = looping;
|
||||
}
|
||||
|
||||
EDefaultLoopTypes() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
public boolean isRepeatingAfterEnd() {
|
||||
return this.looping;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.builder;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import software.bernie.geckolib3.core.builder.ILoopType.EDefaultLoopTypes;
|
||||
|
||||
public class RawAnimation {
|
||||
public String animationName;
|
||||
|
||||
/**
|
||||
* If loop is null, the animation processor will use the loopByDefault boolean
|
||||
* to decide if the animation should loop.
|
||||
*/
|
||||
public ILoopType loopType;
|
||||
|
||||
/**
|
||||
* A raw animation only stores the animation name and if it should loop, nothing
|
||||
* else
|
||||
*
|
||||
* @param animationName The name of the animation
|
||||
* @param loop Whether it should loop
|
||||
*/
|
||||
public RawAnimation(String animationName, ILoopType loop) {
|
||||
this.animationName = animationName;
|
||||
this.loopType = loop;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public RawAnimation(String animationName, boolean loop) {
|
||||
this(animationName, loop ? EDefaultLoopTypes.LOOP : EDefaultLoopTypes.PLAY_ONCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this)
|
||||
return true;
|
||||
if (!(obj instanceof RawAnimation)) {
|
||||
return false;
|
||||
}
|
||||
RawAnimation animation = (RawAnimation) obj;
|
||||
if (animation.loopType == this.loopType && animation.animationName.equals(this.animationName)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(animationName, loopType);
|
||||
}
|
||||
}
|
||||
+745
@@ -0,0 +1,745 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.controller;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.molang.MolangParser;
|
||||
|
||||
import software.bernie.geckolib3.core.AnimationState;
|
||||
import software.bernie.geckolib3.core.ConstantValue;
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
import software.bernie.geckolib3.core.IAnimatableModel;
|
||||
import software.bernie.geckolib3.core.PlayState;
|
||||
import software.bernie.geckolib3.core.builder.Animation;
|
||||
import software.bernie.geckolib3.core.builder.AnimationBuilder;
|
||||
import software.bernie.geckolib3.core.builder.ILoopType;
|
||||
import software.bernie.geckolib3.core.easing.EasingType;
|
||||
import software.bernie.geckolib3.core.event.CustomInstructionKeyframeEvent;
|
||||
import software.bernie.geckolib3.core.event.ParticleKeyFrameEvent;
|
||||
import software.bernie.geckolib3.core.event.SoundKeyframeEvent;
|
||||
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
|
||||
import software.bernie.geckolib3.core.keyframe.AnimationPoint;
|
||||
import software.bernie.geckolib3.core.keyframe.BoneAnimation;
|
||||
import software.bernie.geckolib3.core.keyframe.BoneAnimationQueue;
|
||||
import software.bernie.geckolib3.core.keyframe.EventKeyFrame;
|
||||
import software.bernie.geckolib3.core.keyframe.KeyFrame;
|
||||
import software.bernie.geckolib3.core.keyframe.KeyFrameLocation;
|
||||
import software.bernie.geckolib3.core.keyframe.ParticleEventKeyFrame;
|
||||
import software.bernie.geckolib3.core.keyframe.VectorKeyFrameList;
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
import software.bernie.geckolib3.core.snapshot.BoneSnapshot;
|
||||
import software.bernie.geckolib3.core.util.Axis;
|
||||
|
||||
/**
|
||||
* The type Animation controller.
|
||||
*
|
||||
* @param <T> the type parameter
|
||||
*/
|
||||
public class AnimationController<T extends IAnimatable> {
|
||||
static List<ModelFetcher<?>> modelFetchers = new ArrayList<>();
|
||||
/**
|
||||
* The Entity.
|
||||
*/
|
||||
protected T animatable;
|
||||
/**
|
||||
* The animation predicate, is tested in every process call (i.e. every frame)
|
||||
*/
|
||||
protected IAnimationPredicate<T> animationPredicate;
|
||||
|
||||
/**
|
||||
* The name of the animation controller
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
protected AnimationState animationState = AnimationState.Stopped;
|
||||
|
||||
/**
|
||||
* How long it takes to transition between animations
|
||||
*/
|
||||
public double transitionLengthTicks;
|
||||
|
||||
/**
|
||||
* The sound listener is called every time a sound keyframe is encountered (i.e.
|
||||
* every frame)
|
||||
*/
|
||||
private ISoundListener<T> soundListener;
|
||||
|
||||
/**
|
||||
* The particle listener is called every time a particle keyframe is encountered
|
||||
* (i.e. every frame)
|
||||
*/
|
||||
private IParticleListener<T> particleListener;
|
||||
|
||||
/**
|
||||
* The custom instruction listener is called every time a custom instruction
|
||||
* keyframe is encountered (i.e. every frame)
|
||||
*/
|
||||
private ICustomInstructionListener<T> customInstructionListener;
|
||||
|
||||
public boolean isJustStarting = false;
|
||||
|
||||
public static void addModelFetcher(ModelFetcher<?> fetcher) {
|
||||
modelFetchers.add(fetcher);
|
||||
}
|
||||
|
||||
public static void removeModelFetcher(ModelFetcher<?> fetcher) {
|
||||
Objects.requireNonNull(fetcher);
|
||||
modelFetchers.remove(fetcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* An AnimationPredicate is run every render frame for ever AnimationController.
|
||||
* The "test" method is where you should change animations, stop animations,
|
||||
* restart, etc.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IAnimationPredicate<P extends IAnimatable> {
|
||||
/**
|
||||
* An AnimationPredicate is run every render frame for ever AnimationController.
|
||||
* The "test" method is where you should change animations, stop animations,
|
||||
* restart, etc.
|
||||
*
|
||||
* @return CONTINUE if the animation should continue, STOP if it should stop.
|
||||
*/
|
||||
PlayState test(AnimationEvent<P> event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sound Listeners are run when a sound keyframe is hit. You can either return
|
||||
* the SoundEvent and geckolib will play the sound for you, or return null and
|
||||
* handle the sounds yourself.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ISoundListener<A extends IAnimatable> {
|
||||
/**
|
||||
* Sound Listeners are run when a sound keyframe is hit. You can either return
|
||||
* the SoundEvent and geckolib will play the sound for you, or return null and
|
||||
* handle the sounds yourself.
|
||||
*/
|
||||
void playSound(SoundKeyframeEvent<A> event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Particle Listeners are run when a sound keyframe is hit. You need to handle
|
||||
* the actual playing of the particle yourself.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IParticleListener<A extends IAnimatable> {
|
||||
/**
|
||||
* Particle Listeners are run when a sound keyframe is hit. You need to handle
|
||||
* the actual playing of the particle yourself.
|
||||
*/
|
||||
void summonParticle(ParticleKeyFrameEvent<A> event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom instructions can be added in blockbench by enabling animation effects
|
||||
* in Animation - Animate Effects. You can then add custom instruction keyframes
|
||||
* and use them as timecodes/events to handle in code.
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ICustomInstructionListener<A extends IAnimatable> {
|
||||
/**
|
||||
* Custom instructions can be added in blockbench by enabling animation effects
|
||||
* in Animation - Animate Effects. You can then add custom instruction keyframes
|
||||
* and use them as timecodes/events to handle in code.
|
||||
*/
|
||||
void executeInstruction(CustomInstructionKeyframeEvent<A> event);
|
||||
}
|
||||
|
||||
private final HashMap<String, BoneAnimationQueue> boneAnimationQueues = new HashMap<>();
|
||||
public double tickOffset;
|
||||
protected Queue<Animation> animationQueue = new LinkedList<>();
|
||||
protected Animation currentAnimation;
|
||||
protected AnimationBuilder currentAnimationBuilder = new AnimationBuilder();
|
||||
protected boolean shouldResetTick = false;
|
||||
private final HashMap<String, BoneSnapshot> boneSnapshots = new HashMap<>();
|
||||
private boolean justStopped = false;
|
||||
protected boolean justStartedTransition = false;
|
||||
public Function<Double, Double> customEasingMethod;
|
||||
protected boolean needsAnimationReload = false;
|
||||
public double animationSpeed = 1D;
|
||||
private final Set<EventKeyFrame<?>> executedKeyFrames = new HashSet<>();
|
||||
|
||||
/**
|
||||
* This method sets the current animation with an animation builder. You can run
|
||||
* this method every frame, if you pass in the same animation builder every
|
||||
* time, it won't restart. Additionally, it smoothly transitions between
|
||||
* animation states.
|
||||
*/
|
||||
public void setAnimation(AnimationBuilder builder) {
|
||||
IAnimatableModel<T> model = getModel(this.animatable);
|
||||
if (model != null) {
|
||||
if (builder == null || builder.getRawAnimationList().size() == 0) {
|
||||
animationState = AnimationState.Stopped;
|
||||
} else if (!builder.getRawAnimationList().equals(currentAnimationBuilder.getRawAnimationList())
|
||||
|| needsAnimationReload) {
|
||||
AtomicBoolean encounteredError = new AtomicBoolean(false);
|
||||
// Convert the list of animation names to the actual list, keeping track of the
|
||||
// loop boolean along the way
|
||||
LinkedList<Animation> animations = builder.getRawAnimationList().stream().map((rawAnimation) -> {
|
||||
Animation animation = model.getAnimation(rawAnimation.animationName, animatable);
|
||||
if (animation == null) {
|
||||
System.out.printf("Could not load animation: %s. Is it missing?", rawAnimation.animationName);
|
||||
encounteredError.set(true);
|
||||
}
|
||||
if (animation != null && rawAnimation.loopType != null) {
|
||||
animation.loop = rawAnimation.loopType;
|
||||
}
|
||||
return animation;
|
||||
}).collect(Collectors.toCollection(LinkedList::new));
|
||||
|
||||
if (encounteredError.get()) {
|
||||
return;
|
||||
} else {
|
||||
animationQueue = animations;
|
||||
}
|
||||
currentAnimationBuilder = builder;
|
||||
|
||||
// Reset the adjusted tick to 0 on next animation process call
|
||||
shouldResetTick = true;
|
||||
this.animationState = AnimationState.Transitioning;
|
||||
justStartedTransition = true;
|
||||
needsAnimationReload = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* By default Geckolib uses the easing types of every keyframe. If you want to
|
||||
* override that for an entire AnimationController, change this value.
|
||||
*/
|
||||
public EasingType easingType = EasingType.NONE;
|
||||
|
||||
/**
|
||||
* Instantiates a new Animation controller. Each animation controller can run
|
||||
* one animation at a time. You can have several animation controllers for each
|
||||
* entity, i.e. one animation to control the entity's size, one to control
|
||||
* movement, attacks, etc.
|
||||
*
|
||||
* @param animatable The entity
|
||||
* @param name Name of the animation controller
|
||||
* (move_controller, size_controller,
|
||||
* attack_controller, etc.)
|
||||
* @param transitionLengthTicks How long it takes to transition between
|
||||
* animations (IN TICKS!!)
|
||||
*/
|
||||
public AnimationController(T animatable, String name, float transitionLengthTicks,
|
||||
IAnimationPredicate<T> animationPredicate) {
|
||||
this.animatable = animatable;
|
||||
this.name = name;
|
||||
this.transitionLengthTicks = transitionLengthTicks;
|
||||
this.animationPredicate = animationPredicate;
|
||||
tickOffset = 0.0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Animation controller. Each animation controller can run
|
||||
* one animation at a time. You can have several animation controllers for each
|
||||
* entity, i.e. one animation to control the entity's size, one to control
|
||||
* movement, attacks, etc.
|
||||
*
|
||||
* @param animatable The entity
|
||||
* @param name Name of the animation controller
|
||||
* (move_controller, size_controller,
|
||||
* attack_controller, etc.)
|
||||
* @param transitionLengthTicks How long it takes to transition between
|
||||
* animations (IN TICKS!!)
|
||||
* @param easingtype The method of easing to use. The other
|
||||
* constructor defaults to no easing.
|
||||
*/
|
||||
public AnimationController(T animatable, String name, float transitionLengthTicks, EasingType easingtype,
|
||||
IAnimationPredicate<T> animationPredicate) {
|
||||
this.animatable = animatable;
|
||||
this.name = name;
|
||||
this.transitionLengthTicks = transitionLengthTicks;
|
||||
this.easingType = easingtype;
|
||||
this.animationPredicate = animationPredicate;
|
||||
tickOffset = 0.0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a new Animation controller. Each animation controller can run
|
||||
* one animation at a time. You can have several animation controllers for each
|
||||
* entity, i.e. one animation to control the entity's size, one to control
|
||||
* movement, attacks, etc.
|
||||
*
|
||||
* @param animatable The entity
|
||||
* @param name Name of the animation controller
|
||||
* (move_controller, size_controller,
|
||||
* attack_controller, etc.)
|
||||
* @param transitionLengthTicks How long it takes to transition between
|
||||
* animations (IN TICKS!!)
|
||||
* @param customEasingMethod If you want to use an easing method that's not
|
||||
* included in the EasingType enum, pass your
|
||||
* method into here. The parameter that's passed in
|
||||
* will be a number between 0 and 1. Return a
|
||||
* number also within 0 and 1. Take a look at
|
||||
* {@link software.bernie.geckolib3.core.easing.EasingManager}
|
||||
*/
|
||||
public AnimationController(T animatable, String name, float transitionLengthTicks,
|
||||
Function<Double, Double> customEasingMethod, IAnimationPredicate<T> animationPredicate) {
|
||||
this.animatable = animatable;
|
||||
this.name = name;
|
||||
this.transitionLengthTicks = transitionLengthTicks;
|
||||
this.customEasingMethod = customEasingMethod;
|
||||
this.easingType = EasingType.CUSTOM;
|
||||
this.animationPredicate = animationPredicate;
|
||||
tickOffset = 0.0d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the controller's name.
|
||||
*
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current animation. Can be null
|
||||
*
|
||||
* @return the current animation
|
||||
*/
|
||||
|
||||
public Animation getCurrentAnimation() {
|
||||
return currentAnimation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current state of this animation controller.
|
||||
*/
|
||||
public AnimationState getAnimationState() {
|
||||
return animationState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current animation's bone animation queues.
|
||||
*
|
||||
* @return the bone animation queues
|
||||
*/
|
||||
public HashMap<String, BoneAnimationQueue> getBoneAnimationQueues() {
|
||||
return boneAnimationQueues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a sound listener.
|
||||
*/
|
||||
public void registerSoundListener(ISoundListener<T> soundListener) {
|
||||
this.soundListener = soundListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a particle listener.
|
||||
*/
|
||||
public void registerParticleListener(IParticleListener<T> particleListener) {
|
||||
this.particleListener = particleListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a custom instruction listener.
|
||||
*/
|
||||
public void registerCustomInstructionListener(ICustomInstructionListener<T> customInstructionListener) {
|
||||
this.customInstructionListener = customInstructionListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called every frame in order to populate the animation point
|
||||
* queues, and process animation state logic.
|
||||
*
|
||||
* @param tick The current tick + partial tick
|
||||
* @param event The animation test event
|
||||
* @param modelRendererList The list of all AnimatedModelRender's
|
||||
* @param boneSnapshotCollection The bone snapshot collection
|
||||
*/
|
||||
public void process(double tick, AnimationEvent<T> event, List<IBone> modelRendererList,
|
||||
HashMap<String, Pair<IBone, BoneSnapshot>> boneSnapshotCollection, MolangParser parser,
|
||||
boolean crashWhenCantFindBone) {
|
||||
parser.setValue("query.life_time", tick / 20);
|
||||
if (currentAnimation != null) {
|
||||
IAnimatableModel<T> model = getModel(this.animatable);
|
||||
if (model != null) {
|
||||
Animation animation = model.getAnimation(currentAnimation.animationName, this.animatable);
|
||||
if (animation != null) {
|
||||
ILoopType loop = currentAnimation.loop;
|
||||
currentAnimation = animation;
|
||||
currentAnimation.loop = loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createInitialQueues(modelRendererList);
|
||||
|
||||
double actualTick = tick;
|
||||
tick = adjustTick(tick);
|
||||
|
||||
// Transition period has ended, reset the tick and set the animation to running
|
||||
if (animationState == AnimationState.Transitioning && tick >= transitionLengthTicks) {
|
||||
this.shouldResetTick = true;
|
||||
animationState = AnimationState.Running;
|
||||
tick = adjustTick(actualTick);
|
||||
}
|
||||
|
||||
assert tick >= 0 : "GeckoLib: Tick was less than zero";
|
||||
|
||||
// This tests the animation predicate
|
||||
PlayState playState = this.testAnimationPredicate(event);
|
||||
if (playState == PlayState.STOP || (currentAnimation == null && animationQueue.size() == 0)) {
|
||||
// The animation should transition to the model's initial state
|
||||
animationState = AnimationState.Stopped;
|
||||
justStopped = true;
|
||||
return;
|
||||
}
|
||||
if (justStartedTransition && (shouldResetTick || justStopped)) {
|
||||
justStopped = false;
|
||||
tick = adjustTick(actualTick);
|
||||
} else if (currentAnimation == null && this.animationQueue.size() != 0) {
|
||||
this.shouldResetTick = true;
|
||||
this.animationState = AnimationState.Transitioning;
|
||||
justStartedTransition = true;
|
||||
needsAnimationReload = false;
|
||||
tick = adjustTick(actualTick);
|
||||
} else {
|
||||
if (animationState != AnimationState.Transitioning) {
|
||||
animationState = AnimationState.Running;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle transitioning to a different animation (or just starting one)
|
||||
if (animationState == AnimationState.Transitioning) {
|
||||
// Just started transitioning, so set the current animation to the first one
|
||||
if (tick == 0 || isJustStarting) {
|
||||
justStartedTransition = false;
|
||||
this.currentAnimation = animationQueue.poll();
|
||||
resetEventKeyFrames();
|
||||
saveSnapshotsForAnimation(currentAnimation, boneSnapshotCollection);
|
||||
}
|
||||
if (currentAnimation != null) {
|
||||
setAnimTime(parser, 0);
|
||||
for (BoneAnimation boneAnimation : currentAnimation.boneAnimations) {
|
||||
BoneAnimationQueue boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName);
|
||||
BoneSnapshot boneSnapshot = this.boneSnapshots.get(boneAnimation.boneName);
|
||||
Optional<IBone> first = modelRendererList.stream()
|
||||
.filter(x -> x.getName().equals(boneAnimation.boneName)).findFirst();
|
||||
if (!first.isPresent()) {
|
||||
if (crashWhenCantFindBone) {
|
||||
throw new RuntimeException("Could not find bone: " + boneAnimation.boneName);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BoneSnapshot initialSnapshot = first.get().getInitialSnapshot();
|
||||
assert boneSnapshot != null : "Bone snapshot was null";
|
||||
|
||||
VectorKeyFrameList<KeyFrame<IValue>> rotationKeyFrames = boneAnimation.rotationKeyFrames;
|
||||
VectorKeyFrameList<KeyFrame<IValue>> positionKeyFrames = boneAnimation.positionKeyFrames;
|
||||
VectorKeyFrameList<KeyFrame<IValue>> scaleKeyFrames = boneAnimation.scaleKeyFrames;
|
||||
|
||||
// Adding the initial positions of the upcoming animation, so the model
|
||||
// transitions to the initial state of the new animation
|
||||
if (!rotationKeyFrames.xKeyFrames.isEmpty()) {
|
||||
AnimationPoint xPoint = getAnimationPointAtTick(rotationKeyFrames.xKeyFrames, 0, true, Axis.X);
|
||||
AnimationPoint yPoint = getAnimationPointAtTick(rotationKeyFrames.yKeyFrames, 0, true, Axis.Y);
|
||||
AnimationPoint zPoint = getAnimationPointAtTick(rotationKeyFrames.zKeyFrames, 0, true, Axis.Z);
|
||||
boneAnimationQueue.rotationXQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.rotationValueX - initialSnapshot.rotationValueX,
|
||||
xPoint.animationStartValue));
|
||||
boneAnimationQueue.rotationYQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.rotationValueY - initialSnapshot.rotationValueY,
|
||||
yPoint.animationStartValue));
|
||||
boneAnimationQueue.rotationZQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.rotationValueZ - initialSnapshot.rotationValueZ,
|
||||
zPoint.animationStartValue));
|
||||
}
|
||||
|
||||
if (!positionKeyFrames.xKeyFrames.isEmpty()) {
|
||||
AnimationPoint xPoint = getAnimationPointAtTick(positionKeyFrames.xKeyFrames, 0, false, Axis.X);
|
||||
AnimationPoint yPoint = getAnimationPointAtTick(positionKeyFrames.yKeyFrames, 0, false, Axis.Y);
|
||||
AnimationPoint zPoint = getAnimationPointAtTick(positionKeyFrames.zKeyFrames, 0, false, Axis.Z);
|
||||
boneAnimationQueue.positionXQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.positionOffsetX, xPoint.animationStartValue));
|
||||
boneAnimationQueue.positionYQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.positionOffsetY, yPoint.animationStartValue));
|
||||
boneAnimationQueue.positionZQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.positionOffsetZ, zPoint.animationStartValue));
|
||||
}
|
||||
|
||||
if (!scaleKeyFrames.xKeyFrames.isEmpty()) {
|
||||
AnimationPoint xPoint = getAnimationPointAtTick(scaleKeyFrames.xKeyFrames, 0, false, Axis.X);
|
||||
AnimationPoint yPoint = getAnimationPointAtTick(scaleKeyFrames.yKeyFrames, 0, false, Axis.Y);
|
||||
AnimationPoint zPoint = getAnimationPointAtTick(scaleKeyFrames.zKeyFrames, 0, false, Axis.Z);
|
||||
boneAnimationQueue.scaleXQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.scaleValueX, xPoint.animationStartValue));
|
||||
boneAnimationQueue.scaleYQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.scaleValueY, yPoint.animationStartValue));
|
||||
boneAnimationQueue.scaleZQueue.add(new AnimationPoint(null, tick, transitionLengthTicks,
|
||||
boneSnapshot.scaleValueZ, zPoint.animationStartValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (getAnimationState() == AnimationState.Running) {
|
||||
// Actually run the animation
|
||||
processCurrentAnimation(tick, actualTick, parser, crashWhenCantFindBone);
|
||||
}
|
||||
}
|
||||
|
||||
private void setAnimTime(MolangParser parser, double tick) {
|
||||
parser.setValue("query.anim_time", tick / 20);
|
||||
}
|
||||
|
||||
private IAnimatableModel<T> getModel(T animatable) {
|
||||
for (ModelFetcher<?> modelFetcher : modelFetchers) {
|
||||
IAnimatableModel<T> model = (IAnimatableModel<T>) modelFetcher.apply(animatable);
|
||||
if (model != null) {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
System.out.printf(
|
||||
"Could not find suitable model for animatable of type %s. Did you register a Model Fetcher?%n",
|
||||
animatable.getClass());
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PlayState testAnimationPredicate(AnimationEvent<T> event) {
|
||||
return this.animationPredicate.test(event);
|
||||
}
|
||||
|
||||
// At the beginning of a new transition, save a snapshot of the model's
|
||||
// rotation, position, and scale values as the initial value to lerp from
|
||||
private void saveSnapshotsForAnimation(Animation animation,
|
||||
HashMap<String, Pair<IBone, BoneSnapshot>> boneSnapshotCollection) {
|
||||
for (Pair<IBone, BoneSnapshot> snapshot : boneSnapshotCollection.values()) {
|
||||
if (animation != null && animation.boneAnimations != null) {
|
||||
if (animation.boneAnimations.stream().anyMatch(x -> x.boneName.equals(snapshot.getLeft().getName()))) {
|
||||
this.boneSnapshots.put(snapshot.getLeft().getName(), new BoneSnapshot(snapshot.getRight()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void processCurrentAnimation(double tick, double actualTick, MolangParser parser,
|
||||
boolean crashWhenCantFindBone) {
|
||||
assert currentAnimation != null;
|
||||
// Animation has ended
|
||||
if (tick >= currentAnimation.animationLength) {
|
||||
resetEventKeyFrames();
|
||||
// If the current animation is set to loop, keep it as the current animation and
|
||||
// just start over
|
||||
if (!currentAnimation.loop.isRepeatingAfterEnd()) {
|
||||
// Pull the next animation from the queue
|
||||
Animation peek = animationQueue.peek();
|
||||
if (peek == null) {
|
||||
// No more animations left, stop the animation controller
|
||||
this.animationState = AnimationState.Stopped;
|
||||
return;
|
||||
} else {
|
||||
// Otherwise, set the state to transitioning and start transitioning to the next
|
||||
// animation next frame
|
||||
this.animationState = AnimationState.Transitioning;
|
||||
shouldResetTick = true;
|
||||
currentAnimation = this.animationQueue.peek();
|
||||
}
|
||||
} else {
|
||||
// Reset the adjusted tick so the next animation starts at tick 0
|
||||
shouldResetTick = true;
|
||||
tick = adjustTick(actualTick);
|
||||
}
|
||||
}
|
||||
setAnimTime(parser, tick);
|
||||
|
||||
// Loop through every boneanimation in the current animation and process the
|
||||
// values
|
||||
List<BoneAnimation> boneAnimations = currentAnimation.boneAnimations;
|
||||
for (BoneAnimation boneAnimation : boneAnimations) {
|
||||
BoneAnimationQueue boneAnimationQueue = boneAnimationQueues.get(boneAnimation.boneName);
|
||||
if (boneAnimationQueue == null) {
|
||||
if (crashWhenCantFindBone) {
|
||||
throw new RuntimeException("Could not find bone: " + boneAnimation.boneName);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
VectorKeyFrameList<KeyFrame<IValue>> rotationKeyFrames = boneAnimation.rotationKeyFrames;
|
||||
VectorKeyFrameList<KeyFrame<IValue>> positionKeyFrames = boneAnimation.positionKeyFrames;
|
||||
VectorKeyFrameList<KeyFrame<IValue>> scaleKeyFrames = boneAnimation.scaleKeyFrames;
|
||||
|
||||
if (!rotationKeyFrames.xKeyFrames.isEmpty()) {
|
||||
boneAnimationQueue.rotationXQueue
|
||||
.add(getAnimationPointAtTick(rotationKeyFrames.xKeyFrames, tick, true, Axis.X));
|
||||
boneAnimationQueue.rotationYQueue
|
||||
.add(getAnimationPointAtTick(rotationKeyFrames.yKeyFrames, tick, true, Axis.Y));
|
||||
boneAnimationQueue.rotationZQueue
|
||||
.add(getAnimationPointAtTick(rotationKeyFrames.zKeyFrames, tick, true, Axis.Z));
|
||||
}
|
||||
|
||||
if (!positionKeyFrames.xKeyFrames.isEmpty()) {
|
||||
boneAnimationQueue.positionXQueue
|
||||
.add(getAnimationPointAtTick(positionKeyFrames.xKeyFrames, tick, false, Axis.X));
|
||||
boneAnimationQueue.positionYQueue
|
||||
.add(getAnimationPointAtTick(positionKeyFrames.yKeyFrames, tick, false, Axis.Y));
|
||||
boneAnimationQueue.positionZQueue
|
||||
.add(getAnimationPointAtTick(positionKeyFrames.zKeyFrames, tick, false, Axis.Z));
|
||||
}
|
||||
|
||||
if (!scaleKeyFrames.xKeyFrames.isEmpty()) {
|
||||
boneAnimationQueue.scaleXQueue
|
||||
.add(getAnimationPointAtTick(scaleKeyFrames.xKeyFrames, tick, false, Axis.X));
|
||||
boneAnimationQueue.scaleYQueue
|
||||
.add(getAnimationPointAtTick(scaleKeyFrames.yKeyFrames, tick, false, Axis.Y));
|
||||
boneAnimationQueue.scaleZQueue
|
||||
.add(getAnimationPointAtTick(scaleKeyFrames.zKeyFrames, tick, false, Axis.Z));
|
||||
}
|
||||
}
|
||||
|
||||
if (soundListener != null || particleListener != null || customInstructionListener != null) {
|
||||
for (EventKeyFrame<String> soundKeyFrame : currentAnimation.soundKeyFrames) {
|
||||
if (!this.executedKeyFrames.contains(soundKeyFrame) && tick >= soundKeyFrame.getStartTick()) {
|
||||
SoundKeyframeEvent<T> event = new SoundKeyframeEvent<>(this.animatable, tick,
|
||||
soundKeyFrame.getEventData(), this);
|
||||
soundListener.playSound(event);
|
||||
|
||||
this.executedKeyFrames.add(soundKeyFrame);
|
||||
}
|
||||
}
|
||||
|
||||
for (ParticleEventKeyFrame particleEventKeyFrame : currentAnimation.particleKeyFrames) {
|
||||
if (!this.executedKeyFrames.contains(particleEventKeyFrame)
|
||||
&& tick >= particleEventKeyFrame.getStartTick()) {
|
||||
ParticleKeyFrameEvent<T> event = new ParticleKeyFrameEvent<>(this.animatable, tick,
|
||||
particleEventKeyFrame.effect, particleEventKeyFrame.locator, particleEventKeyFrame.script,
|
||||
this);
|
||||
particleListener.summonParticle(event);
|
||||
|
||||
this.executedKeyFrames.add(particleEventKeyFrame);
|
||||
}
|
||||
}
|
||||
|
||||
for (EventKeyFrame<String> customInstructionKeyFrame : currentAnimation.customInstructionKeyframes) {
|
||||
if (!this.executedKeyFrames.contains(customInstructionKeyFrame)
|
||||
&& tick >= customInstructionKeyFrame.getStartTick()) {
|
||||
CustomInstructionKeyframeEvent<T> event = new CustomInstructionKeyframeEvent<>(this.animatable,
|
||||
tick, customInstructionKeyFrame.getEventData(), this);
|
||||
customInstructionListener.executeInstruction(event);
|
||||
|
||||
this.executedKeyFrames.add(customInstructionKeyFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.transitionLengthTicks == 0 && shouldResetTick && this.animationState == AnimationState.Transitioning) {
|
||||
this.currentAnimation = animationQueue.poll();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to populate all the initial animation point queues
|
||||
private void createInitialQueues(List<IBone> modelRendererList) {
|
||||
boneAnimationQueues.clear();
|
||||
for (IBone modelRenderer : modelRendererList) {
|
||||
boneAnimationQueues.put(modelRenderer.getName(), new BoneAnimationQueue(modelRenderer));
|
||||
}
|
||||
}
|
||||
|
||||
// Used to reset the "tick" everytime a new animation starts, a transition
|
||||
// starts, or something else of importance happens
|
||||
protected double adjustTick(double tick) {
|
||||
if (shouldResetTick) {
|
||||
if (getAnimationState() == AnimationState.Transitioning) {
|
||||
this.tickOffset = tick;
|
||||
} else if (getAnimationState() == AnimationState.Running) {
|
||||
this.tickOffset = tick;
|
||||
}
|
||||
shouldResetTick = false;
|
||||
return 0;
|
||||
} else {
|
||||
// assert tick - this.tickOffset >= 0;
|
||||
return animationSpeed * Math.max(tick - tickOffset, 0.0D);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to transform a KeyFrameLocation to an AnimationPoint
|
||||
private AnimationPoint getAnimationPointAtTick(List<KeyFrame<IValue>> frames, double tick, boolean isRotation,
|
||||
Axis axis) {
|
||||
KeyFrameLocation<KeyFrame<IValue>> location = getCurrentKeyFrameLocation(frames, tick);
|
||||
KeyFrame<IValue> currentFrame = location.currentFrame;
|
||||
double startValue = currentFrame.getStartValue().get();
|
||||
double endValue = currentFrame.getEndValue().get();
|
||||
|
||||
if (isRotation) {
|
||||
if (!(currentFrame.getStartValue() instanceof ConstantValue)) {
|
||||
startValue = Math.toRadians(startValue);
|
||||
if (axis == Axis.X || axis == Axis.Y) {
|
||||
startValue *= -1;
|
||||
}
|
||||
}
|
||||
if (!(currentFrame.getEndValue() instanceof ConstantValue)) {
|
||||
endValue = Math.toRadians(endValue);
|
||||
if (axis == Axis.X || axis == Axis.Y) {
|
||||
endValue *= -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new AnimationPoint(currentFrame, location.currentTick, currentFrame.getLength(), startValue, endValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current keyframe object, plus how long the previous keyframes
|
||||
* have taken (aka elapsed animation time)
|
||||
**/
|
||||
private KeyFrameLocation<KeyFrame<IValue>> getCurrentKeyFrameLocation(List<KeyFrame<IValue>> frames,
|
||||
double ageInTicks) {
|
||||
double totalTimeTracker = 0;
|
||||
for (KeyFrame<IValue> frame : frames) {
|
||||
totalTimeTracker += frame.getLength();
|
||||
if (totalTimeTracker > ageInTicks) {
|
||||
double tick = (ageInTicks - (totalTimeTracker - frame.getLength()));
|
||||
return new KeyFrameLocation<>(frame, tick);
|
||||
}
|
||||
}
|
||||
return new KeyFrameLocation<>(frames.get(frames.size() - 1), ageInTicks);
|
||||
}
|
||||
|
||||
private void resetEventKeyFrames() {
|
||||
this.executedKeyFrames.clear();
|
||||
}
|
||||
|
||||
public void markNeedsReload() {
|
||||
this.needsAnimationReload = true;
|
||||
}
|
||||
|
||||
public void clearAnimationCache() {
|
||||
this.currentAnimationBuilder = new AnimationBuilder();
|
||||
}
|
||||
|
||||
public double getAnimationSpeed() {
|
||||
return animationSpeed;
|
||||
}
|
||||
|
||||
public void setAnimationSpeed(double animationSpeed) {
|
||||
this.animationSpeed = animationSpeed;
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface ModelFetcher<T> extends Function<IAnimatable, IAnimatableModel<T>> {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,373 @@
|
||||
package software.bernie.geckolib3.core.easing;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.DoubleStream;
|
||||
|
||||
import software.bernie.geckolib3.core.util.Memoizer;
|
||||
|
||||
public class EasingManager {
|
||||
static class EasingFunctionArgs {
|
||||
public final EasingType easingType;
|
||||
public final Double arg0;
|
||||
|
||||
public EasingFunctionArgs(EasingType easingType, Double arg0) {
|
||||
this.easingType = easingType;
|
||||
this.arg0 = arg0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
return true;
|
||||
if (o == null || getClass() != o.getClass())
|
||||
return false;
|
||||
EasingFunctionArgs that = (EasingFunctionArgs) o;
|
||||
return easingType == that.easingType && Objects.equals(arg0, that.arg0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(easingType, arg0);
|
||||
}
|
||||
}
|
||||
|
||||
public static double ease(double number, EasingType easingType, List<Double> easingArgs) {
|
||||
Double firstArg = easingArgs == null || easingArgs.size() < 1 ? null : easingArgs.get(0);
|
||||
return getEasingFunction.apply(new EasingFunctionArgs(easingType, firstArg)).apply(number);
|
||||
}
|
||||
|
||||
// Memoize easing functions so we don't need to create new ones from HOFs every
|
||||
// frame
|
||||
static Function<Double, Double> quart = poly(4);
|
||||
static Function<Double, Double> quint = poly(5);
|
||||
static Function<EasingFunctionArgs, Function<Double, Double>> getEasingFunction = Memoizer
|
||||
.memoize(EasingManager::getEasingFuncImpl);
|
||||
|
||||
// Don't call this, use getEasingFunction instead as that function is the
|
||||
// memoized version
|
||||
static Function<Double, Double> getEasingFuncImpl(EasingFunctionArgs args) {
|
||||
switch (args.easingType) {
|
||||
default:
|
||||
case Linear:
|
||||
return in(EasingManager::linear);
|
||||
case Step:
|
||||
return in(step(args.arg0));
|
||||
case EaseInSine:
|
||||
return in(EasingManager::sin);
|
||||
case EaseOutSine:
|
||||
return out(EasingManager::sin);
|
||||
case EaseInOutSine:
|
||||
return inOut(EasingManager::sin);
|
||||
case EaseInQuad:
|
||||
return in(EasingManager::quad);
|
||||
case EaseOutQuad:
|
||||
return out(EasingManager::quad);
|
||||
case EaseInOutQuad:
|
||||
return inOut(EasingManager::quad);
|
||||
case EaseInCubic:
|
||||
return in(EasingManager::cubic);
|
||||
case EaseOutCubic:
|
||||
return out(EasingManager::cubic);
|
||||
case EaseInOutCubic:
|
||||
return inOut(EasingManager::cubic);
|
||||
case EaseInExpo:
|
||||
return in(EasingManager::exp);
|
||||
case EaseOutExpo:
|
||||
return out(EasingManager::exp);
|
||||
case EaseInOutExpo:
|
||||
return inOut(EasingManager::exp);
|
||||
case EaseInCirc:
|
||||
return in(EasingManager::circle);
|
||||
case EaseOutCirc:
|
||||
return out(EasingManager::circle);
|
||||
case EaseInOutCirc:
|
||||
return inOut(EasingManager::circle);
|
||||
case EaseInQuart:
|
||||
return in(quart);
|
||||
case EaseOutQuart:
|
||||
return out(quart);
|
||||
case EaseInOutQuart:
|
||||
return inOut(quart);
|
||||
case EaseInQuint:
|
||||
return in(quint);
|
||||
case EaseOutQuint:
|
||||
return out(quint);
|
||||
case EaseInOutQuint:
|
||||
return inOut(quint);
|
||||
case EaseInBack:
|
||||
return in(back(args.arg0));
|
||||
case EaseOutBack:
|
||||
return out(back(args.arg0));
|
||||
case EaseInOutBack:
|
||||
return inOut(back(args.arg0));
|
||||
case EaseInElastic:
|
||||
return in(elastic(args.arg0));
|
||||
case EaseOutElastic:
|
||||
return out(elastic(args.arg0));
|
||||
case EaseInOutElastic:
|
||||
return inOut(elastic(args.arg0));
|
||||
case EaseInBounce:
|
||||
return in(bounce(args.arg0));
|
||||
case EaseOutBounce:
|
||||
return out(bounce(args.arg0));
|
||||
case EaseInOutBounce:
|
||||
return inOut(bounce(args.arg0));
|
||||
}
|
||||
}
|
||||
|
||||
// The MIT license notice below applies to the easing functions below except for
|
||||
// bounce and step
|
||||
/**
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the LICENSE file
|
||||
* in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runs an easing function forwards.
|
||||
*/
|
||||
static Function<Double, Double> in(Function<Double, Double> easing) {
|
||||
return easing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an easing function backwards.
|
||||
*/
|
||||
static Function<Double, Double> out(Function<Double, Double> easing) {
|
||||
return t -> 1 - easing.apply(1 - t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes any easing function symmetrical. The easing function will run forwards
|
||||
* for half of the duration, then backwards for the rest of the duration.
|
||||
*/
|
||||
static Function<Double, Double> inOut(Function<Double, Double> easing) {
|
||||
return t -> {
|
||||
if (t < 0.5) {
|
||||
return easing.apply(t * 2) / 2;
|
||||
}
|
||||
return 1 - easing.apply((1 - t) * 2) / 2;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* A stepping function, returns 1 for any positive value of `n`.
|
||||
*/
|
||||
static Function<Double, Double> step0() {
|
||||
return n -> n > 0 ? 1D : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A stepping function, returns 1 if `n` is greater than or equal to 1.
|
||||
*/
|
||||
static Function<Double, Double> step1() {
|
||||
return n -> n >= 1D ? 1D : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A linear function, `f(t) = t`. Position correlates to elapsed time one to
|
||||
* one.
|
||||
* <p>
|
||||
* http://cubic-bezier.com/#0,0,1,1
|
||||
*/
|
||||
static double linear(double t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inertial interaction, similar to an object slowly accelerating to
|
||||
* speed.
|
||||
*
|
||||
* http://cubic-bezier.com/#.42,0,1,1
|
||||
*/
|
||||
// static ease(t) {
|
||||
// if (!ease) {
|
||||
// ease = Easing.bezier(0.42, 0, 1, 1);
|
||||
// }
|
||||
// return ease(t);
|
||||
// }
|
||||
|
||||
/**
|
||||
* A quadratic function, `f(t) = t * t`. Position equals the square of elapsed
|
||||
* time.
|
||||
* <p>
|
||||
* http://easings.net/#easeInQuad
|
||||
*/
|
||||
static double quad(double t) {
|
||||
return t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A cubic function, `f(t) = t * t * t`. Position equals the cube of elapsed
|
||||
* time.
|
||||
* <p>
|
||||
* http://easings.net/#easeInCubic
|
||||
*/
|
||||
static double cubic(double t) {
|
||||
return t * t * t;
|
||||
}
|
||||
|
||||
/**
|
||||
* A power function. Position is equal to the Nth power of elapsed time.
|
||||
* <p>
|
||||
* n = 4: http://easings.net/#easeInQuart n = 5: http://easings.net/#easeInQuint
|
||||
*/
|
||||
static Function<Double, Double> poly(double n) {
|
||||
return (t) -> Math.pow(t, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* A sinusoidal function.
|
||||
* <p>
|
||||
* http://easings.net/#easeInSine
|
||||
*/
|
||||
static double sin(double t) {
|
||||
return 1 - Math.cos((float) ((t * Math.PI) / 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* A circular function.
|
||||
* <p>
|
||||
* http://easings.net/#easeInCirc
|
||||
*/
|
||||
static double circle(double t) {
|
||||
return 1 - Math.sqrt(1 - t * t);
|
||||
}
|
||||
|
||||
/**
|
||||
* An exponential function.
|
||||
* <p>
|
||||
* http://easings.net/#easeInExpo
|
||||
*/
|
||||
static double exp(double t) {
|
||||
return Math.pow(2, 10 * (t - 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple elastic interaction, similar to a spring oscillating back and forth.
|
||||
* <p>
|
||||
* Default bounciness is 1, which overshoots a little bit once. 0 bounciness
|
||||
* doesn't overshoot at all, and bounciness of N > 1 will overshoot about N
|
||||
* times.
|
||||
* <p>
|
||||
* http://easings.net/#easeInElastic
|
||||
*/
|
||||
static Function<Double, Double> elastic(Double bounciness) {
|
||||
double p = (bounciness == null ? 1 : bounciness) * Math.PI;
|
||||
return t -> 1 - Math.pow(Math.cos((float) ((t * Math.PI) / 2)), 3) * Math.cos((float) (t * p));
|
||||
}
|
||||
|
||||
/**
|
||||
* Use with `Animated.parallel()` to create a simple effect where the object
|
||||
* animates back slightly as the animation starts.
|
||||
* <p>
|
||||
* Wolfram Plot:
|
||||
* <p>
|
||||
* - http://tiny.cc/back_default (s = 1.70158, default)
|
||||
*/
|
||||
static Function<Double, Double> back(Double s) {
|
||||
double p = s == null ? 1.70158 : s * 1.70158;
|
||||
return t -> t * t * ((p + 1) * t - p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a simple bouncing effect.
|
||||
* <p>
|
||||
* Props to Waterded#6455 for making the bounce adjustable and GiantLuigi4#6616
|
||||
* for helping clean it up using min instead of ternaries
|
||||
* http://easings.net/#easeInBounce
|
||||
*/
|
||||
public static Function<Double, Double> bounce(Double s) {
|
||||
double k = s == null ? 0.5 : s;
|
||||
Function<Double, Double> q = x -> (121.0 / 16.0) * x * x;
|
||||
Function<Double, Double> w = x -> ((121.0 / 4.0) * k) * Math.pow(x - (6.0 / 11.0), 2) + 1 - k;
|
||||
Function<Double, Double> r = x -> 121 * k * k * Math.pow(x - (9.0 / 11.0), 2) + 1 - k * k;
|
||||
Function<Double, Double> t = x -> 484 * k * k * k * Math.pow(x - (10.5 / 11.0), 2) + 1 - k * k * k;
|
||||
return x -> min(q.apply(x), w.apply(x), r.apply(x), t.apply(x));
|
||||
}
|
||||
|
||||
static Function<Double, Double> step(Double stepArg) {
|
||||
int steps = stepArg != null ? stepArg.intValue() : 2;
|
||||
double[] intervals = stepRange(steps);
|
||||
return t -> intervals[findIntervalBorderIndex(t, intervals, false)];
|
||||
}
|
||||
|
||||
static double min(double a, double b, double c, double d) {
|
||||
return Math.min(Math.min(a, b), Math.min(c, d));
|
||||
}
|
||||
|
||||
// The MIT license notice below applies to the function findIntervalBorderIndex
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2015 Boris Chumichev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*
|
||||
* /**
|
||||
*
|
||||
* Utilizes bisection method to search an interval to which point belongs to,
|
||||
* then returns an index of left or right border of the interval
|
||||
*
|
||||
* @param {Number} point
|
||||
*
|
||||
* @param {Array} intervals
|
||||
*
|
||||
* @param {Boolean} useRightBorder
|
||||
*
|
||||
* @returns {Number}
|
||||
*/
|
||||
static int findIntervalBorderIndex(double point, double[] intervals, boolean useRightBorder) {
|
||||
// If point is beyond given intervals
|
||||
if (point < intervals[0])
|
||||
return 0;
|
||||
if (point > intervals[intervals.length - 1])
|
||||
return intervals.length - 1;
|
||||
// If point is inside interval
|
||||
// Start searching on a full range of intervals
|
||||
int indexOfNumberToCompare = 0;
|
||||
int leftBorderIndex = 0;
|
||||
int rightBorderIndex = intervals.length - 1;
|
||||
// Reduce searching range till it find an interval point belongs to using binary
|
||||
// search
|
||||
while (rightBorderIndex - leftBorderIndex != 1) {
|
||||
indexOfNumberToCompare = leftBorderIndex + (rightBorderIndex - leftBorderIndex) / 2;
|
||||
if (point >= intervals[indexOfNumberToCompare]) {
|
||||
leftBorderIndex = indexOfNumberToCompare;
|
||||
} else {
|
||||
rightBorderIndex = indexOfNumberToCompare;
|
||||
}
|
||||
}
|
||||
return useRightBorder ? rightBorderIndex : leftBorderIndex;
|
||||
}
|
||||
|
||||
static double[] stepRange(int steps) {
|
||||
final double stop = 1;
|
||||
if (steps < 2)
|
||||
throw new IllegalArgumentException("steps must be > 2, got:" + steps);
|
||||
double stepLength = stop / (double) steps;
|
||||
// There must be an easier way of doing this but I just don't care
|
||||
AtomicInteger i = new AtomicInteger();
|
||||
return DoubleStream.generate(() -> i.getAndIncrement() * stepLength).limit(steps).toArray();
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package software.bernie.geckolib3.core.easing;
|
||||
|
||||
public enum EasingType {
|
||||
NONE, CUSTOM, Linear, Step, EaseInSine, EaseOutSine, EaseInOutSine, EaseInQuad, EaseOutQuad, EaseInOutQuad,
|
||||
EaseInCubic, EaseOutCubic, EaseInOutCubic, EaseInQuart, EaseOutQuart, EaseInOutQuart, EaseInQuint, EaseOutQuint,
|
||||
EaseInOutQuint, EaseInExpo, EaseOutExpo, EaseInOutExpo, EaseInCirc, EaseOutCirc, EaseInOutCirc, EaseInBack,
|
||||
EaseOutBack, EaseInOutBack, EaseInElastic, EaseOutElastic, EaseInOutElastic, EaseInBounce, EaseOutBounce,
|
||||
EaseInOutBounce;
|
||||
|
||||
public static EasingType getEasingTypeFromString(String search) {
|
||||
for (EasingType each : EasingType.values()) {
|
||||
if (each.name().compareToIgnoreCase(search) == 0) {
|
||||
return each;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.event;
|
||||
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
|
||||
public class CustomInstructionKeyframeEvent<T> extends KeyframeEvent<T>
|
||||
{
|
||||
public final String instructions;
|
||||
|
||||
/**
|
||||
* This stores all the fields that are needed in the AnimationTestEvent
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param animationTick The amount of ticks that have passed in either the current transition or animation, depending on the controller's AnimationState.
|
||||
* @param instructions A list of all the custom instructions. In blockbench, each line in the custom instruction box is a separate instruction.
|
||||
* @param controller the controller
|
||||
*/
|
||||
public CustomInstructionKeyframeEvent(T entity, double animationTick, String instructions, AnimationController controller)
|
||||
{
|
||||
super(entity, animationTick, controller);
|
||||
this.instructions = instructions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.event;
|
||||
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
|
||||
public abstract class KeyframeEvent<T> {
|
||||
private final T entity;
|
||||
private final double animationTick;
|
||||
private final AnimationController controller;
|
||||
|
||||
/**
|
||||
* This stores all the fields that are needed in the AnimationTestEvent
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param animationTick The amount of ticks that have passed in either the
|
||||
* current transition or animation, depending on the
|
||||
* controller's AnimationState.
|
||||
* @param controller the controller
|
||||
*/
|
||||
public KeyframeEvent(T entity, double animationTick, AnimationController controller) {
|
||||
this.entity = entity;
|
||||
this.animationTick = animationTick;
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of ticks that have passed in either the current transition or
|
||||
* animation, depending on the controller's AnimationState.
|
||||
*
|
||||
* @return the animation tick
|
||||
*/
|
||||
public double getAnimationTick() {
|
||||
return animationTick;
|
||||
}
|
||||
|
||||
public T getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public AnimationController getController() {
|
||||
return controller;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package software.bernie.geckolib3.core.event;
|
||||
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
|
||||
public class ParticleKeyFrameEvent<T> extends KeyframeEvent<T> {
|
||||
public final String effect;
|
||||
public final String locator;
|
||||
public final String script;
|
||||
|
||||
/**
|
||||
* This stores all the fields that are needed in the AnimationTestEvent
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param animationTick The amount of ticks that have passed in either the
|
||||
* current transition or animation, depending on the
|
||||
* controller's AnimationState.
|
||||
* @param controller the controller
|
||||
*/
|
||||
public ParticleKeyFrameEvent(T entity, double animationTick, String effect, String locator, String script,
|
||||
AnimationController controller) {
|
||||
super(entity, animationTick, controller);
|
||||
this.effect = effect;
|
||||
this.locator = locator;
|
||||
this.script = script;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.event;
|
||||
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
|
||||
public class SoundKeyframeEvent<T> extends KeyframeEvent<T> {
|
||||
public final String sound;
|
||||
|
||||
/**
|
||||
* This stores all the fields that are needed in the AnimationTestEvent
|
||||
*
|
||||
* @param entity the entity
|
||||
* @param animationTick The amount of ticks that have passed in either the
|
||||
* current transition or animation, depending on the
|
||||
* controller's AnimationState.
|
||||
* @param sound The name of the sound to play
|
||||
* @param controller the controller
|
||||
*/
|
||||
public SoundKeyframeEvent(T entity, double animationTick, String sound, AnimationController controller) {
|
||||
super(entity, animationTick, controller);
|
||||
this.sound = sound;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package software.bernie.geckolib3.core.event.predicate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
|
||||
public class AnimationEvent<T extends IAnimatable> {
|
||||
private final T animatable;
|
||||
public double animationTick;
|
||||
private final float limbSwing;
|
||||
private final float limbSwingAmount;
|
||||
private final float partialTick;
|
||||
private final boolean isMoving;
|
||||
private final List<Object> extraData;
|
||||
protected AnimationController controller;
|
||||
|
||||
public AnimationEvent(T animatable, float limbSwing, float limbSwingAmount, float partialTick, boolean isMoving,
|
||||
List<Object> extraData) {
|
||||
this.animatable = animatable;
|
||||
this.limbSwing = limbSwing;
|
||||
this.limbSwingAmount = limbSwingAmount;
|
||||
this.partialTick = partialTick;
|
||||
this.isMoving = isMoving;
|
||||
this.extraData = extraData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of ticks that have passed in either the current transition or
|
||||
* animation, depending on the controller's AnimationState.
|
||||
*
|
||||
* @return the animation tick
|
||||
*/
|
||||
public double getAnimationTick() {
|
||||
return animationTick;
|
||||
}
|
||||
|
||||
public T getAnimatable() {
|
||||
return animatable;
|
||||
}
|
||||
|
||||
public float getLimbSwing() {
|
||||
return limbSwing;
|
||||
}
|
||||
|
||||
public float getLimbSwingAmount() {
|
||||
return limbSwingAmount;
|
||||
}
|
||||
|
||||
public float getPartialTick() {
|
||||
return partialTick;
|
||||
}
|
||||
|
||||
public boolean isMoving() {
|
||||
return isMoving;
|
||||
}
|
||||
|
||||
public AnimationController getController() {
|
||||
return controller;
|
||||
}
|
||||
|
||||
public void setController(AnimationController controller) {
|
||||
this.controller = controller;
|
||||
}
|
||||
|
||||
public List<Object> getExtraData() {
|
||||
return extraData;
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
public <T> List<T> getExtraDataOfType(Class<T> type) {
|
||||
return extraData.stream().filter(x -> type.isAssignableFrom(x.getClass())).map(x -> type.cast(x))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
|
||||
public class AnimationPoint {
|
||||
/**
|
||||
* The current tick in the animation to lerp from
|
||||
*/
|
||||
public final Double currentTick;
|
||||
/**
|
||||
* The tick that the current animation should end at
|
||||
*/
|
||||
public final Double animationEndTick;
|
||||
/**
|
||||
* The Animation start value.
|
||||
*/
|
||||
public final Double animationStartValue;
|
||||
/**
|
||||
* The Animation end value.
|
||||
*/
|
||||
public final Double animationEndValue;
|
||||
|
||||
/**
|
||||
* The current keyframe.
|
||||
*/
|
||||
|
||||
public final KeyFrame<IValue> keyframe;
|
||||
|
||||
public AnimationPoint(KeyFrame<IValue> keyframe, Double currentTick, Double animationEndTick,
|
||||
Double animationStartValue, Double animationEndValue) {
|
||||
this.keyframe = keyframe;
|
||||
this.currentTick = currentTick;
|
||||
this.animationEndTick = animationEndTick;
|
||||
this.animationStartValue = animationStartValue;
|
||||
this.animationEndValue = animationEndValue;
|
||||
}
|
||||
|
||||
public AnimationPoint(KeyFrame<IValue> keyframe, double tick, double animationEndTick, float animationStartValue,
|
||||
double animationEndValue) {
|
||||
this.keyframe = keyframe;
|
||||
this.currentTick = tick;
|
||||
this.animationEndTick = animationEndTick;
|
||||
this.animationStartValue = Double.valueOf(animationStartValue);
|
||||
this.animationEndValue = animationEndValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Tick: " + currentTick + " | End Tick: " + animationEndTick + " | Start Value: " + animationStartValue
|
||||
+ " | End Value: " + animationEndValue;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
|
||||
/**
|
||||
* An animation point queue holds a queue of Animation Points which are used in
|
||||
* the AnimatedEntityModel to lerp between values
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AnimationPointQueue extends LinkedList<AnimationPoint> {
|
||||
public IBone model;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class BoneAnimation implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
public String boneName;
|
||||
public VectorKeyFrameList<KeyFrame<IValue>> rotationKeyFrames;
|
||||
public VectorKeyFrameList<KeyFrame<IValue>> positionKeyFrames;
|
||||
public VectorKeyFrameList<KeyFrame<IValue>> scaleKeyFrames;
|
||||
|
||||
public BoneAnimation() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
|
||||
public class BoneAnimationQueue {
|
||||
public final IBone bone;
|
||||
public AnimationPointQueue rotationXQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue rotationYQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue rotationZQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue positionXQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue positionYQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue positionZQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue scaleXQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue scaleYQueue = new AnimationPointQueue();
|
||||
public AnimationPointQueue scaleZQueue = new AnimationPointQueue();
|
||||
|
||||
public BoneAnimationQueue(IBone bone) {
|
||||
this.bone = bone;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class EventKeyFrame<T> implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
private T eventData;
|
||||
private Double startTick;
|
||||
|
||||
public EventKeyFrame(Double startTick, T eventData) {
|
||||
this.startTick = startTick;
|
||||
this.eventData = eventData;
|
||||
}
|
||||
|
||||
public T getEventData() {
|
||||
return this.eventData;
|
||||
}
|
||||
|
||||
public Double getStartTick() {
|
||||
return this.startTick;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import software.bernie.geckolib3.core.easing.EasingType;
|
||||
|
||||
public class KeyFrame<T> implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
private Double length;
|
||||
private T startValue;
|
||||
private T endValue;
|
||||
public EasingType easingType;
|
||||
public List<Double> easingArgs;
|
||||
|
||||
public KeyFrame(Double length, T startValue, T endValue) {
|
||||
this.easingType = EasingType.Linear;
|
||||
this.easingArgs = new ArrayList();
|
||||
this.length = length;
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
}
|
||||
|
||||
public KeyFrame(Double length, T startValue, T endValue, EasingType easingType) {
|
||||
this.easingType = EasingType.Linear;
|
||||
this.easingArgs = new ArrayList();
|
||||
this.length = length;
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.easingType = easingType;
|
||||
}
|
||||
|
||||
public KeyFrame(Double length, T startValue, T endValue, EasingType easingType, List<Double> easingArgs) {
|
||||
this.easingType = EasingType.Linear;
|
||||
this.easingArgs = new ArrayList();
|
||||
this.length = length;
|
||||
this.startValue = startValue;
|
||||
this.endValue = endValue;
|
||||
this.easingType = easingType;
|
||||
this.easingArgs = easingArgs;
|
||||
}
|
||||
|
||||
public Double getLength() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
public void setLength(Double length) {
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
public T getStartValue() {
|
||||
return this.startValue;
|
||||
}
|
||||
|
||||
public void setStartValue(T startValue) {
|
||||
this.startValue = startValue;
|
||||
}
|
||||
|
||||
public T getEndValue() {
|
||||
return this.endValue;
|
||||
}
|
||||
|
||||
public void setEndValue(T endValue) {
|
||||
this.endValue = endValue;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return Objects.hash(new Object[]{this.length, this.startValue, this.endValue});
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof KeyFrame && this.hashCode() == obj.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
/**
|
||||
* This class stores a location in an animation, and returns the keyframe that
|
||||
* should be executed.
|
||||
*
|
||||
*/
|
||||
public class KeyFrameLocation<T extends KeyFrame> {
|
||||
/**
|
||||
* The curent frame.
|
||||
*/
|
||||
public T currentFrame;
|
||||
|
||||
/**
|
||||
* This is the combined total time of all the previous keyframes
|
||||
*/
|
||||
public double currentTick;
|
||||
|
||||
/**
|
||||
* Instantiates a new Key frame location.
|
||||
*
|
||||
* @param currentFrame the current frame
|
||||
* @param currentTick the current animation tick
|
||||
*/
|
||||
public KeyFrameLocation(T currentFrame, double currentTick) {
|
||||
this.currentFrame = currentFrame;
|
||||
this.currentTick = currentTick;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
public class ParticleEventKeyFrame extends EventKeyFrame<String> {
|
||||
public final String effect;
|
||||
public final String locator;
|
||||
public final String script;
|
||||
|
||||
public ParticleEventKeyFrame(Double startTick, String effect, String locator, String script) {
|
||||
super(startTick, effect + "\n" + locator + "\n" + script);
|
||||
this.script = script;
|
||||
this.locator = locator;
|
||||
this.effect = effect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventData() {
|
||||
return super.getEventData();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package software.bernie.geckolib3.core.keyframe;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class VectorKeyFrameList<T extends KeyFrame> implements Serializable {
|
||||
private static final long serialVersionUID = 42L;
|
||||
public List<T> xKeyFrames;
|
||||
public List<T> yKeyFrames;
|
||||
public List<T> zKeyFrames;
|
||||
|
||||
public VectorKeyFrameList(List<T> XKeyFrames, List<T> YKeyFrames, List<T> ZKeyFrames) {
|
||||
this.xKeyFrames = XKeyFrames;
|
||||
this.yKeyFrames = YKeyFrames;
|
||||
this.zKeyFrames = ZKeyFrames;
|
||||
}
|
||||
|
||||
public VectorKeyFrameList() {
|
||||
this.xKeyFrames = new ArrayList();
|
||||
this.yKeyFrames = new ArrayList();
|
||||
this.zKeyFrames = new ArrayList();
|
||||
}
|
||||
|
||||
public double getLastKeyframeTime() {
|
||||
double xTime = 0.0;
|
||||
|
||||
KeyFrame frame;
|
||||
for(Iterator var3 = this.xKeyFrames.iterator(); var3.hasNext(); xTime += frame.getLength()) {
|
||||
frame = (KeyFrame)var3.next();
|
||||
}
|
||||
|
||||
double yTime = 0.0;
|
||||
|
||||
for(Iterator var5 = this.yKeyFrames.iterator(); var5.hasNext(); yTime += frame.getLength()) {
|
||||
frame = (KeyFrame)var5.next();
|
||||
}
|
||||
|
||||
double zTime = 0.0;
|
||||
|
||||
for(Iterator var7 = this.zKeyFrames.iterator(); var7.hasNext(); zTime += frame.getLength()) {
|
||||
frame = (KeyFrame)var7.next();
|
||||
}
|
||||
|
||||
return Math.max(xTime, Math.max(yTime, zTime));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.manager;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
import software.bernie.geckolib3.core.snapshot.BoneSnapshot;
|
||||
|
||||
public class AnimationData {
|
||||
private HashMap<String, Pair<IBone, BoneSnapshot>> boneSnapshotCollection;
|
||||
private HashMap<String, AnimationController> animationControllers = new HashMap<>();
|
||||
public double tick;
|
||||
public boolean isFirstTick = true;
|
||||
private double resetTickLength = 1;
|
||||
public Double startTick;
|
||||
public Object ticker;
|
||||
public boolean shouldPlayWhilePaused = false;
|
||||
|
||||
/**
|
||||
* Instantiates a new Animation controller collection.
|
||||
*/
|
||||
public AnimationData() {
|
||||
super();
|
||||
boneSnapshotCollection = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is how you register animation controllers, without this, your
|
||||
* AnimationPredicate method will never be called
|
||||
*
|
||||
* @param value The value
|
||||
* @return the animation controller
|
||||
*/
|
||||
public AnimationController addAnimationController(AnimationController value) {
|
||||
return this.animationControllers.put(value.getName(), value);
|
||||
}
|
||||
|
||||
public HashMap<String, Pair<IBone, BoneSnapshot>> getBoneSnapshotCollection() {
|
||||
return boneSnapshotCollection;
|
||||
}
|
||||
|
||||
public void setBoneSnapshotCollection(HashMap<String, Pair<IBone, BoneSnapshot>> boneSnapshotCollection) {
|
||||
this.boneSnapshotCollection = boneSnapshotCollection;
|
||||
}
|
||||
|
||||
public void clearSnapshotCache() {
|
||||
this.boneSnapshotCollection = new HashMap<>();
|
||||
}
|
||||
|
||||
public double getResetSpeed() {
|
||||
return resetTickLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is how long it takes for any bones that don't have an animation to
|
||||
* revert back to their original position
|
||||
*
|
||||
* @param resetTickLength The amount of ticks it takes to reset. Cannot be
|
||||
* negative.
|
||||
*/
|
||||
public void setResetSpeedInTicks(double resetTickLength) {
|
||||
this.resetTickLength = resetTickLength < 0 ? 0 : resetTickLength;
|
||||
}
|
||||
|
||||
public HashMap<String, AnimationController> getAnimationControllers() {
|
||||
return animationControllers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package software.bernie.geckolib3.core.manager;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
|
||||
public class AnimationFactory {
|
||||
private final IAnimatable animatable;
|
||||
private HashMap<Integer, AnimationData> animationDataMap = new HashMap<>();
|
||||
|
||||
public AnimationFactory(IAnimatable animatable) {
|
||||
this.animatable = animatable;
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates or gets the cached animation manager for any unique ID. For
|
||||
* itemstacks, this is typically a hashcode of their nbt. For entities it should
|
||||
* be their unique uuid. For tile entities you can use nbt or just one constant
|
||||
* value since they are not singletons.
|
||||
*
|
||||
* @param uniqueID A unique integer ID. For every ID the same animation manager
|
||||
* will be returned.
|
||||
* @return the animatable manager
|
||||
*/
|
||||
public AnimationData getOrCreateAnimationData(Integer uniqueID) {
|
||||
if (!animationDataMap.containsKey(uniqueID)) {
|
||||
AnimationData data = new AnimationData();
|
||||
animatable.registerControllers(data);
|
||||
animationDataMap.put(uniqueID, data);
|
||||
}
|
||||
return animationDataMap.get(uniqueID);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
package software.bernie.geckolib3.core.processor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.eliotlash.molang.MolangParser;
|
||||
|
||||
import software.bernie.geckolib3.core.IAnimatable;
|
||||
import software.bernie.geckolib3.core.IAnimatableModel;
|
||||
import software.bernie.geckolib3.core.controller.AnimationController;
|
||||
import software.bernie.geckolib3.core.event.predicate.AnimationEvent;
|
||||
import software.bernie.geckolib3.core.keyframe.AnimationPoint;
|
||||
import software.bernie.geckolib3.core.keyframe.BoneAnimationQueue;
|
||||
import software.bernie.geckolib3.core.manager.AnimationData;
|
||||
import software.bernie.geckolib3.core.snapshot.BoneSnapshot;
|
||||
import software.bernie.geckolib3.core.snapshot.DirtyTracker;
|
||||
import software.bernie.geckolib3.core.util.MathUtil;
|
||||
|
||||
public class AnimationProcessor<T extends IAnimatable> {
|
||||
public boolean reloadAnimations = false;
|
||||
private List<IBone> modelRendererList = new ArrayList();
|
||||
private double lastTickValue = -1;
|
||||
private Set<Integer> animatedEntities = new HashSet<>();
|
||||
private final IAnimatableModel animatedModel;
|
||||
|
||||
public AnimationProcessor(IAnimatableModel animatedModel) {
|
||||
this.animatedModel = animatedModel;
|
||||
}
|
||||
|
||||
public void tickAnimation(IAnimatable entity, Integer uniqueID, double seekTime, AnimationEvent event,
|
||||
MolangParser parser, boolean crashWhenCantFindBone) {
|
||||
if (seekTime != lastTickValue) {
|
||||
animatedEntities.clear();
|
||||
} else if (animatedEntities.contains(uniqueID)) { // Entity already animated on this tick
|
||||
return;
|
||||
}
|
||||
|
||||
lastTickValue = seekTime;
|
||||
animatedEntities.add(uniqueID);
|
||||
|
||||
// Each animation has it's own collection of animations (called the
|
||||
// EntityAnimationManager), which allows for multiple independent animations
|
||||
AnimationData manager = entity.getFactory().getOrCreateAnimationData(uniqueID);
|
||||
// Keeps track of which bones have had animations applied to them, and
|
||||
// eventually sets the ones that don't have an animation to their default values
|
||||
HashMap<String, DirtyTracker> modelTracker = createNewDirtyTracker();
|
||||
|
||||
// Store the current value of each bone rotation/position/scale
|
||||
updateBoneSnapshots(manager.getBoneSnapshotCollection());
|
||||
|
||||
HashMap<String, Pair<IBone, BoneSnapshot>> boneSnapshots = manager.getBoneSnapshotCollection();
|
||||
|
||||
for (AnimationController<T> controller : manager.getAnimationControllers().values()) {
|
||||
if (reloadAnimations) {
|
||||
controller.markNeedsReload();
|
||||
controller.getBoneAnimationQueues().clear();
|
||||
}
|
||||
|
||||
controller.isJustStarting = manager.isFirstTick;
|
||||
|
||||
// Set current controller to animation test event
|
||||
event.setController(controller);
|
||||
|
||||
// Process animations and add new values to the point queues
|
||||
controller.process(seekTime, event, modelRendererList, boneSnapshots, parser, crashWhenCantFindBone);
|
||||
|
||||
// Loop through every single bone and lerp each property
|
||||
for (BoneAnimationQueue boneAnimation : controller.getBoneAnimationQueues().values()) {
|
||||
IBone bone = boneAnimation.bone;
|
||||
BoneSnapshot snapshot = boneSnapshots.get(bone.getName()).getRight();
|
||||
BoneSnapshot initialSnapshot = bone.getInitialSnapshot();
|
||||
|
||||
AnimationPoint rXPoint = boneAnimation.rotationXQueue.poll();
|
||||
AnimationPoint rYPoint = boneAnimation.rotationYQueue.poll();
|
||||
AnimationPoint rZPoint = boneAnimation.rotationZQueue.poll();
|
||||
|
||||
AnimationPoint pXPoint = boneAnimation.positionXQueue.poll();
|
||||
AnimationPoint pYPoint = boneAnimation.positionYQueue.poll();
|
||||
AnimationPoint pZPoint = boneAnimation.positionZQueue.poll();
|
||||
|
||||
AnimationPoint sXPoint = boneAnimation.scaleXQueue.poll();
|
||||
AnimationPoint sYPoint = boneAnimation.scaleYQueue.poll();
|
||||
AnimationPoint sZPoint = boneAnimation.scaleZQueue.poll();
|
||||
|
||||
// If there's any rotation points for this bone
|
||||
DirtyTracker dirtyTracker = modelTracker.get(bone.getName());
|
||||
if (dirtyTracker == null) {
|
||||
continue;
|
||||
}
|
||||
if (rXPoint != null && rYPoint != null && rZPoint != null) {
|
||||
bone.setRotationX(MathUtil.lerpValues(rXPoint, controller.easingType, controller.customEasingMethod)
|
||||
+ initialSnapshot.rotationValueX);
|
||||
bone.setRotationY(MathUtil.lerpValues(rYPoint, controller.easingType, controller.customEasingMethod)
|
||||
+ initialSnapshot.rotationValueY);
|
||||
bone.setRotationZ(MathUtil.lerpValues(rZPoint, controller.easingType, controller.customEasingMethod)
|
||||
+ initialSnapshot.rotationValueZ);
|
||||
snapshot.rotationValueX = bone.getRotationX();
|
||||
snapshot.rotationValueY = bone.getRotationY();
|
||||
snapshot.rotationValueZ = bone.getRotationZ();
|
||||
snapshot.isCurrentlyRunningRotationAnimation = true;
|
||||
dirtyTracker.hasRotationChanged = true;
|
||||
}
|
||||
|
||||
// If there's any position points for this bone
|
||||
if (pXPoint != null && pYPoint != null && pZPoint != null) {
|
||||
bone.setPositionX(
|
||||
MathUtil.lerpValues(pXPoint, controller.easingType, controller.customEasingMethod));
|
||||
bone.setPositionY(
|
||||
MathUtil.lerpValues(pYPoint, controller.easingType, controller.customEasingMethod));
|
||||
bone.setPositionZ(
|
||||
MathUtil.lerpValues(pZPoint, controller.easingType, controller.customEasingMethod));
|
||||
snapshot.positionOffsetX = bone.getPositionX();
|
||||
snapshot.positionOffsetY = bone.getPositionY();
|
||||
snapshot.positionOffsetZ = bone.getPositionZ();
|
||||
snapshot.isCurrentlyRunningPositionAnimation = true;
|
||||
|
||||
dirtyTracker.hasPositionChanged = true;
|
||||
}
|
||||
|
||||
// If there's any scale points for this bone
|
||||
if (sXPoint != null && sYPoint != null && sZPoint != null) {
|
||||
bone.setScaleX(MathUtil.lerpValues(sXPoint, controller.easingType, controller.customEasingMethod));
|
||||
bone.setScaleY(MathUtil.lerpValues(sYPoint, controller.easingType, controller.customEasingMethod));
|
||||
bone.setScaleZ(MathUtil.lerpValues(sZPoint, controller.easingType, controller.customEasingMethod));
|
||||
snapshot.scaleValueX = bone.getScaleX();
|
||||
snapshot.scaleValueY = bone.getScaleY();
|
||||
snapshot.scaleValueZ = bone.getScaleZ();
|
||||
snapshot.isCurrentlyRunningScaleAnimation = true;
|
||||
|
||||
dirtyTracker.hasScaleChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.reloadAnimations = false;
|
||||
|
||||
double resetTickLength = manager.getResetSpeed();
|
||||
for (Map.Entry<String, DirtyTracker> tracker : modelTracker.entrySet()) {
|
||||
IBone model = tracker.getValue().model;
|
||||
BoneSnapshot initialSnapshot = model.getInitialSnapshot();
|
||||
BoneSnapshot saveSnapshot = boneSnapshots.get(tracker.getKey()).getRight();
|
||||
if (saveSnapshot == null) {
|
||||
if (crashWhenCantFindBone) {
|
||||
throw new RuntimeException(
|
||||
"Could not find save snapshot for bone: " + tracker.getValue().model.getName()
|
||||
+ ". Please don't add bones that are used in an animation at runtime.");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tracker.getValue().hasRotationChanged) {
|
||||
if (saveSnapshot.isCurrentlyRunningRotationAnimation) {
|
||||
saveSnapshot.mostRecentResetRotationTick = (float) seekTime;
|
||||
saveSnapshot.isCurrentlyRunningRotationAnimation = false;
|
||||
}
|
||||
|
||||
double percentageReset = Math
|
||||
.min((seekTime - saveSnapshot.mostRecentResetRotationTick) / resetTickLength, 1);
|
||||
|
||||
model.setRotationX(MathUtil.lerpValues(percentageReset, saveSnapshot.rotationValueX,
|
||||
initialSnapshot.rotationValueX));
|
||||
model.setRotationY(MathUtil.lerpValues(percentageReset, saveSnapshot.rotationValueY,
|
||||
initialSnapshot.rotationValueY));
|
||||
model.setRotationZ(MathUtil.lerpValues(percentageReset, saveSnapshot.rotationValueZ,
|
||||
initialSnapshot.rotationValueZ));
|
||||
|
||||
if (percentageReset >= 1) {
|
||||
saveSnapshot.rotationValueX = model.getRotationX();
|
||||
saveSnapshot.rotationValueY = model.getRotationY();
|
||||
saveSnapshot.rotationValueZ = model.getRotationZ();
|
||||
}
|
||||
}
|
||||
if (!tracker.getValue().hasPositionChanged) {
|
||||
if (saveSnapshot.isCurrentlyRunningPositionAnimation) {
|
||||
saveSnapshot.mostRecentResetPositionTick = (float) seekTime;
|
||||
saveSnapshot.isCurrentlyRunningPositionAnimation = false;
|
||||
}
|
||||
|
||||
double percentageReset = Math
|
||||
.min((seekTime - saveSnapshot.mostRecentResetPositionTick) / resetTickLength, 1);
|
||||
|
||||
model.setPositionX(MathUtil.lerpValues(percentageReset, saveSnapshot.positionOffsetX,
|
||||
initialSnapshot.positionOffsetX));
|
||||
model.setPositionY(MathUtil.lerpValues(percentageReset, saveSnapshot.positionOffsetY,
|
||||
initialSnapshot.positionOffsetY));
|
||||
model.setPositionZ(MathUtil.lerpValues(percentageReset, saveSnapshot.positionOffsetZ,
|
||||
initialSnapshot.positionOffsetZ));
|
||||
|
||||
if (percentageReset >= 1) {
|
||||
saveSnapshot.positionOffsetX = model.getPositionX();
|
||||
saveSnapshot.positionOffsetY = model.getPositionY();
|
||||
saveSnapshot.positionOffsetZ = model.getPositionZ();
|
||||
}
|
||||
}
|
||||
if (!tracker.getValue().hasScaleChanged) {
|
||||
if (saveSnapshot.isCurrentlyRunningScaleAnimation) {
|
||||
saveSnapshot.mostRecentResetScaleTick = (float) seekTime;
|
||||
saveSnapshot.isCurrentlyRunningScaleAnimation = false;
|
||||
}
|
||||
|
||||
double percentageReset = Math.min((seekTime - saveSnapshot.mostRecentResetScaleTick) / resetTickLength,
|
||||
1);
|
||||
|
||||
model.setScaleX(
|
||||
MathUtil.lerpValues(percentageReset, saveSnapshot.scaleValueX, initialSnapshot.scaleValueX));
|
||||
model.setScaleY(
|
||||
MathUtil.lerpValues(percentageReset, saveSnapshot.scaleValueY, initialSnapshot.scaleValueY));
|
||||
model.setScaleZ(
|
||||
MathUtil.lerpValues(percentageReset, saveSnapshot.scaleValueZ, initialSnapshot.scaleValueZ));
|
||||
|
||||
if (percentageReset >= 1) {
|
||||
saveSnapshot.scaleValueX = model.getScaleX();
|
||||
saveSnapshot.scaleValueY = model.getScaleY();
|
||||
saveSnapshot.scaleValueZ = model.getScaleZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
manager.isFirstTick = false;
|
||||
}
|
||||
|
||||
private HashMap<String, DirtyTracker> createNewDirtyTracker() {
|
||||
HashMap<String, DirtyTracker> tracker = new HashMap<>();
|
||||
for (IBone bone : modelRendererList) {
|
||||
tracker.put(bone.getName(), new DirtyTracker(false, false, false, bone));
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
|
||||
private void updateBoneSnapshots(HashMap<String, Pair<IBone, BoneSnapshot>> boneSnapshotCollection) {
|
||||
for (IBone bone : modelRendererList) {
|
||||
if (!boneSnapshotCollection.containsKey(bone.getName())) {
|
||||
boneSnapshotCollection.put(bone.getName(), Pair.of(bone, new BoneSnapshot(bone.getInitialSnapshot())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a bone by name.
|
||||
*
|
||||
* @param boneName The bone name
|
||||
* @return the bone
|
||||
*/
|
||||
public IBone getBone(String boneName) {
|
||||
return modelRendererList.stream().filter(x -> x.getName().equals(boneName)).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register model renderer. Each AnimatedModelRenderer (group in blockbench)
|
||||
* NEEDS to be registered via this method.
|
||||
*
|
||||
* @param modelRenderer The model renderer
|
||||
*/
|
||||
public void registerModelRenderer(IBone modelRenderer) {
|
||||
modelRenderer.saveInitialSnapshot();
|
||||
modelRendererList.add(modelRenderer);
|
||||
}
|
||||
|
||||
public void clearModelRendererList() {
|
||||
this.modelRendererList.clear();
|
||||
}
|
||||
|
||||
public List<IBone> getModelRendererList() {
|
||||
return modelRendererList;
|
||||
}
|
||||
|
||||
public void preAnimationSetup(IAnimatable animatable, double seekTime) {
|
||||
this.animatedModel.setMolangQueries(animatable, seekTime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package software.bernie.geckolib3.core.processor;
|
||||
|
||||
import software.bernie.geckolib3.core.snapshot.BoneSnapshot;
|
||||
|
||||
public interface IBone {
|
||||
float getRotationX();
|
||||
|
||||
float getRotationY();
|
||||
|
||||
float getRotationZ();
|
||||
|
||||
float getPositionX();
|
||||
|
||||
float getPositionY();
|
||||
|
||||
float getPositionZ();
|
||||
|
||||
float getScaleX();
|
||||
|
||||
float getScaleY();
|
||||
|
||||
float getScaleZ();
|
||||
|
||||
void setRotationX(float value);
|
||||
|
||||
void setRotationY(float value);
|
||||
|
||||
void setRotationZ(float value);
|
||||
|
||||
void setPositionX(float value);
|
||||
|
||||
void setPositionY(float value);
|
||||
|
||||
void setPositionZ(float value);
|
||||
|
||||
void setScaleX(float value);
|
||||
|
||||
void setScaleY(float value);
|
||||
|
||||
void setScaleZ(float value);
|
||||
|
||||
void setPivotX(float value);
|
||||
|
||||
void setPivotY(float value);
|
||||
|
||||
void setPivotZ(float value);
|
||||
|
||||
float getPivotX();
|
||||
|
||||
float getPivotY();
|
||||
|
||||
float getPivotZ();
|
||||
|
||||
boolean isHidden();
|
||||
|
||||
boolean cubesAreHidden();
|
||||
|
||||
boolean childBonesAreHiddenToo();
|
||||
|
||||
void setHidden(boolean hidden);
|
||||
|
||||
void setCubesHidden(boolean hidden);
|
||||
|
||||
void setHidden(boolean selfHidden, boolean skipChildRendering);
|
||||
|
||||
void setModelRendererName(String modelRendererName);
|
||||
|
||||
void saveInitialSnapshot();
|
||||
|
||||
BoneSnapshot getInitialSnapshot();
|
||||
|
||||
default BoneSnapshot saveSnapshot() {
|
||||
return new BoneSnapshot(this);
|
||||
}
|
||||
|
||||
String getName();
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.snapshot;
|
||||
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
|
||||
public class BoneSnapshot {
|
||||
public BoneSnapshot(IBone modelRenderer) {
|
||||
rotationValueX = modelRenderer.getRotationX();
|
||||
rotationValueY = modelRenderer.getRotationY();
|
||||
rotationValueZ = modelRenderer.getRotationZ();
|
||||
|
||||
positionOffsetX = modelRenderer.getPositionX();
|
||||
positionOffsetY = modelRenderer.getPositionY();
|
||||
positionOffsetZ = modelRenderer.getPositionZ();
|
||||
|
||||
scaleValueX = modelRenderer.getScaleX();
|
||||
scaleValueY = modelRenderer.getScaleY();
|
||||
scaleValueZ = modelRenderer.getScaleZ();
|
||||
|
||||
this.modelRenderer = modelRenderer;
|
||||
this.name = modelRenderer.getName();
|
||||
}
|
||||
|
||||
public BoneSnapshot(IBone modelRenderer, boolean dontSaveRotations) {
|
||||
if (dontSaveRotations) {
|
||||
rotationValueX = 0;
|
||||
rotationValueY = 0;
|
||||
rotationValueZ = 0;
|
||||
}
|
||||
|
||||
rotationValueX = modelRenderer.getRotationX();
|
||||
rotationValueY = modelRenderer.getRotationY();
|
||||
rotationValueZ = modelRenderer.getRotationZ();
|
||||
|
||||
positionOffsetX = modelRenderer.getPositionX();
|
||||
positionOffsetY = modelRenderer.getPositionY();
|
||||
positionOffsetZ = modelRenderer.getPositionZ();
|
||||
|
||||
scaleValueX = modelRenderer.getScaleX();
|
||||
scaleValueY = modelRenderer.getScaleY();
|
||||
scaleValueZ = modelRenderer.getScaleZ();
|
||||
|
||||
this.modelRenderer = modelRenderer;
|
||||
this.name = modelRenderer.getName();
|
||||
}
|
||||
|
||||
public BoneSnapshot(BoneSnapshot snapshot) {
|
||||
scaleValueX = snapshot.scaleValueX;
|
||||
scaleValueY = snapshot.scaleValueY;
|
||||
scaleValueZ = snapshot.scaleValueZ;
|
||||
|
||||
positionOffsetX = snapshot.positionOffsetX;
|
||||
positionOffsetY = snapshot.positionOffsetY;
|
||||
positionOffsetZ = snapshot.positionOffsetZ;
|
||||
|
||||
rotationValueX = snapshot.rotationValueX;
|
||||
rotationValueY = snapshot.rotationValueY;
|
||||
rotationValueZ = snapshot.rotationValueZ;
|
||||
this.modelRenderer = snapshot.modelRenderer;
|
||||
this.name = snapshot.name;
|
||||
}
|
||||
|
||||
public String name;
|
||||
private IBone modelRenderer;
|
||||
|
||||
public float scaleValueX;
|
||||
public float scaleValueY;
|
||||
public float scaleValueZ;
|
||||
|
||||
public float positionOffsetX;
|
||||
public float positionOffsetY;
|
||||
public float positionOffsetZ;
|
||||
|
||||
public float rotationValueX;
|
||||
public float rotationValueY;
|
||||
public float rotationValueZ;
|
||||
|
||||
public float mostRecentResetRotationTick = 0;
|
||||
public float mostRecentResetPositionTick = 0;
|
||||
public float mostRecentResetScaleTick = 0;
|
||||
|
||||
public boolean isCurrentlyRunningRotationAnimation = true;
|
||||
public boolean isCurrentlyRunningPositionAnimation = true;
|
||||
public boolean isCurrentlyRunningScaleAnimation = true;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
BoneSnapshot that = (BoneSnapshot) o;
|
||||
return name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) 2020.
|
||||
* Author: Bernie G. (Gecko)
|
||||
*/
|
||||
|
||||
package software.bernie.geckolib3.core.snapshot;
|
||||
|
||||
import software.bernie.geckolib3.core.processor.IBone;
|
||||
|
||||
public class DirtyTracker {
|
||||
public IBone model;
|
||||
public boolean hasScaleChanged;
|
||||
public boolean hasPositionChanged;
|
||||
public boolean hasRotationChanged;
|
||||
|
||||
public DirtyTracker(boolean hasScaleChanged, boolean hasPositionChanged, boolean hasRotationChanged, IBone model) {
|
||||
this.hasScaleChanged = hasScaleChanged;
|
||||
this.hasPositionChanged = hasPositionChanged;
|
||||
this.hasRotationChanged = hasRotationChanged;
|
||||
this.model = model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package software.bernie.geckolib3.core.util;
|
||||
|
||||
public enum Axis {
|
||||
X, Y, Z
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
Direct copy of https://github.com/shedaniel/cloth-basic-math/blob/master/src/main/java/me/shedaniel/math/Color.java under the unlicense.
|
||||
*/
|
||||
package software.bernie.geckolib3.core.util;
|
||||
|
||||
public final class Color {
|
||||
private final int color;
|
||||
|
||||
public static final Color WHITE = new Color(0xFFFFFFFF);
|
||||
|
||||
public static final Color LIGHT_GRAY = new Color(0xFFC0C0C0);
|
||||
|
||||
public static final Color GRAY = new Color(0xFF808080);
|
||||
|
||||
public static final Color DARK_GRAY = new Color(0xFF404040);
|
||||
|
||||
public static final Color BLACK = new Color(0xFF000000);
|
||||
|
||||
public static final Color RED = new Color(0xFFFF0000);
|
||||
|
||||
public static final Color PINK = new Color(0xFFFFAFAF);
|
||||
|
||||
public static final Color ORANGE = new Color(0xFFFFC800);
|
||||
|
||||
public static final Color YELLOW = new Color(0xFFFFFF00);
|
||||
|
||||
public static final Color GREEN = new Color(0xFF00FF00);
|
||||
|
||||
public static final Color MAGENTA = new Color(0xFFFF00FF);
|
||||
|
||||
public static final Color CYAN = new Color(0xFF00FFFF);
|
||||
|
||||
public static final Color BLUE = new Color(0xFF0000FF);
|
||||
|
||||
private Color(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
public static Color ofTransparent(int color) {
|
||||
return new Color(color);
|
||||
}
|
||||
|
||||
public static Color ofOpaque(int color) {
|
||||
return new Color(0xFF000000 | color);
|
||||
}
|
||||
|
||||
public static Color ofRGB(float r, float g, float b) {
|
||||
return ofRGBA(r, g, b, 1f);
|
||||
}
|
||||
|
||||
public static Color ofRGB(int r, int g, int b) {
|
||||
return ofRGBA(r, g, b, 255);
|
||||
}
|
||||
|
||||
public static Color ofRGBA(float r, float g, float b, float a) {
|
||||
return ofRGBA((int) (r * 255 + 0.5), (int) (g * 255 + 0.5), (int) (b * 255 + 0.5), (int) (a * 255 + 0.5));
|
||||
}
|
||||
|
||||
public static Color ofRGBA(int r, int g, int b, int a) {
|
||||
return new Color(((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF));
|
||||
}
|
||||
|
||||
public static Color ofHSB(float hue, float saturation, float brightness) {
|
||||
return ofOpaque(HSBtoRGB(hue, saturation, brightness));
|
||||
}
|
||||
|
||||
public static int HSBtoRGB(float hue, float saturation, float brightness) {
|
||||
int r = 0, g = 0, b = 0;
|
||||
if (saturation == 0) {
|
||||
r = g = b = (int) (brightness * 255.0f + 0.5f);
|
||||
} else {
|
||||
float h = (hue - (float) Math.floor(hue)) * 6.0f;
|
||||
float f = h - (float) Math.floor(h);
|
||||
float p = brightness * (1.0f - saturation);
|
||||
float q = brightness * (1.0f - saturation * f);
|
||||
float t = brightness * (1.0f - (saturation * (1.0f - f)));
|
||||
switch ((int) h) {
|
||||
case 0:
|
||||
r = (int) (brightness * 255.0f + 0.5f);
|
||||
g = (int) (t * 255.0f + 0.5f);
|
||||
b = (int) (p * 255.0f + 0.5f);
|
||||
break;
|
||||
case 1:
|
||||
r = (int) (q * 255.0f + 0.5f);
|
||||
g = (int) (brightness * 255.0f + 0.5f);
|
||||
b = (int) (p * 255.0f + 0.5f);
|
||||
break;
|
||||
case 2:
|
||||
r = (int) (p * 255.0f + 0.5f);
|
||||
g = (int) (brightness * 255.0f + 0.5f);
|
||||
b = (int) (t * 255.0f + 0.5f);
|
||||
break;
|
||||
case 3:
|
||||
r = (int) (p * 255.0f + 0.5f);
|
||||
g = (int) (q * 255.0f + 0.5f);
|
||||
b = (int) (brightness * 255.0f + 0.5f);
|
||||
break;
|
||||
case 4:
|
||||
r = (int) (t * 255.0f + 0.5f);
|
||||
g = (int) (p * 255.0f + 0.5f);
|
||||
b = (int) (brightness * 255.0f + 0.5f);
|
||||
break;
|
||||
case 5:
|
||||
r = (int) (brightness * 255.0f + 0.5f);
|
||||
g = (int) (p * 255.0f + 0.5f);
|
||||
b = (int) (q * 255.0f + 0.5f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0xff000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public int getAlpha() {
|
||||
return color >> 24 & 0xFF;
|
||||
}
|
||||
|
||||
public int getRed() {
|
||||
return color >> 16 & 0xFF;
|
||||
}
|
||||
|
||||
public int getGreen() {
|
||||
return color >> 8 & 0xFF;
|
||||
}
|
||||
|
||||
public int getBlue() {
|
||||
return color & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a brighter color
|
||||
*
|
||||
* @param factor the higher the value, the brighter the color
|
||||
* @return the brighter color
|
||||
*/
|
||||
public Color brighter(double factor) {
|
||||
int r = getRed(), g = getGreen(), b = getBlue();
|
||||
int i = (int) (1.0 / (1.0 - (1 / factor)));
|
||||
if (r == 0 && g == 0 && b == 0) {
|
||||
return ofRGBA(i, i, i, getAlpha());
|
||||
}
|
||||
if (r > 0 && r < i)
|
||||
r = i;
|
||||
if (g > 0 && g < i)
|
||||
g = i;
|
||||
if (b > 0 && b < i)
|
||||
b = i;
|
||||
return ofRGBA(Math.min((int) (r / (1 / factor)), 255), Math.min((int) (g / (1 / factor)), 255),
|
||||
Math.min((int) (b / (1 / factor)), 255), getAlpha());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a darker color
|
||||
*
|
||||
* @param factor the higher the value, the darker the color
|
||||
* @return the darker color
|
||||
*/
|
||||
public Color darker(double factor) {
|
||||
return ofRGBA(Math.max((int) (getRed() * (1 / factor)), 0), Math.max((int) (getGreen() * (1 / factor)), 0),
|
||||
Math.max((int) (getBlue() * (1 / factor)), 0), getAlpha());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (this == other)
|
||||
return true;
|
||||
if (other == null || getClass() != other.getClass())
|
||||
return false;
|
||||
return color == ((Color) other).color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.valueOf(color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package software.bernie.geckolib3.core.util;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import software.bernie.geckolib3.core.easing.EasingManager;
|
||||
import software.bernie.geckolib3.core.easing.EasingType;
|
||||
import software.bernie.geckolib3.core.keyframe.AnimationPoint;
|
||||
|
||||
public class MathUtil {
|
||||
/**
|
||||
* Lerps an AnimationPoint
|
||||
*
|
||||
* @param animationPoint The animation point
|
||||
* @return the resulting lerped value
|
||||
*/
|
||||
public static float lerpValues(AnimationPoint animationPoint, EasingType easingType,
|
||||
Function<Double, Double> customEasingMethod) {
|
||||
if (animationPoint.currentTick >= animationPoint.animationEndTick) {
|
||||
return animationPoint.animationEndValue.floatValue();
|
||||
}
|
||||
if (animationPoint.currentTick == 0 && animationPoint.animationEndTick == 0) {
|
||||
return animationPoint.animationEndValue.floatValue();
|
||||
}
|
||||
|
||||
if (easingType == EasingType.CUSTOM && customEasingMethod != null) {
|
||||
return lerpValues(customEasingMethod.apply(animationPoint.currentTick / animationPoint.animationEndTick),
|
||||
animationPoint.animationStartValue, animationPoint.animationEndValue);
|
||||
} else if (easingType == EasingType.NONE && animationPoint.keyframe != null) {
|
||||
easingType = animationPoint.keyframe.easingType;
|
||||
}
|
||||
double ease = EasingManager.ease(animationPoint.currentTick / animationPoint.animationEndTick, easingType,
|
||||
animationPoint.keyframe == null ? null : animationPoint.keyframe.easingArgs);
|
||||
return lerpValues(ease, animationPoint.animationStartValue, animationPoint.animationEndValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the actual function that smoothly interpolates (lerp) between
|
||||
* keyframes
|
||||
*
|
||||
* @param startValue The animation's start value
|
||||
* @param endValue The animation's end value
|
||||
* @return The interpolated value
|
||||
*/
|
||||
public static float lerpValues(double percentCompleted, double startValue, double endValue) {
|
||||
// current tick / position should be between 0 and 1 and represent the
|
||||
// percentage of the lerping that has completed
|
||||
return (float) lerp(percentCompleted, startValue, endValue);
|
||||
}
|
||||
|
||||
public static double lerp(double pct, double start, double end) {
|
||||
return start + pct * (end - start);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package software.bernie.geckolib3.core.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Memoizer<T, U> {
|
||||
private final Map<T, U> cache = new ConcurrentHashMap<>();
|
||||
|
||||
private Memoizer() {
|
||||
}
|
||||
|
||||
private Function<T, U> doMemoize(final Function<T, U> function) {
|
||||
return input -> cache.computeIfAbsent(input, function::apply);
|
||||
}
|
||||
|
||||
public static <T, U> Function<T, U> memoize(final Function<T, U> function) {
|
||||
return new Memoizer<T, U>().doMemoize(function);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Add your dependencies here. Supported configurations:
|
||||
* - api("group:name:version:classifier"): if you use the types from this dependency in the public API of this mod
|
||||
* Available at runtime and compiletime for mods depending on this mod
|
||||
* - implementation("g:n:v:c"): if you need this for internal implementation details of the mod, but none of it is visible via the public API
|
||||
* Available at runtime but not compiletime for mods depending on this mod
|
||||
* - compileOnly("g:n:v:c"): if the mod you're building doesn't need this dependency during runtime at all, e.g. for optional mods
|
||||
* Not available at all for mods depending on this mod, only visible at compiletime for this mod
|
||||
* - compileOnlyApi("g:n:v:c"): like compileOnly, but also visible at compiletime for mods depending on this mod
|
||||
* Available at compiletime but not runtime for mods depending on this mod
|
||||
* - runtimeOnlyNonPublishable("g:n:v:c"): if you want to include a mod in this mod's runClient/runServer runs, but not publish it as a dependency
|
||||
* Not available at all for mods depending on this mod, only visible at runtime for this mod
|
||||
* - devOnlyNonPublishable("g:n:v:c"): a combination of runtimeOnlyNonPublishable and compileOnly for dependencies present at both compiletime and runtime,
|
||||
* but not published as Maven dependencies - useful for RFG-deobfuscated dependencies or local testing
|
||||
* - runtimeOnly("g:n:v:c"): if you don't need this at compile time, but want it to be present at runtime
|
||||
* Available at runtime for mods depending on this mod
|
||||
* - annotationProcessor("g:n:v:c"): mostly for java compiler plugins, if you know you need this, use it, otherwise don't worry
|
||||
* - testCONFIG("g:n:v:c") - replace CONFIG by one of the above (except api), same as above but for the test sources instead of main
|
||||
*
|
||||
* - shadowImplementation("g:n:v:c"): effectively the same as API, but the dependency is included in your jar under a renamed package name
|
||||
* Requires you to enable usesShadowedDependencies in gradle.properties
|
||||
*
|
||||
* - compile("g:n:v:c"): deprecated, replace with "api" (works like the old "compile") or "implementation" (can be more efficient)
|
||||
*
|
||||
* You can exclude transitive dependencies (dependencies of the chosen dependency) by appending { transitive = false } if needed,
|
||||
* but use this sparingly as it can break using your mod as another mod's dependency if you're not careful.
|
||||
*
|
||||
* To depend on obfuscated jars you can use `devOnlyNonPublishable(rfg.deobf("dep:spec:1.2.3"))` to fetch an obfuscated jar from maven,
|
||||
* or `devOnlyNonPublishable(rfg.deobf(project.files("libs/my-mod-jar.jar")))` to use a file.
|
||||
*
|
||||
* Gradle names for some of the configuration can be misleading, compileOnlyApi and runtimeOnly both get published as dependencies in Maven, but compileOnly does not.
|
||||
* The buildscript adds runtimeOnlyNonPublishable to also have a runtime dependency that's not published.
|
||||
*
|
||||
* For more details, see https://docs.gradle.org/8.0.1/userguide/java_library_plugin.html#sec:java_library_configurations_graph
|
||||
*/
|
||||
dependencies {
|
||||
compile 'com.eliotlash.molang:molang:18'
|
||||
compile 'com.eliotlash.mclib:mclib:18'
|
||||
compile project(':geckolib-core')
|
||||
compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.0'
|
||||
compile group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.0'
|
||||
compile 'com.github.jengelman.gradle.plugins:shadow:4.0.4'
|
||||
|
||||
shadeCompile ('com.eliotlash.molang:molang:18')
|
||||
shadeCompile ('com.eliotlash.mclib:mclib:18')
|
||||
shadeCompile (project(':geckolib-core'))
|
||||
shadeCompile (group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.0')
|
||||
shadeCompile (group: 'com.fasterxml.jackson.datatype', name: 'jackson-datatype-jsr310', version: '2.9.0')
|
||||
|
||||
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
|
||||
testImplementation 'org.junit.jupiter:junit-jupiter-params:5.6.2'
|
||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.2'
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
modName = GeckoLib3
|
||||
|
||||
# This is a case-sensitive string to identify your mod. Convention is to use lower case.
|
||||
modId = geckolib3
|
||||
|
||||
modGroup = software.bernie.geckolib3
|
||||
|
||||
# WHY is there no version field?
|
||||
# The build script relies on git to provide a version via tags. It is super easy and will enable you to always know the
|
||||
# code base or your binary. Check out this tutorial: https://blog.mattclemente.com/2017/10/13/versioning-with-git-tags/
|
||||
|
||||
# Will update your build.gradle automatically whenever an update is available
|
||||
autoUpdateBuildScript = false
|
||||
|
||||
minecraftVersion = 1.7.10
|
||||
forgeVersion = 10.13.4.1614
|
||||
|
||||
# Specify a MCP channel and mappings version for dependency deobfuscation and the deobfParams task.
|
||||
channel = stable
|
||||
mappingsVersion = 12
|
||||
|
||||
# Define other MCP mappings for dependency deobfuscation
|
||||
remoteMappings = https://raw.githubusercontent.com/MinecraftForge/FML/1.7.10/conf/
|
||||
|
||||
# Select a username for testing your mod with breakpoints. You may leave this empty for a random username each time you
|
||||
# restart Minecraft in development. Choose this dependent on your mod:
|
||||
# Do you need consistent player progressing (for example Thaumcraft)? -> Select a name
|
||||
# Do you need to test how your custom blocks interacts with a player that is not the owner? -> leave name empty
|
||||
developmentEnvironmentUserName = Developer
|
||||
|
||||
# Enables using modern java syntax (up to version 17) via Jabel, while still targeting JVM 8.
|
||||
# See https://github.com/bsideup/jabel for details on how this works.
|
||||
enableModernJavaSyntax = true
|
||||
|
||||
# Enables injecting missing generics into the decompiled source code for a better coding experience
|
||||
# Turns most publicly visible List, Map, etc. into proper List<Type>, Map<K, V> types
|
||||
enableGenericInjection = false
|
||||
|
||||
# Generate a class with String fields for the mod id, name, version and group name named with the fields below
|
||||
generateGradleTokenClass = com.myname.mymodid.Tags
|
||||
gradleTokenModId = MODID
|
||||
gradleTokenModName = MODNAME
|
||||
gradleTokenVersion = VERSION
|
||||
gradleTokenGroupName = GROUPNAME
|
||||
# [DEPRECATED]
|
||||
# Multiple source files can be defined here by providing a comma-seperated list: Class1.java,Class2.java,Class3.java
|
||||
# public static final String VERSION = "GRADLETOKEN_VERSION";
|
||||
# The string's content will be replaced with your mod's version when compiled. You should use this to specify your mod's
|
||||
# version in @Mod([...], version = VERSION, [...])
|
||||
# Leave these properties empty to skip individual token replacements
|
||||
replaceGradleTokenInFile =
|
||||
|
||||
# In case your mod provides an API for other mods to implement you may declare its package here. Otherwise, you can
|
||||
# leave this property empty.
|
||||
# Example value: apiPackage = api + modGroup = com.myname.mymodid -> com.myname.mymodid.api
|
||||
apiPackage =
|
||||
|
||||
# Specify the configuration file for Forge's access transformers here. It must be placed into /src/main/resources/META-INF/
|
||||
# There can be multiple files in a space-separated list.
|
||||
# Example value: mymodid_at.cfg nei_at.cfg
|
||||
accessTransformersFile = geckolib_at.cfg
|
||||
|
||||
# Provides setup for Mixins if enabled. If you don't know what mixins are: Keep it disabled!
|
||||
usesMixins = false
|
||||
# Adds some debug arguments like verbose output and export
|
||||
usesMixinDebug = false
|
||||
# Specify the location of your implementation of IMixinConfigPlugin. Leave it empty otherwise.
|
||||
mixinPlugin =
|
||||
# Specify the package that contains all of your Mixins. You may only place Mixins in this package or the build will fail!
|
||||
mixinsPackage =
|
||||
# Specify the core mod entry class if you use a core mod. This class must implement IFMLLoadingPlugin!
|
||||
# This parameter is for legacy compatibility only
|
||||
# Example value: coreModClass = asm.FMLPlugin + modGroup = com.myname.mymodid -> com.myname.mymodid.asm.FMLPlugin
|
||||
coreModClass =
|
||||
# If your project is only a consolidation of mixins or a core mod and does NOT contain a 'normal' mod ( = some class
|
||||
# that is annotated with @Mod) you want this to be true. When in doubt: leave it on false!
|
||||
containsMixinsAndOrCoreModOnly = false
|
||||
|
||||
# Enables Mixins even if this mod doesn't use them, useful if one of the dependencies uses mixins.
|
||||
forceEnableMixins = false
|
||||
|
||||
# If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your
|
||||
# responsibility check the licence and request permission for distribution, if required.
|
||||
usesShadowedDependencies = true
|
||||
# If disabled, won't remove unused classes from shaded dependencies. Some libraries use reflection to access
|
||||
# their own classes, making the minimization unreliable.
|
||||
minimizeShadowedDependencies = true
|
||||
# If disabled, won't rename the shadowed classes.
|
||||
relocateShadowedDependencies = true
|
||||
|
||||
# Adds the GTNH maven, CurseMaven, IC2/Player maven, and some more well-known 1.7.10 repositories
|
||||
includeWellKnownRepositories = true
|
||||
|
||||
# Change these to your Maven coordinates if you want to publish to a custom Maven repository instead of the default GTNH Maven.
|
||||
# Authenticate with the MAVEN_USERNAME and MAVEN_PASSWORD environment variables.
|
||||
# If you need a more complex setup disable maven publishing here and add a publishing repository to addon.gradle.
|
||||
usesMavenPublishing = true
|
||||
# mavenPublishUrl = http://jenkins.usrv.eu:8081/nexus/content/repositories/releases
|
||||
|
||||
# Publishing to modrinth requires you to set the MODRINTH_TOKEN environment variable to your current modrinth API token.
|
||||
|
||||
# The project's ID on Modrinth. Can be either the slug or the ID.
|
||||
# Leave this empty if you don't want to publish on Modrinth.
|
||||
modrinthProjectId =
|
||||
|
||||
# The project's relations on Modrinth. You can use this to refer to other projects on Modrinth.
|
||||
# Syntax: scope1-type1:name1;scope2-type2:name2;...
|
||||
# Where scope can be one of [required, optional, incompatible, embedded],
|
||||
# type can be one of [project, version],
|
||||
# and the name is the Modrinth project or version slug/id of the other mod.
|
||||
# Example: required-project:fplib;optional-project:gasstation;incompatible-project:gregtech
|
||||
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
|
||||
modrinthRelations =
|
||||
|
||||
|
||||
# Publishing to CurseForge requires you to set the CURSEFORGE_TOKEN environment variable to one of your CurseForge API tokens.
|
||||
|
||||
# The project's numeric ID on CurseForge. You can find this in the About Project box.
|
||||
# Leave this empty if you don't want to publish on CurseForge.
|
||||
curseForgeProjectId =
|
||||
|
||||
# The project's relations on CurseForge. You can use this to refer to other projects on CurseForge.
|
||||
# Syntax: type1:name1;type2:name2;...
|
||||
# Where type can be one of [requiredDependency, embeddedLibrary, optionalDependency, tool, incompatible],
|
||||
# and the name is the CurseForge project slug of the other mod.
|
||||
# Example: requiredDependency:railcraft;embeddedLibrary:cofhlib;incompatible:buildcraft
|
||||
# Note: GTNH Mixins is automatically set as a required dependency if usesMixins = true
|
||||
curseForgeRelations =
|
||||
|
||||
|
||||
# Optional parameter to customize the produced artifacts. Use this to preserver artifact naming when migrating older
|
||||
# projects. New projects should not use this parameter.
|
||||
# customArchiveBaseName =
|
||||
|
||||
# Optional parameter to prevent the source code from being published
|
||||
# noPublishedSources =
|
||||
|
||||
# Uncomment this to disable spotless checks
|
||||
# This should only be uncommented to keep it easier to sync with upstream/other forks.
|
||||
# That is, if there is no other active fork/upstream, NEVER change this.
|
||||
disableSpotless = true
|
||||
|
||||
# Uncomment this to disable checkstyle checks (currently wildcard import check).
|
||||
disableCheckstyle = true
|
||||
|
||||
# Override the IDEA build type. Valid value is "" (leave blank, do not override), "idea" (force use native IDEA build), "gradle"
|
||||
# (force use delegated build).
|
||||
# This is meant to be set in $HOME/.gradle/gradle.properties.
|
||||
# e.g. add "systemProp.org.gradle.project.ideaOverrideBuildType=idea" will override the build type to be always native build.
|
||||
# WARNING: If you do use this option, it will overwrite whatever you have in your existing projects. This might not be what you want!
|
||||
# Usually there is no need to uncomment this here as other developers do not necessarily use the same build type as you.
|
||||
# ideaOverrideBuildType = idea
|
||||
Vendored
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
@@ -0,0 +1,400 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="23">
|
||||
<profile kind="CodeFormatterProfile" name="Spotless" version="23">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="52"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_switch_case_arrow_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_permitted_types" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="52"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="85"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="48"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_permitted_types_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_arrow" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="52"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_selector_in_method_invocation_on_expression_first_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_switch_case_with_arrow_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_switch_case_with_colon" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_switch_case_with_arrow" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_if_single_item"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="20"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_permitted_types" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_if_empty"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
@@ -0,0 +1,40 @@
|
||||
|
||||
apply plugin: 'com.diffplug.spotless'
|
||||
|
||||
// Spotless autoformatter
|
||||
// See https://github.com/diffplug/spotless/tree/main/plugin-gradle
|
||||
// Can be locally toggled via spotless:off/spotless:on comments
|
||||
spotless {
|
||||
encoding 'UTF-8'
|
||||
|
||||
format 'misc', {
|
||||
target '.gitignore'
|
||||
|
||||
trimTrailingWhitespace()
|
||||
indentWithSpaces(4)
|
||||
endWithNewline()
|
||||
}
|
||||
java {
|
||||
target 'src/*/java/**/*.java', 'src/*/scala/**/*.java'
|
||||
|
||||
toggleOffOn()
|
||||
importOrderFile(Blowdryer.file('spotless.importorder'))
|
||||
removeUnusedImports()
|
||||
eclipse('4.19.0').configFile(Blowdryer.file('spotless.eclipseformat.xml'))
|
||||
}
|
||||
kotlin {
|
||||
target 'src/*/kotlin/**/*.kt'
|
||||
|
||||
toggleOffOn()
|
||||
ktfmt('0.39')
|
||||
|
||||
trimTrailingWhitespace()
|
||||
indentWithSpaces(4)
|
||||
endWithNewline()
|
||||
}
|
||||
scala {
|
||||
target 'src/*/scala/**/*.scala'
|
||||
|
||||
scalafmt('3.7.1')
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#Organize Import Order
|
||||
#Sat Jan 28 17:57:48 GMT 2023
|
||||
0=java
|
||||
1=javax
|
||||
2=net
|
||||
3=org
|
||||
4=com
|
||||
@@ -0,0 +1,2 @@
|
||||
before_install:
|
||||
- ./gradlew setupCIWorkspace
|
||||
@@ -0,0 +1,9 @@
|
||||
// Add any additional repositories for your dependencies here
|
||||
|
||||
repositories {
|
||||
maven { url 'https://maven.enginehub.org/repo/' }
|
||||
maven { url 'https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/' }
|
||||
maven { url "https://cfa2.cursemaven.com" }
|
||||
jcenter()
|
||||
mavenCentral()
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
maven {
|
||||
// RetroFuturaGradle
|
||||
name "GTNH Maven"
|
||||
url "http://jenkins.usrv.eu:8081/nexus/content/groups/public/"
|
||||
allowInsecureProtocol = true
|
||||
mavenContent {
|
||||
includeGroup("com.gtnewhorizons.retrofuturagradle")
|
||||
}
|
||||
}
|
||||
gradlePluginPortal()
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'com.diffplug.blowdryerSetup' version '1.6.0'
|
||||
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.4.0' // Provides java toolchains
|
||||
}
|
||||
|
||||
blowdryerSetup {
|
||||
repoSubfolder 'gtnhShared'
|
||||
github('GTNewHorizons/ExampleMod1.7.10', 'tag', '0.2.2')
|
||||
//devLocal '.' // Use this when testing config updates locally
|
||||
}
|
||||
|
||||
rootProject.name = 'geckolib-forge1.7.10'
|
||||
include ':geckolib-core'
|
||||
project(':geckolib-core').projectDir = new File('./core')
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.eliotlash.mclib.events;
|
||||
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
|
||||
import cpw.mods.fml.common.network.FMLNetworkEvent;
|
||||
|
||||
public class EventHandler
|
||||
{
|
||||
@SubscribeEvent
|
||||
public void clientLogsOut(FMLNetworkEvent.ClientDisconnectionFromServerEvent event)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.eliotlash.mclib.events;
|
||||
|
||||
import cpw.mods.fml.common.eventhandler.Event;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import com.eliotlash.mclib.utils.resources.MultiResourceLocation;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class MultiskinProcessedEvent extends Event
|
||||
{
|
||||
public MultiResourceLocation location;
|
||||
public BufferedImage image;
|
||||
|
||||
public MultiskinProcessedEvent(MultiResourceLocation location, BufferedImage image)
|
||||
{
|
||||
this.location = location;
|
||||
this.image = image;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.eliotlash.mclib.math;
|
||||
|
||||
import software.bernie.geckolib3.resource.GeckoLibCache;
|
||||
|
||||
public class GeckoVariable extends Variable{
|
||||
public GeckoVariable(String name, double value) {
|
||||
super(name, value);
|
||||
}
|
||||
|
||||
public double get() {
|
||||
if(this!= GeckoLibCache.getInstance().parser.getVariable(getName())){
|
||||
return GeckoLibCache.getInstance().parser.getVariable(getName()).get();
|
||||
}
|
||||
return super.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.eliotlash.mclib.math;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public interface IValue extends Serializable {
|
||||
double get();
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.eliotlash.mclib.utils;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class Color implements ICopy<Color>
|
||||
{
|
||||
public float r;
|
||||
public float g;
|
||||
public float b;
|
||||
public float a = 1;
|
||||
|
||||
public Color()
|
||||
{}
|
||||
|
||||
public Color(float r, float g, float b)
|
||||
{
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public Color(float r, float g, float b, float a)
|
||||
{
|
||||
this(r, g, b);
|
||||
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public Color(int color)
|
||||
{
|
||||
this(color, true);
|
||||
}
|
||||
|
||||
public Color(int color, boolean alpha)
|
||||
{
|
||||
this.set(color, alpha);
|
||||
}
|
||||
|
||||
public Color set(float r, float g, float b, float a)
|
||||
{
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Color set(float value, int component)
|
||||
{
|
||||
switch (component)
|
||||
{
|
||||
case 1:
|
||||
this.r = value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
this.g = value;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
this.b = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
this.a = value;
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Color set(int color)
|
||||
{
|
||||
return this.set(color, true);
|
||||
}
|
||||
|
||||
public Color set(int color, boolean alpha)
|
||||
{
|
||||
this.set((color >> 16 & 0xff) / 255F, (color >> 8 & 0xff) / 255F, (color & 0xff) / 255F, alpha ? (color >> 24 & 0xff) / 255F : 1F);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color copy()
|
||||
{
|
||||
Color copy = new Color();
|
||||
|
||||
copy.copy(this);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void copy(Color color)
|
||||
{
|
||||
this.set(color.r, color.g, color.b, color.a);
|
||||
}
|
||||
|
||||
public int getRGBAColor()
|
||||
{
|
||||
float r = MathUtils.clamp(this.r, 0, 1);
|
||||
float g = MathUtils.clamp(this.g, 0, 1);
|
||||
float b = MathUtils.clamp(this.b, 0, 1);
|
||||
float a = MathUtils.clamp(this.a, 0, 1);
|
||||
|
||||
return ((int) (a * 255) << 24) | ((int) (r * 255) << 16) | ((int) (g * 255) << 8) | (int) (b * 255);
|
||||
}
|
||||
|
||||
public int getRGBColor()
|
||||
{
|
||||
return this.getRGBAColor() & 0xffffff;
|
||||
}
|
||||
|
||||
public String stringify()
|
||||
{
|
||||
return this.stringify(false);
|
||||
}
|
||||
|
||||
public String stringify(boolean alpha)
|
||||
{
|
||||
if (alpha)
|
||||
{
|
||||
return "#" + StringUtils.leftPad(Integer.toHexString(this.getRGBAColor()), 8, '0');
|
||||
}
|
||||
|
||||
return "#" + StringUtils.leftPad(Integer.toHexString(this.getRGBColor()), 6, '0');
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj instanceof Color)
|
||||
{
|
||||
Color color = (Color) obj;
|
||||
|
||||
return color.getRGBAColor() == this.getRGBAColor();
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.eliotlash.mclib.utils;
|
||||
|
||||
import net.geckominecraft.client.renderer.GlStateManager;
|
||||
|
||||
public class ColorUtils
|
||||
{
|
||||
public static final int HALF_BLACK = 0x88000000;
|
||||
|
||||
public static final Color COLOR = new Color();
|
||||
|
||||
public static int multiplyColor(int color, float factor)
|
||||
{
|
||||
COLOR.set(color, true);
|
||||
COLOR.r *= factor;
|
||||
COLOR.g *= factor;
|
||||
COLOR.b *= factor;
|
||||
|
||||
return COLOR.getRGBAColor();
|
||||
}
|
||||
|
||||
public static int setAlpha(int color, float alpha)
|
||||
{
|
||||
COLOR.set(color, true);
|
||||
COLOR.a = alpha;
|
||||
|
||||
return COLOR.getRGBAColor();
|
||||
}
|
||||
|
||||
public static void interpolate(Color target, int a, int b, float x)
|
||||
{
|
||||
interpolate(target, a, b, x, true);
|
||||
}
|
||||
|
||||
public static void interpolate(Color target, int a, int b, float x, boolean alpha)
|
||||
{
|
||||
target.set(a, alpha);
|
||||
COLOR.set(b, alpha);
|
||||
|
||||
target.r = Interpolations.lerp(target.r, COLOR.r, x);
|
||||
target.g = Interpolations.lerp(target.g, COLOR.g, x);
|
||||
target.b = Interpolations.lerp(target.b, COLOR.b, x);
|
||||
|
||||
if (alpha)
|
||||
{
|
||||
target.a = Interpolations.lerp(target.a, COLOR.a, x);
|
||||
}
|
||||
}
|
||||
|
||||
public static void bindColor(int color)
|
||||
{
|
||||
COLOR.set(color, true);
|
||||
|
||||
GlStateManager.color(COLOR.r, COLOR.g, COLOR.b, COLOR.a);
|
||||
}
|
||||
|
||||
public static int rgbaToInt(float r, float g, float b, float a)
|
||||
{
|
||||
COLOR.set(r, g, b, a);
|
||||
|
||||
return COLOR.getRGBAColor();
|
||||
}
|
||||
|
||||
public static int parseColor(String color)
|
||||
{
|
||||
return parseColor(color, 0);
|
||||
}
|
||||
|
||||
public static int parseColor(String color, int orDefault)
|
||||
{
|
||||
try
|
||||
{
|
||||
return parseColorWithException(color);
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
return orDefault;
|
||||
}
|
||||
|
||||
public static int parseColorWithException(String color) throws Exception
|
||||
{
|
||||
if (color.startsWith("#"))
|
||||
{
|
||||
color = color.substring(1);
|
||||
}
|
||||
|
||||
if (color.length() == 6 || color.length() == 8)
|
||||
{
|
||||
if (color.length() == 8)
|
||||
{
|
||||
String alpha = color.substring(0, 2);
|
||||
String rest = color.substring(2);
|
||||
|
||||
int a = Integer.parseInt(alpha, 16) << 24;
|
||||
int rgb = Integer.parseInt(rest, 16);
|
||||
|
||||
return a + rgb;
|
||||
}
|
||||
|
||||
return Integer.parseInt(color, 16);
|
||||
}
|
||||
|
||||
throw new Exception("Given color \"" + color + "\" can't be parsed!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.eliotlash.mclib.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
/**
|
||||
* Dummy entity
|
||||
*
|
||||
* This class is used in model editor as a player substitution for the model
|
||||
* methods.
|
||||
*/
|
||||
public class DummyEntity extends EntityLivingBase
|
||||
{
|
||||
private final ItemStack[] held;
|
||||
|
||||
public DummyEntity(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
|
||||
this.held = new ItemStack[] {null,null,null,null,new ItemStack(Items.diamond_sword)};
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getHeldItem() {
|
||||
return held[4];
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getEquipmentInSlot(int slot) {
|
||||
return held[slot];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCurrentItemOrArmor(int p_70062_1_, ItemStack p_70062_2_) {
|
||||
this.held[p_70062_1_]=p_70062_2_;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack[] getLastActiveItems() {
|
||||
return held;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.eliotlash.mclib.utils;
|
||||
|
||||
/**
|
||||
* The Java Cloneable interface is only a marker interface to enforce
|
||||
* a convention to override the protected Object.clone() method with a public method.
|
||||
* This does not allow for dynamic validation whether an object actually has a public clone() method.
|
||||
*
|
||||
* This interface should provide better knowledge at compile time whether a generic object
|
||||
* has a public copy method.
|
||||
* @param <T> by convention this should be the type of the class that inherits this interface
|
||||
*/
|
||||
public interface ICopy<T>
|
||||
{
|
||||
T copy();
|
||||
|
||||
default void copy(T origin)
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,758 @@
|
||||
package com.eliotlash.mclib.utils;
|
||||
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.lwjgl.BufferUtils;
|
||||
import org.lwjgl.opengl.GL11;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.*;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class MatrixUtils
|
||||
{
|
||||
/**
|
||||
* Model view matrix buffer
|
||||
*/
|
||||
public static final FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
|
||||
|
||||
/**
|
||||
* Float array for transferring data from FloatBuffer to the matrix
|
||||
*/
|
||||
public static final float[] floats = new float[16];
|
||||
|
||||
/**
|
||||
* Model view matrix captured here
|
||||
*/
|
||||
public static Matrix4f matrix;
|
||||
|
||||
private static final DoubleBuffer doubleBuffer = BufferUtils.createDoubleBuffer(16);
|
||||
private static final double[] doubles = new double[16];
|
||||
private static final Matrix4d camera = new Matrix4d();
|
||||
|
||||
public static Matrix4d getCameraMatrix()
|
||||
{
|
||||
return new Matrix4d(camera);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read OpenGL's model view matrix
|
||||
*/
|
||||
public static Matrix4f readModelView(Matrix4f matrix4f)
|
||||
{
|
||||
buffer.clear();
|
||||
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, buffer);
|
||||
buffer.get(floats);
|
||||
|
||||
matrix4f.set(floats);
|
||||
matrix4f.transpose();
|
||||
|
||||
return matrix4f;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called by the ASMAfterCamera method. It saves the camera modelview matrix after the camera is set up.
|
||||
* The camera matrix will be used to calculate global transformations of models.
|
||||
* Thank you to MiaoNLI for discovering this possibility.
|
||||
*/
|
||||
private static void readCamera()
|
||||
{
|
||||
doubleBuffer.clear();
|
||||
GL11.glGetDouble(GL11.GL_MODELVIEW_MATRIX, doubleBuffer);
|
||||
doubleBuffer.get(doubles);
|
||||
camera.set(doubles);
|
||||
camera.transpose();
|
||||
}
|
||||
|
||||
public static Matrix4f readModelView()
|
||||
{
|
||||
return readModelView(new Matrix4f());
|
||||
}
|
||||
|
||||
public static Matrix4d readModelViewDouble()
|
||||
{
|
||||
doubleBuffer.clear();
|
||||
GL11.glGetDouble(GL11.GL_MODELVIEW_MATRIX, doubleBuffer);
|
||||
doubleBuffer.get(doubles);
|
||||
|
||||
Matrix4d matrix4d = new Matrix4d();
|
||||
|
||||
matrix4d.set(doubles);
|
||||
matrix4d.transpose();
|
||||
|
||||
return matrix4d;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace model view matrix with given matrix
|
||||
*/
|
||||
public static void loadModelView(Matrix4f matrix4f)
|
||||
{
|
||||
matrixToFloat(floats, matrix4f);
|
||||
|
||||
buffer.clear();
|
||||
buffer.put(floats);
|
||||
buffer.rewind();
|
||||
GL11.glLoadMatrix(buffer);
|
||||
}
|
||||
|
||||
/**
|
||||
* method to fill the float array with values from the matrix
|
||||
*/
|
||||
public static void matrixToFloat(float[] floats, Matrix4f matrix4f)
|
||||
{
|
||||
floats[0] = matrix4f.m00;
|
||||
floats[1] = matrix4f.m01;
|
||||
floats[2] = matrix4f.m02;
|
||||
floats[3] = matrix4f.m03;
|
||||
floats[4] = matrix4f.m10;
|
||||
floats[5] = matrix4f.m11;
|
||||
floats[6] = matrix4f.m12;
|
||||
floats[7] = matrix4f.m13;
|
||||
floats[8] = matrix4f.m20;
|
||||
floats[9] = matrix4f.m21;
|
||||
floats[10] = matrix4f.m22;
|
||||
floats[11] = matrix4f.m23;
|
||||
floats[12] = matrix4f.m30;
|
||||
floats[13] = matrix4f.m31;
|
||||
floats[14] = matrix4f.m32;
|
||||
floats[15] = matrix4f.m33;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param floatBuffer with the minimum size of 16
|
||||
* @param matrix
|
||||
*/
|
||||
public static void matrixToFloatBuffer(FloatBuffer floatBuffer, Matrix4f matrix)
|
||||
{
|
||||
floatBuffer.put(matrix.m00);
|
||||
floatBuffer.put(matrix.m01);
|
||||
floatBuffer.put(matrix.m02);
|
||||
floatBuffer.put(matrix.m03);
|
||||
floatBuffer.put(matrix.m10);
|
||||
floatBuffer.put(matrix.m11);
|
||||
floatBuffer.put(matrix.m12);
|
||||
floatBuffer.put(matrix.m13);
|
||||
floatBuffer.put(matrix.m20);
|
||||
floatBuffer.put(matrix.m21);
|
||||
floatBuffer.put(matrix.m22);
|
||||
floatBuffer.put(matrix.m23);
|
||||
floatBuffer.put(matrix.m30);
|
||||
floatBuffer.put(matrix.m31);
|
||||
floatBuffer.put(matrix.m32);
|
||||
floatBuffer.put(matrix.m33);
|
||||
|
||||
floatBuffer.flip();
|
||||
}
|
||||
|
||||
|
||||
public static boolean captureMatrix()
|
||||
{
|
||||
if (matrix == null)
|
||||
{
|
||||
matrix = MatrixUtils.readModelView(new Matrix4f());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void ASMAfterCamera()
|
||||
{
|
||||
readCamera();
|
||||
}
|
||||
|
||||
public static void releaseMatrix()
|
||||
{
|
||||
matrix = null;
|
||||
}
|
||||
|
||||
public static Quat4d matrixToQuaternion(Matrix3f matrix)
|
||||
{
|
||||
double tr = matrix.m00 + matrix.m11 + matrix.m22;
|
||||
double qw = 0;
|
||||
double qx = 0;
|
||||
double qy = 0;
|
||||
double qz = 0;
|
||||
|
||||
if (tr > 0)
|
||||
{
|
||||
double S = Math.sqrt(tr+1.0) * 2; // S=4*qw
|
||||
qw = 0.25 * S;
|
||||
qx = (matrix.m21 - matrix.m12) / S;
|
||||
qy = (matrix.m02 - matrix.m20) / S;
|
||||
qz = (matrix.m10 - matrix.m01) / S;
|
||||
}
|
||||
else if ((matrix.m00 > matrix.m11) & (matrix.m00 > matrix.m22))
|
||||
{
|
||||
double S = Math.sqrt(1.0 + matrix.m00 - matrix.m11 - matrix.m22) * 2; // S=4*qx
|
||||
qw = (matrix.m21 - matrix.m12) / S;
|
||||
qx = 0.25 * S;
|
||||
qy = (matrix.m01 + matrix.m10) / S;
|
||||
qz = (matrix.m02 + matrix.m20) / S;
|
||||
}
|
||||
else if (matrix.m11 > matrix.m22)
|
||||
{
|
||||
double S = Math.sqrt(1.0 + matrix.m11 - matrix.m00 - matrix.m22) * 2; // S=4*qy
|
||||
qw = (matrix.m02 - matrix.m20) / S;
|
||||
qx = (matrix.m01 + matrix.m10) / S;
|
||||
qy = 0.25 * S;
|
||||
qz = (matrix.m12 + matrix.m21) / S;
|
||||
}
|
||||
else
|
||||
{
|
||||
double S = Math.sqrt(1.0 + matrix.m22 - matrix.m00 - matrix.m11) * 2; // S=4*qz
|
||||
qw = (matrix.m10 - matrix.m01) / S;
|
||||
qx = (matrix.m02 + matrix.m20) / S;
|
||||
qy = (matrix.m12 + matrix.m21) / S;
|
||||
qz = 0.25 * S;
|
||||
}
|
||||
|
||||
return new Quat4d(qw, qx, qy, qz);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the angular velocity around the arbitrary axis.
|
||||
* The arbitrary axis and the angle around it can be obtained from this result.
|
||||
* @param rotation
|
||||
* @return the angular velocity vector.
|
||||
*/
|
||||
public static Vector3f getAngularVelocity(Matrix3f rotation)
|
||||
{
|
||||
Matrix3f step = new Matrix3f(rotation);
|
||||
Matrix3f angularVelocity = new Matrix3f();
|
||||
Matrix3f i = new Matrix3f();
|
||||
|
||||
i.setIdentity();
|
||||
angularVelocity.setIdentity();
|
||||
angularVelocity.mul(2);
|
||||
|
||||
step.add(i);
|
||||
step.invert();
|
||||
step.mul(4);
|
||||
|
||||
angularVelocity.sub(step);
|
||||
|
||||
Vector3f angularV = new Vector3f(angularVelocity.m21,
|
||||
-angularVelocity.m20,
|
||||
angularVelocity.m10);
|
||||
|
||||
return angularV;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate an intrinsic rotation matrix based on the given order and the angles.
|
||||
* @param x angle in radians
|
||||
* @param y angle in radians
|
||||
* @param z angle in radians
|
||||
* @param order order of the rotation matrix
|
||||
* @return intrinsic rotation matrix
|
||||
*/
|
||||
public static Matrix4f getRotationMatrix(float x, float y, float z, RotationOrder order)
|
||||
{
|
||||
Matrix4f mat = new Matrix4f();
|
||||
Matrix4f rot = new Matrix4f();
|
||||
|
||||
mat.setIdentity();
|
||||
|
||||
switch (order)
|
||||
{
|
||||
case XYZ:
|
||||
rot.rotZ(z);
|
||||
mat.mul(rot);
|
||||
rot.rotY(y);
|
||||
mat.mul(rot);
|
||||
rot.rotX(x);
|
||||
mat.mul(rot);
|
||||
|
||||
break;
|
||||
case ZYX:
|
||||
rot.rotX(x);
|
||||
mat.mul(rot);
|
||||
rot.rotY(y);
|
||||
mat.mul(rot);
|
||||
rot.rotZ(z);
|
||||
mat.mul(rot);
|
||||
|
||||
break;
|
||||
case XZY:
|
||||
rot.rotY(y);
|
||||
mat.mul(rot);
|
||||
rot.rotZ(z);
|
||||
mat.mul(rot);
|
||||
rot.rotX(x);
|
||||
mat.mul(rot);
|
||||
|
||||
break;
|
||||
case YZX:
|
||||
rot.rotX(x);
|
||||
mat.mul(rot);
|
||||
rot.rotZ(z);
|
||||
mat.mul(rot);
|
||||
rot.rotY(y);
|
||||
mat.mul(rot);
|
||||
|
||||
break;
|
||||
case YXZ:
|
||||
rot.rotZ(z);
|
||||
mat.mul(rot);
|
||||
rot.rotX(x);
|
||||
mat.mul(rot);
|
||||
rot.rotY(y);
|
||||
mat.mul(rot);
|
||||
|
||||
break;
|
||||
case ZXY:
|
||||
rot.rotY(y);
|
||||
mat.mul(rot);
|
||||
rot.rotX(x);
|
||||
mat.mul(rot);
|
||||
rot.rotZ(z);
|
||||
mat.mul(rot);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the current global transformations
|
||||
* @return Matrix4d array {translation, rotation, scale} or null if singular matrix exception occured during inverting the camera matrix.
|
||||
*/
|
||||
public static Matrix4d[] getTransformation()
|
||||
{
|
||||
Matrix4d parent = new Matrix4d(camera);
|
||||
Matrix4d translation = new Matrix4d();
|
||||
Matrix4d rotation = new Matrix4d();
|
||||
Matrix4d scale = new Matrix4d();
|
||||
|
||||
translation.setIdentity();
|
||||
rotation.setIdentity();
|
||||
scale.setIdentity();
|
||||
|
||||
try
|
||||
{
|
||||
parent.invert();
|
||||
}
|
||||
catch (SingularMatrixException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
parent.mul(parent, readModelViewDouble());
|
||||
|
||||
Entity renderViewEntity = Minecraft.getMinecraft().renderViewEntity;
|
||||
|
||||
Matrix4d cameraTrans = new Matrix4d();
|
||||
|
||||
cameraTrans.setIdentity();
|
||||
cameraTrans.m03 = Interpolations.lerp(renderViewEntity.lastTickPosX, renderViewEntity.posX, Minecraft.getMinecraft().timer.renderPartialTicks);
|
||||
cameraTrans.m13 = Interpolations.lerp(renderViewEntity.lastTickPosY, renderViewEntity.posY, Minecraft.getMinecraft().timer.renderPartialTicks);
|
||||
cameraTrans.m23 = Interpolations.lerp(renderViewEntity.lastTickPosZ, renderViewEntity.posZ, Minecraft.getMinecraft().timer.renderPartialTicks);
|
||||
|
||||
parent.mul(cameraTrans, parent);
|
||||
|
||||
Vector4d rx = new Vector4d(parent.m00, parent.m10, parent.m20, 0);
|
||||
Vector4d ry = new Vector4d(parent.m01, parent.m11, parent.m21, 0);
|
||||
Vector4d rz = new Vector4d(parent.m02, parent.m12, parent.m22, 0);
|
||||
|
||||
rx.normalize();
|
||||
ry.normalize();
|
||||
rz.normalize();
|
||||
rotation.setRow(0, rx);
|
||||
rotation.setRow(1, ry);
|
||||
rotation.setRow(2, rz);
|
||||
|
||||
translation.setTranslation(new Vector3d(parent.m03, parent.m13, parent.m23));
|
||||
|
||||
scale.m00 = Math.sqrt(parent.m00 * parent.m00 + parent.m10 * parent.m10 + parent.m20 * parent.m20);
|
||||
scale.m11 = Math.sqrt(parent.m01 * parent.m01 + parent.m11 * parent.m11 + parent.m21 * parent.m21);
|
||||
scale.m22 = Math.sqrt(parent.m02 * parent.m02 + parent.m12 * parent.m12 + parent.m22 * parent.m22);
|
||||
|
||||
return new Matrix4d[]{translation, rotation, scale};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method extracts the rotation, translation and scale from the modelview matrix. It needs the view matrix to work properly
|
||||
* @author Christian F. (known as Chryfi)
|
||||
* @param cameraMatrix The cameraMatrix from rendering so you can extract modelView from OpenGL's matrix.
|
||||
* @param modelView The matrix containing the transformations that should be extracted.
|
||||
* @return Transformation contains translation, rotation and scale as 4x4 matrices. It also has getter methods for the 3x3 matrices.
|
||||
*/
|
||||
public static Transformation extractTransformations(@Nullable Matrix4f cameraMatrix, Matrix4f modelView)
|
||||
{
|
||||
return extractTransformations(cameraMatrix, modelView, MatrixMajor.ROW);
|
||||
}
|
||||
|
||||
public static Transformation extractTransformations(@Nullable Matrix4f cameraMatrix, Matrix4f modelView, MatrixMajor major)
|
||||
{
|
||||
Matrix4f parent = new Matrix4f(modelView);
|
||||
|
||||
if (cameraMatrix != null)
|
||||
{
|
||||
parent.set(cameraMatrix);
|
||||
|
||||
try
|
||||
{
|
||||
parent.invert();
|
||||
}
|
||||
catch (SingularMatrixException e)
|
||||
{
|
||||
Transformation transformation = new Transformation();
|
||||
transformation.creationException = e;
|
||||
|
||||
return transformation;
|
||||
}
|
||||
|
||||
parent.mul(modelView);
|
||||
}
|
||||
|
||||
Matrix4f translation = new Matrix4f();
|
||||
Matrix4f scale = new Matrix4f();
|
||||
Matrix4f rotation = new Matrix4f();
|
||||
|
||||
translation.setIdentity();
|
||||
rotation.setIdentity();
|
||||
scale.setIdentity();
|
||||
|
||||
translation.m03 = parent.m03;
|
||||
translation.m13 = parent.m13;
|
||||
translation.m23 = parent.m23;
|
||||
|
||||
Vector4f ax = new Vector4f(parent.m00, parent.m01, parent.m02, 0);
|
||||
Vector4f ay = new Vector4f(parent.m10, parent.m11, parent.m12, 0);
|
||||
Vector4f az = new Vector4f(parent.m20, parent.m21, parent.m22, 0);
|
||||
|
||||
if (major == MatrixMajor.COLUMN)
|
||||
{
|
||||
ax = new Vector4f(parent.m00, parent.m10, parent.m20, 0.0F);
|
||||
ay = new Vector4f(parent.m01, parent.m11, parent.m21, 0.0F);
|
||||
az = new Vector4f(parent.m02, parent.m12, parent.m22, 0.0F);
|
||||
}
|
||||
|
||||
ax.normalize();
|
||||
ay.normalize();
|
||||
az.normalize();
|
||||
rotation.setRow(0, ax);
|
||||
rotation.setRow(1, ay);
|
||||
rotation.setRow(2, az);
|
||||
|
||||
if (major == MatrixMajor.COLUMN)
|
||||
{
|
||||
rotation.transpose();
|
||||
}
|
||||
|
||||
scale.m00 = (float) Math.sqrt(parent.m00 * parent.m00 + parent.m01 * parent.m01 + parent.m02 * parent.m02);
|
||||
scale.m11 = (float) Math.sqrt(parent.m10 * parent.m10 + parent.m11 * parent.m11 + parent.m12 * parent.m12);
|
||||
scale.m22 = (float) Math.sqrt(parent.m20 * parent.m20 + parent.m21 * parent.m21 + parent.m22 * parent.m22);
|
||||
|
||||
if (major == MatrixMajor.COLUMN)
|
||||
{
|
||||
scale.m00 = (float) Math.sqrt(parent.m00 * parent.m00 + parent.m10 * parent.m10 + parent.m20 * parent.m20);
|
||||
scale.m11 = (float) Math.sqrt(parent.m01 * parent.m01 + parent.m11 * parent.m11 + parent.m21 * parent.m21);
|
||||
scale.m22 = (float) Math.sqrt(parent.m02 * parent.m02 + parent.m12 * parent.m12 + parent.m22 * parent.m22);
|
||||
}
|
||||
|
||||
return new Transformation(translation, rotation, scale);
|
||||
}
|
||||
|
||||
public static class Transformation
|
||||
{
|
||||
public Matrix4f translation = new Matrix4f();
|
||||
public Matrix4f rotation = new Matrix4f();
|
||||
public Matrix4f scale = new Matrix4f();
|
||||
/**
|
||||
* contains the exception that may have
|
||||
* occurred during calculation of transformation data
|
||||
*/
|
||||
private Exception creationException = null;
|
||||
|
||||
public Transformation(Matrix4f translation, Matrix4f rotation, Matrix4f scale)
|
||||
{
|
||||
this.translation.set(translation);
|
||||
this.rotation.set(rotation);
|
||||
this.scale.set(scale);
|
||||
}
|
||||
|
||||
public Transformation()
|
||||
{
|
||||
this.translation.setIdentity();
|
||||
this.rotation.setIdentity();
|
||||
this.scale.setIdentity();
|
||||
}
|
||||
|
||||
public Matrix3f getScale3f()
|
||||
{
|
||||
Matrix3f scale3f = new Matrix3f();
|
||||
|
||||
scale3f.setIdentity();
|
||||
|
||||
scale3f.m00 = this.scale.m00;
|
||||
scale3f.m11 = this.scale.m11;
|
||||
scale3f.m22 = this.scale.m22;
|
||||
|
||||
return scale3f;
|
||||
}
|
||||
|
||||
public Vector3f getTranslation3f()
|
||||
{
|
||||
Vector3f translation3f = new Vector3f();
|
||||
|
||||
translation3f.set(this.translation.m03,this.translation.m13, this.translation.m23);
|
||||
|
||||
return translation3f;
|
||||
}
|
||||
|
||||
public Matrix3f getRotation3f()
|
||||
{
|
||||
Matrix3f rotation3f = new Matrix3f();
|
||||
|
||||
rotation3f.setIdentity();
|
||||
rotation3f.setRow(0, this.rotation.m00, this.rotation.m01, this.rotation.m02);
|
||||
rotation3f.setRow(1, this.rotation.m10, this.rotation.m11, this.rotation.m12);
|
||||
rotation3f.setRow(2, this.rotation.m20, this.rotation.m21, this.rotation.m22);
|
||||
|
||||
return rotation3f;
|
||||
}
|
||||
|
||||
public Exception getCreationException()
|
||||
{
|
||||
return this.creationException;
|
||||
}
|
||||
|
||||
public Vector3f getRotation(RotationOrder order)
|
||||
{
|
||||
return this.getRotation(order, null);
|
||||
}
|
||||
public Vector3f getRotation(RotationOrder order, Vector3f ref)
|
||||
{
|
||||
return this.getRotation(order, ref, 0);
|
||||
}
|
||||
public Vector3f getRotation(RotationOrder order, int invAxis)
|
||||
{
|
||||
return this.getRotation(order, null, invAxis);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rotation values from matrix<br>
|
||||
* <b>It must be called first to determine if the value can be obtained
|
||||
* properly</b>
|
||||
*
|
||||
* @param order Rotation Order
|
||||
* @param ref The vector used for reference. Null if nothing to refer. Make
|
||||
* sure that the incoming matrix is not affected by negative
|
||||
* scaling.
|
||||
* @param invAxis The axis to be inverted when the matrix is a left-handed
|
||||
* coordinate system. 012 equals xyz
|
||||
* @return A vector includes rotation values with specific order, null if matrix
|
||||
* is a illegal rotation matrix.<br>
|
||||
* The returned vector will be as close to the reference vector as
|
||||
* possible
|
||||
*/
|
||||
public Vector3f getRotation(RotationOrder order, Vector3f ref, int invAxis)
|
||||
{
|
||||
Matrix3f mat = this.getRotation3f();
|
||||
float[] rotation = new float[3];
|
||||
float[] refFloats = null;
|
||||
if (ref != null)
|
||||
{
|
||||
refFloats = new float[3];
|
||||
ref.get(refFloats);
|
||||
}
|
||||
|
||||
// DirectX -> OpenGL
|
||||
// If the scaling value has an odd number of negative values, this will cause it
|
||||
// to become a left-handed coordinate system.
|
||||
Vector3f x = new Vector3f(mat.m00, mat.m10, mat.m20);
|
||||
Vector3f y = new Vector3f(mat.m01, mat.m11, mat.m21);
|
||||
Vector3f z = new Vector3f(mat.m02, mat.m12, mat.m22);
|
||||
Vector3f crossY = new Vector3f();
|
||||
Vector3f originalY = new Vector3f();
|
||||
originalY.normalize(y);
|
||||
crossY.cross(z, x);
|
||||
crossY.normalize();
|
||||
|
||||
if (crossY.dot(originalY) < 0)
|
||||
{
|
||||
mat.mul(getInvertAxisMatrix(invAxis));
|
||||
}
|
||||
|
||||
Float angle = order.doTest(order.thirdIndex, mat);
|
||||
|
||||
/* if the second rotation value is +/-90, here will be null. */
|
||||
if (angle != null)
|
||||
{
|
||||
if (refFloats != null)
|
||||
{
|
||||
angle = refFloats[order.thirdIndex] + MathHelper.wrapDegrees(2F * (angle - refFloats[order.thirdIndex])) / 2F;
|
||||
}
|
||||
rotation[order.thirdIndex] = angle;
|
||||
mat.mul(getRotationMatrix(order.thirdIndex, -angle), mat);
|
||||
}
|
||||
else if (refFloats != null)
|
||||
{
|
||||
rotation[order.thirdIndex] = angle = refFloats[order.thirdIndex];
|
||||
mat.mul(getRotationMatrix(order.thirdIndex, -angle), mat);
|
||||
}
|
||||
angle = order.doTest(order.secondIndex, mat);
|
||||
|
||||
if (angle == null)
|
||||
{
|
||||
// Illegal: Scale is zero, no rotation information here.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (refFloats != null)
|
||||
{
|
||||
angle = refFloats[order.secondIndex] + MathHelper.wrapDegrees(angle - refFloats[order.secondIndex]);
|
||||
}
|
||||
|
||||
rotation[order.secondIndex] = angle;
|
||||
mat.mul(getRotationMatrix(order.secondIndex, -angle), mat);
|
||||
|
||||
angle = order.doTest(order.firstIndex, mat);
|
||||
|
||||
if (angle == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else if (refFloats != null)
|
||||
{
|
||||
angle = refFloats[order.firstIndex] + MathHelper.wrapDegrees(angle - refFloats[order.firstIndex]);
|
||||
}
|
||||
|
||||
rotation[order.firstIndex] = angle;
|
||||
|
||||
return new Vector3f(rotation);
|
||||
}
|
||||
|
||||
public Vector3f getScale()
|
||||
{
|
||||
return this.getScale(0);
|
||||
}
|
||||
|
||||
public Vector3f getScale(int invAxis)
|
||||
{
|
||||
Vector3f scale = new Vector3f(this.scale.m00, this.scale.m11, this.scale.m22);
|
||||
Vector3f x = new Vector3f(this.rotation.m00, this.rotation.m10, this.rotation.m20);
|
||||
Vector3f y = new Vector3f(this.rotation.m01, this.rotation.m11, this.rotation.m21);
|
||||
Vector3f z = new Vector3f(this.rotation.m02, this.rotation.m12, this.rotation.m22);
|
||||
Vector3f crossY = new Vector3f();
|
||||
Vector3f originalY = new Vector3f();
|
||||
|
||||
originalY.normalize(y);
|
||||
crossY.cross(z, x);
|
||||
crossY.normalize();
|
||||
|
||||
if (crossY.dot(originalY) < 0)
|
||||
{
|
||||
getInvertAxisMatrix(invAxis).transform(scale);
|
||||
}
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
public static Matrix3f getRotationMatrix(int axis, double degrees)
|
||||
{
|
||||
Matrix3f mat = new Matrix3f();
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case 0:
|
||||
mat.rotX((float) Math.toRadians(degrees));
|
||||
break;
|
||||
case 1:
|
||||
mat.rotY((float) Math.toRadians(degrees));
|
||||
break;
|
||||
case 2:
|
||||
mat.rotZ((float) Math.toRadians(degrees));
|
||||
break;
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
|
||||
public static Matrix3f getInvertAxisMatrix(int axis)
|
||||
{
|
||||
Matrix3f mat = new Matrix3f();
|
||||
|
||||
mat.setIdentity();
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case 0:
|
||||
mat.m00 = -1;
|
||||
break;
|
||||
case 1:
|
||||
mat.m11 = -1;
|
||||
break;
|
||||
case 2:
|
||||
mat.m22 = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return mat;
|
||||
}
|
||||
}
|
||||
|
||||
public enum MatrixMajor
|
||||
{
|
||||
ROW,
|
||||
COLUMN
|
||||
}
|
||||
|
||||
public enum RotationOrder
|
||||
{
|
||||
XYZ, XZY, YXZ, YZX, ZXY, ZYX;
|
||||
|
||||
public final int firstIndex;
|
||||
public final int secondIndex;
|
||||
public final int thirdIndex;
|
||||
|
||||
private RotationOrder()
|
||||
{
|
||||
String order = this.name().toUpperCase();
|
||||
firstIndex = order.charAt(0) - 'X';
|
||||
secondIndex = order.charAt(1) - 'X';
|
||||
thirdIndex = order.charAt(2) - 'X';
|
||||
}
|
||||
|
||||
public Float doTest(int index, Matrix3f test)
|
||||
{
|
||||
float[] buffer = new float[3];
|
||||
|
||||
buffer[index == firstIndex ? secondIndex : firstIndex] = 1;
|
||||
|
||||
Vector3f in = new Vector3f(buffer);
|
||||
Vector3f out = new Vector3f();
|
||||
|
||||
test.transform(in, out);
|
||||
out.get(buffer);
|
||||
buffer[index] = 0;
|
||||
out.set(buffer);
|
||||
|
||||
if (out.length() < 1E-07)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
out.normalize();
|
||||
|
||||
float cos = in.dot(out);
|
||||
|
||||
out.cross(in, out);
|
||||
out.get(buffer);
|
||||
|
||||
float sin = out.length() * Math.signum(buffer[index]);
|
||||
|
||||
return (float) Math.toDegrees(Math.atan2(sin, cos));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package com.eliotlash.mclib.utils;
|
||||
|
||||
import cpw.mods.fml.client.FMLClientHandler;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.client.resources.IResourcePack;
|
||||
import net.minecraft.client.resources.SimpleReloadableResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class ReflectionUtils
|
||||
{
|
||||
/**
|
||||
* Minecraft texture manager's field to the texture map (a map of
|
||||
* {@link ITextureObject} which is used to cache references to
|
||||
* OpenGL textures).
|
||||
*/
|
||||
public static Field TEXTURE_MAP;
|
||||
|
||||
/**
|
||||
* Whether isShadowPass field was checked
|
||||
*/
|
||||
private static boolean SHADOW_PASS_CHECK;
|
||||
|
||||
/**
|
||||
* Optifine's shadow pass field
|
||||
*/
|
||||
private static Field SHADOW_PASS;
|
||||
|
||||
/**
|
||||
* Get texture map from texture manager using reflection API
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<ResourceLocation, ITextureObject> getTextures(TextureManager manager)
|
||||
{
|
||||
if (TEXTURE_MAP == null)
|
||||
{
|
||||
setupTextureMapField(manager);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return (Map<ResourceLocation, ITextureObject>) TEXTURE_MAP.get(manager);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup texture map field which is looked up using the reflection API
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static void setupTextureMapField(TextureManager manager)
|
||||
{
|
||||
/* Finding the field which has holds the texture cache */
|
||||
for (Field field : manager.getClass().getDeclaredFields())
|
||||
{
|
||||
if (Modifier.isStatic(field.getModifiers()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
field.setAccessible(true);
|
||||
|
||||
try
|
||||
{
|
||||
Object value = field.get(manager);
|
||||
|
||||
if (value instanceof Map && ((Map) value).keySet().iterator().next() instanceof ResourceLocation)
|
||||
{
|
||||
TEXTURE_MAP = field;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static boolean registerResourcePack(IResourcePack pack)
|
||||
{
|
||||
try
|
||||
{
|
||||
Field field = FMLClientHandler.class.getDeclaredField("resourcePackList");
|
||||
field.setAccessible(true);
|
||||
|
||||
List<IResourcePack> packs = (List<IResourcePack>) field.get(FMLClientHandler.instance());
|
||||
packs.add(pack);
|
||||
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
|
||||
|
||||
if (manager instanceof SimpleReloadableResourceManager)
|
||||
{
|
||||
((SimpleReloadableResourceManager) manager).reloadResourcePack(pack);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static boolean isOptifineShadowPass()
|
||||
{
|
||||
if (!SHADOW_PASS_CHECK)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class clazz = Class.forName("net.optifine.shaders.Shaders");
|
||||
|
||||
SHADOW_PASS = clazz.getDeclaredField("isShadowPass");
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
SHADOW_PASS_CHECK = true;
|
||||
}
|
||||
|
||||
if (SHADOW_PASS != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (boolean) SHADOW_PASS.get(null);
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,333 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class FilteredResourceLocation implements IWritableLocation<FilteredResourceLocation>
|
||||
{
|
||||
public static final int DEFAULT_COLOR = 0xffffffff;
|
||||
|
||||
public ResourceLocation path;
|
||||
|
||||
public boolean autoSize = true;
|
||||
public int sizeW;
|
||||
public int sizeH;
|
||||
|
||||
public int color = DEFAULT_COLOR;
|
||||
public float scale = 1F;
|
||||
public boolean scaleToLargest;
|
||||
public int shiftX;
|
||||
public int shiftY;
|
||||
|
||||
/* Filters */
|
||||
public int pixelate = 1;
|
||||
public boolean erase;
|
||||
|
||||
public static FilteredResourceLocation from(NBTBase base)
|
||||
{
|
||||
try
|
||||
{
|
||||
FilteredResourceLocation location = new FilteredResourceLocation();
|
||||
|
||||
location.fromNbt(base);
|
||||
|
||||
return location;
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static FilteredResourceLocation from(JsonElement element)
|
||||
{
|
||||
try
|
||||
{
|
||||
FilteredResourceLocation location = new FilteredResourceLocation();
|
||||
|
||||
location.fromJson(element);
|
||||
|
||||
return location;
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public FilteredResourceLocation()
|
||||
{}
|
||||
|
||||
public FilteredResourceLocation(ResourceLocation path)
|
||||
{
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public int getWidth(int width)
|
||||
{
|
||||
if (!this.autoSize && this.sizeW > 0)
|
||||
{
|
||||
return this.sizeW;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
public int getHeight(int height)
|
||||
{
|
||||
if (!this.autoSize && this.sizeH > 0)
|
||||
{
|
||||
return this.sizeH;
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.path == null ? "" : this.path.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (super.equals(obj))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj instanceof FilteredResourceLocation)
|
||||
{
|
||||
FilteredResourceLocation frl = (FilteredResourceLocation) obj;
|
||||
|
||||
return Objects.equals(this.path, frl.path)
|
||||
&& this.autoSize == frl.autoSize
|
||||
&& this.sizeW == frl.sizeW
|
||||
&& this.sizeH == frl.sizeH
|
||||
&& this.scaleToLargest == frl.scaleToLargest
|
||||
&& this.color == frl.color
|
||||
&& this.scale == frl.scale
|
||||
&& this.shiftX == frl.shiftX
|
||||
&& this.shiftY == frl.shiftY
|
||||
&& this.pixelate == frl.pixelate
|
||||
&& this.erase == frl.erase;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
int hashCode = this.path.hashCode();
|
||||
|
||||
hashCode = 31 * hashCode + (this.autoSize ? 1 : 0);
|
||||
hashCode = 31 * hashCode + this.sizeW;
|
||||
hashCode = 31 * hashCode + this.sizeH;
|
||||
hashCode = 31 * hashCode + (this.scaleToLargest ? 1 : 0);
|
||||
hashCode = 31 * hashCode + this.color;
|
||||
hashCode = 31 * hashCode + (int) (this.scale * 1000);
|
||||
hashCode = 31 * hashCode + this.shiftX;
|
||||
hashCode = 31 * hashCode + this.shiftY;
|
||||
hashCode = 31 * hashCode + this.pixelate;
|
||||
hashCode = 31 * hashCode + (this.erase ? 1 : 0);
|
||||
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
public boolean isDefault()
|
||||
{
|
||||
return (this.autoSize || (this.sizeW == 0 && this.sizeH == 0)) && this.color == DEFAULT_COLOR && !this.scaleToLargest && this.scale == 1F && this.shiftX == 0 && this.shiftY == 0 && this.pixelate <= 1 && !this.erase;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNbt(NBTBase nbt) throws Exception
|
||||
{
|
||||
if (nbt instanceof NBTTagString)
|
||||
{
|
||||
this.path = RLUtils.create(nbt);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NBTTagCompound tag = (NBTTagCompound) nbt;
|
||||
|
||||
this.path = RLUtils.create(tag.getString("Path"));
|
||||
|
||||
if (tag.hasKey("Color"))
|
||||
{
|
||||
this.color = tag.getInteger("Color");
|
||||
}
|
||||
|
||||
if (tag.hasKey("Scale"))
|
||||
{
|
||||
this.scale = tag.getFloat("Scale");
|
||||
}
|
||||
|
||||
if (tag.hasKey("ScaleToLargest"))
|
||||
{
|
||||
this.scaleToLargest = tag.getBoolean("ScaleToLargest");
|
||||
}
|
||||
|
||||
if (tag.hasKey("ShiftX"))
|
||||
{
|
||||
this.shiftX = tag.getInteger("ShiftX");
|
||||
}
|
||||
|
||||
if (tag.hasKey("ShiftY"))
|
||||
{
|
||||
this.shiftY = tag.getInteger("ShiftY");
|
||||
}
|
||||
|
||||
if (tag.hasKey("Pixelate"))
|
||||
{
|
||||
this.pixelate = tag.getInteger("Pixelate");
|
||||
}
|
||||
|
||||
if (tag.hasKey("Erase"))
|
||||
{
|
||||
this.erase = tag.getBoolean("Erase");
|
||||
}
|
||||
|
||||
if (tag.hasKey("AutoSize"))
|
||||
{
|
||||
this.autoSize = tag.getBoolean("AutoSize");
|
||||
}
|
||||
|
||||
if (tag.hasKey("SizeW"))
|
||||
{
|
||||
this.sizeW = tag.getInteger("SizeW");
|
||||
}
|
||||
|
||||
if (tag.hasKey("SizeH"))
|
||||
{
|
||||
this.sizeH = tag.getInteger("SizeH");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJson(JsonElement element) throws Exception
|
||||
{
|
||||
if (element.isJsonPrimitive())
|
||||
{
|
||||
this.path = RLUtils.create(element);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
|
||||
this.path = RLUtils.create(object.get("path").getAsString());
|
||||
|
||||
if (object.has("color"))
|
||||
{
|
||||
this.color = object.get("color").getAsInt();
|
||||
}
|
||||
|
||||
if (object.has("scale"))
|
||||
{
|
||||
this.scale = object.get("scale").getAsFloat();
|
||||
}
|
||||
|
||||
if (object.has("scaleToLargest"))
|
||||
{
|
||||
this.scaleToLargest = object.get("scaleToLargest").getAsBoolean();
|
||||
}
|
||||
|
||||
if (object.has("shiftX"))
|
||||
{
|
||||
this.shiftX = object.get("shiftX").getAsInt();
|
||||
}
|
||||
|
||||
if (object.has("shiftY"))
|
||||
{
|
||||
this.shiftY = object.get("shiftY").getAsInt();
|
||||
}
|
||||
|
||||
if (object.has("pixelate"))
|
||||
{
|
||||
this.pixelate = object.get("pixelate").getAsInt();
|
||||
}
|
||||
|
||||
if (object.has("erase"))
|
||||
{
|
||||
this.erase = object.get("erase").getAsBoolean();
|
||||
}
|
||||
|
||||
if (object.has("autoSize"))
|
||||
{
|
||||
this.autoSize = object.get("autoSize").getAsBoolean();
|
||||
}
|
||||
|
||||
if (object.has("sizeW"))
|
||||
{
|
||||
this.sizeW = object.get("sizeW").getAsInt();
|
||||
}
|
||||
|
||||
if (object.has("sizeH"))
|
||||
{
|
||||
this.sizeH = object.get("sizeH").getAsInt();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase writeNbt()
|
||||
{
|
||||
NBTTagCompound tag = new NBTTagCompound();
|
||||
|
||||
tag.setString("Path", this.toString());
|
||||
|
||||
if (this.color != DEFAULT_COLOR) tag.setInteger("Color", this.color);
|
||||
if (this.scale != 1) tag.setFloat("Scale", this.scale);
|
||||
if (this.scaleToLargest) tag.setBoolean("ScaleToLargest", this.scaleToLargest);
|
||||
if (this.shiftX != 0) tag.setInteger("ShiftX", this.shiftX);
|
||||
if (this.shiftY != 0) tag.setInteger("ShiftY", this.shiftY);
|
||||
if (this.pixelate > 1) tag.setInteger("Pixelate", this.pixelate);
|
||||
if (this.erase) tag.setBoolean("Erase", this.erase);
|
||||
if (!this.autoSize) tag.setBoolean("AutoSize", this.autoSize);
|
||||
if (this.sizeW > 0) tag.setInteger("SizeW", this.sizeW);
|
||||
if (this.sizeH > 0) tag.setInteger("SizeH", this.sizeH);
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement writeJson()
|
||||
{
|
||||
JsonObject object = new JsonObject();
|
||||
|
||||
object.addProperty("path", this.toString());
|
||||
|
||||
if (this.color != DEFAULT_COLOR) object.addProperty("color", this.color);
|
||||
if (this.scale != 1) object.addProperty("scale", this.scale);
|
||||
if (this.scaleToLargest) object.addProperty("scaleToLargest", this.scaleToLargest);
|
||||
if (this.shiftX != 0) object.addProperty("shiftX", this.shiftX);
|
||||
if (this.shiftY != 0) object.addProperty("shiftY", this.shiftY);
|
||||
if (this.pixelate > 1) object.addProperty("pixelate", this.pixelate);
|
||||
if (this.erase) object.addProperty("erase", this.erase);
|
||||
if (!this.autoSize) object.addProperty("autoSize", this.autoSize);
|
||||
if (this.sizeW > 0) object.addProperty("sizeW", this.sizeW);
|
||||
if (this.sizeH > 0) object.addProperty("sizeH", this.sizeH);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation clone()
|
||||
{
|
||||
return RLUtils.clone(this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FilteredResourceLocation copy()
|
||||
{
|
||||
return FilteredResourceLocation.from(this.writeNbt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.texture.AbstractTexture;
|
||||
import net.minecraft.client.renderer.texture.ITextureObject;
|
||||
import net.minecraft.client.renderer.texture.TextureManager;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import com.eliotlash.mclib.utils.MathUtils;
|
||||
|
||||
public class GifTexture extends AbstractTexture
|
||||
{
|
||||
public static int globalTick = 0;
|
||||
public static int entityTick = -1;
|
||||
|
||||
public static boolean tried = false;
|
||||
public static Field fieldMultiTex = null;
|
||||
|
||||
public ResourceLocation base;
|
||||
public ResourceLocation[] frames;
|
||||
public int[] delays;
|
||||
|
||||
public int duration;
|
||||
|
||||
public static void bindTexture(ResourceLocation location, int ticks, float partialTicks)
|
||||
{
|
||||
TextureManager textures = Minecraft.getMinecraft().renderEngine;
|
||||
|
||||
if (location.getResourcePath().endsWith("gif"))
|
||||
{
|
||||
ITextureObject object = textures.getTexture(location);
|
||||
|
||||
if (object instanceof GifTexture)
|
||||
{
|
||||
GifTexture texture = (GifTexture) object;
|
||||
|
||||
location = texture.getFrame(ticks, partialTicks);
|
||||
}
|
||||
}
|
||||
|
||||
textures.bindTexture(location);
|
||||
}
|
||||
|
||||
public static void updateTick()
|
||||
{
|
||||
globalTick += 1;
|
||||
}
|
||||
|
||||
public GifTexture(ResourceLocation texture, int[] delays, ResourceLocation[] frames)
|
||||
{
|
||||
this.base = texture;
|
||||
this.delays = Arrays.copyOf(delays, delays.length);
|
||||
this.frames = frames;
|
||||
}
|
||||
|
||||
public void calculateDuration()
|
||||
{
|
||||
this.duration = 0;
|
||||
|
||||
for (int delay : this.delays)
|
||||
{
|
||||
this.duration += delay;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadTexture(IResourceManager resourceManager) throws IOException
|
||||
{}
|
||||
|
||||
@Override
|
||||
public int getGlTextureId()
|
||||
{
|
||||
Minecraft mc = Minecraft.getMinecraft();
|
||||
TextureManager textures = mc.renderEngine;
|
||||
ResourceLocation rl = this.getFrame(entityTick > -1 ? entityTick : globalTick, mc.timer.renderPartialTicks);
|
||||
|
||||
textures.bindTexture(rl);
|
||||
|
||||
ITextureObject texture = textures.getTexture(rl);
|
||||
|
||||
this.updateMultiTex(texture);
|
||||
|
||||
return texture.getGlTextureId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteGlTexture()
|
||||
{}
|
||||
|
||||
public ResourceLocation getFrame(int ticks, float partialTicks)
|
||||
{
|
||||
int tick = (int) ((ticks + partialTicks) * 5 % this.duration);
|
||||
|
||||
int duration = 0;
|
||||
int index = 0;
|
||||
|
||||
for (int delay : this.delays)
|
||||
{
|
||||
duration += delay;
|
||||
|
||||
if (tick < duration)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
index = MathUtils.clamp(index, 0, this.frames.length - 1);
|
||||
|
||||
return this.frames[index];
|
||||
}
|
||||
|
||||
private void updateMultiTex(ITextureObject texture)
|
||||
{
|
||||
if (!tried)
|
||||
{
|
||||
try
|
||||
{
|
||||
fieldMultiTex = AbstractTexture.class.getField("multiTex");
|
||||
}
|
||||
catch (NoSuchFieldException | SecurityException e)
|
||||
{
|
||||
fieldMultiTex = null;
|
||||
}
|
||||
|
||||
tried = true;
|
||||
}
|
||||
|
||||
if (texture instanceof AbstractTexture && fieldMultiTex != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Object obj = fieldMultiTex.get(texture);
|
||||
|
||||
fieldMultiTex.set(this, obj);
|
||||
}
|
||||
catch (IllegalArgumentException | IllegalAccessException e)
|
||||
{}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
public interface IResourceTransformer
|
||||
{
|
||||
public String transformDomain(String domain, String path);
|
||||
|
||||
public String transformPath(String domain, String path);
|
||||
|
||||
public String transform(String location);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.eliotlash.mclib.utils.ICopy;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
|
||||
public interface IWritableLocation<T> extends ICopy<T>
|
||||
{
|
||||
public void fromNbt(NBTBase nbt) throws Exception;
|
||||
|
||||
public void fromJson(JsonElement element) throws Exception;
|
||||
|
||||
public NBTBase writeNbt();
|
||||
|
||||
public JsonElement writeJson();
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Multiple resource location class
|
||||
*
|
||||
* This bad boy allows constructing a single texture out of several
|
||||
* {@link ResourceLocation}s. It doesn't really make sense for other
|
||||
* types of resources beside pictures.
|
||||
*/
|
||||
public class MultiResourceLocation extends ResourceLocation implements IWritableLocation<MultiResourceLocation>
|
||||
{
|
||||
public List<FilteredResourceLocation> children = new ArrayList<FilteredResourceLocation>();
|
||||
|
||||
private int id = -1;
|
||||
|
||||
public MultiResourceLocation(String resourceName)
|
||||
{
|
||||
this();
|
||||
this.children.add(new FilteredResourceLocation(RLUtils.create(resourceName)));
|
||||
}
|
||||
|
||||
public MultiResourceLocation(String resourceDomainIn, String resourcePathIn)
|
||||
{
|
||||
this();
|
||||
this.children.add(new FilteredResourceLocation(RLUtils.create(resourceDomainIn, resourcePathIn)));
|
||||
}
|
||||
|
||||
public static MultiResourceLocation from(NBTBase nbt)
|
||||
{
|
||||
NBTTagList list = nbt instanceof NBTTagList ? (NBTTagList) nbt : null;
|
||||
|
||||
if (list == null || list.tagCount()==0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MultiResourceLocation multi = new MultiResourceLocation();
|
||||
|
||||
try
|
||||
{
|
||||
multi.fromNbt(nbt);
|
||||
|
||||
return multi;
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MultiResourceLocation from(JsonElement element)
|
||||
{
|
||||
JsonArray list = element.isJsonArray() ? (JsonArray) element : null;
|
||||
|
||||
if (list == null || list.size() == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
MultiResourceLocation multi = new MultiResourceLocation();
|
||||
|
||||
try
|
||||
{
|
||||
multi.fromJson(element);
|
||||
|
||||
return multi;
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MultiResourceLocation()
|
||||
{
|
||||
/* This needed so there would less chances to match with an
|
||||
* actual ResourceLocation */
|
||||
super("it_would_be_very_ironic", "if_this_would_match_with_regular_rls");
|
||||
}
|
||||
|
||||
public void recalculateId()
|
||||
{
|
||||
this.id = MultiResourceLocationManager.getId(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceDomain()
|
||||
{
|
||||
return this.children.isEmpty() ? "" : this.children.get(0).path.getResourceDomain();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourcePath()
|
||||
{
|
||||
return this.children.isEmpty() ? "" : this.children.get(0).path.getResourcePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is mostly for looks, but it doesn't really makes sense by
|
||||
* itself
|
||||
*/
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.getResourceDomain() + ":" + this.getResourcePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj instanceof MultiResourceLocation)
|
||||
{
|
||||
MultiResourceLocation multi = (MultiResourceLocation) obj;
|
||||
|
||||
return Objects.equal(this.children, multi.children);
|
||||
}
|
||||
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
if (this.id < 0)
|
||||
{
|
||||
this.recalculateId();
|
||||
}
|
||||
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromNbt(NBTBase nbt) throws Exception
|
||||
{
|
||||
NBTTagList list = (NBTTagList) nbt;
|
||||
|
||||
for (int i = 0; i < list.tagCount(); i++)
|
||||
{
|
||||
FilteredResourceLocation location = FilteredResourceLocation.from(list.getCompoundTagAt(i));
|
||||
|
||||
if (location != null)
|
||||
{
|
||||
this.children.add(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromJson(JsonElement element) throws Exception
|
||||
{
|
||||
JsonArray array = (JsonArray) element;
|
||||
|
||||
for (int i = 0; i < array.size(); i++)
|
||||
{
|
||||
FilteredResourceLocation location = FilteredResourceLocation.from(array.get(i));
|
||||
|
||||
if (location != null)
|
||||
{
|
||||
this.children.add(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NBTBase writeNbt()
|
||||
{
|
||||
NBTTagList list = new NBTTagList();
|
||||
|
||||
for (FilteredResourceLocation child : this.children)
|
||||
{
|
||||
NBTBase tag = child.writeNbt();
|
||||
|
||||
if (tag != null)
|
||||
{
|
||||
list.appendTag(tag);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonElement writeJson()
|
||||
{
|
||||
JsonArray array = new JsonArray();
|
||||
|
||||
for (FilteredResourceLocation child : this.children)
|
||||
{
|
||||
JsonElement element = child.writeJson();
|
||||
|
||||
if (element != null)
|
||||
{
|
||||
array.add(element);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiResourceLocation copy()
|
||||
{
|
||||
MultiResourceLocation newMulti = new MultiResourceLocation();
|
||||
|
||||
for (FilteredResourceLocation child : this.children)
|
||||
{
|
||||
newMulti.children.add(child.copy());
|
||||
}
|
||||
|
||||
return newMulti;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class MultiResourceLocationManager
|
||||
{
|
||||
private static int id = 0;
|
||||
private static Map<ResourceLocation, List<Pair>> map = new HashMap<ResourceLocation, List<Pair>>();
|
||||
|
||||
public static int getId(MultiResourceLocation location)
|
||||
{
|
||||
if (location.children.isEmpty())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ResourceLocation keyRL = location.children.get(0).path;
|
||||
List<Pair> pairs = map.get(keyRL);
|
||||
|
||||
if (pairs == null)
|
||||
{
|
||||
pairs = new ArrayList<Pair>();
|
||||
|
||||
map.put(keyRL, pairs);
|
||||
}
|
||||
|
||||
for (Pair pair : pairs)
|
||||
{
|
||||
if (pair.mrl.equals(location))
|
||||
{
|
||||
return pair.id;
|
||||
}
|
||||
}
|
||||
|
||||
int newId = id;
|
||||
|
||||
pairs.add(new Pair(newId, location.copy()));
|
||||
id += 1;
|
||||
|
||||
return newId;
|
||||
}
|
||||
|
||||
private static class Pair
|
||||
{
|
||||
public int id;
|
||||
public MultiResourceLocation mrl;
|
||||
|
||||
public Pair(int id, MultiResourceLocation mrl)
|
||||
{
|
||||
this.id = id;
|
||||
this.mrl = mrl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.eliotlash.mclib.utils.Color;
|
||||
|
||||
public enum PixelAccessor
|
||||
{
|
||||
BYTE()
|
||||
{
|
||||
@Override
|
||||
public void get(Pixels pixels, int index, Color color)
|
||||
{
|
||||
index *= pixels.pixelLength;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
if (pixels.hasAlpha())
|
||||
{
|
||||
color.a = ((int) pixels.pixelBytes[index + offset++] & 0xff) / 255F;
|
||||
}
|
||||
else
|
||||
{
|
||||
color.a = 1;
|
||||
}
|
||||
|
||||
color.b = ((int) pixels.pixelBytes[index + offset++] & 0xff) / 255F;
|
||||
color.g = ((int) pixels.pixelBytes[index + offset++] & 0xff) / 255F;
|
||||
color.r = ((int) pixels.pixelBytes[index + offset] & 0xff) / 255F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Pixels pixels, int index, Color color)
|
||||
{
|
||||
index *= pixels.pixelLength;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
if (pixels.hasAlpha())
|
||||
{
|
||||
pixels.pixelBytes[index + offset++] = (byte) (color.a * 0xff);
|
||||
}
|
||||
|
||||
pixels.pixelBytes[index + offset++] = (byte) (color.b * 0xff);
|
||||
pixels.pixelBytes[index + offset++] = (byte) (color.g * 0xff);
|
||||
pixels.pixelBytes[index + offset] = (byte) (color.r * 0xff);
|
||||
}
|
||||
},
|
||||
INT()
|
||||
{
|
||||
@Override
|
||||
public void get(Pixels pixels, int index, Color color)
|
||||
{
|
||||
int c = pixels.pixelInts[index];
|
||||
|
||||
int a = c >> 24 & 0xff;
|
||||
int b = c >> 16 & 0xff;
|
||||
int g = c >> 8 & 0xff;
|
||||
int r = c & 0xff;
|
||||
|
||||
color.r = r / 255F;
|
||||
color.g = g / 255F;
|
||||
color.b = b / 255F;
|
||||
color.a = a / 255F;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Pixels pixels, int index, Color color)
|
||||
{
|
||||
pixels.pixelInts[index] = ((int) (color.a * 0xff) << 24) + ((int) (color.b * 0xff) << 16) + ((int) (color.g * 0xff) << 8) + (int) (color.r * 0xff);
|
||||
}
|
||||
};
|
||||
|
||||
public abstract void get(Pixels pixels, int index, Color color);
|
||||
|
||||
public abstract void set(Pixels pixels, int index, Color color);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.eliotlash.mclib.utils.Color;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.DataBufferByte;
|
||||
import java.awt.image.DataBufferInt;
|
||||
|
||||
public class Pixels
|
||||
{
|
||||
public byte[] pixelBytes;
|
||||
public int[] pixelInts;
|
||||
public int pixelLength;
|
||||
public int width;
|
||||
public int height;
|
||||
|
||||
public Color color = new Color();
|
||||
private PixelAccessor accessor;
|
||||
|
||||
public void set(BufferedImage image)
|
||||
{
|
||||
if (image.getRaster().getDataBuffer() instanceof DataBufferByte)
|
||||
{
|
||||
this.pixelBytes = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
|
||||
this.pixelInts = null;
|
||||
this.accessor = PixelAccessor.BYTE;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.pixelInts = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
|
||||
this.pixelBytes = null;
|
||||
this.accessor = PixelAccessor.INT;
|
||||
}
|
||||
|
||||
this.pixelLength = image.getAlphaRaster() != null ? 4 : 3;
|
||||
this.width = image.getWidth();
|
||||
this.height = image.getHeight();
|
||||
}
|
||||
|
||||
public boolean hasAlpha()
|
||||
{
|
||||
return this.pixelLength == 4;
|
||||
}
|
||||
|
||||
public int toIndex(int x, int y)
|
||||
{
|
||||
return x + y * this.width;
|
||||
}
|
||||
|
||||
public int toX(int index)
|
||||
{
|
||||
return index % this.width;
|
||||
}
|
||||
|
||||
public int toY(int index)
|
||||
{
|
||||
return index / this.width;
|
||||
}
|
||||
|
||||
public int getCount()
|
||||
{
|
||||
return this.accessor == PixelAccessor.BYTE ? this.pixelBytes.length / this.pixelLength : this.pixelInts.length;
|
||||
}
|
||||
|
||||
public Color getColor(int index)
|
||||
{
|
||||
this.accessor.get(this, index, this.color);
|
||||
|
||||
return this.color;
|
||||
}
|
||||
|
||||
public Color getColor(int x, int y)
|
||||
{
|
||||
return this.getColor(this.toIndex(x, y));
|
||||
}
|
||||
|
||||
public void setColor(int index, Color color)
|
||||
{
|
||||
this.accessor.set(this, index, color);
|
||||
}
|
||||
|
||||
public void setColor(int x, int y, Color color)
|
||||
{
|
||||
this.setColor(this.toIndex(x, y), color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonNull;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.SimpleResource;
|
||||
import net.minecraft.nbt.NBTBase;
|
||||
import net.minecraft.nbt.NBTTagString;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* {@link ResourceLocation} utility methods
|
||||
*
|
||||
* This class has utils for saving and reading {@link ResourceLocation} from
|
||||
* actor model and skin.
|
||||
*/
|
||||
public class RLUtils
|
||||
{
|
||||
private static List<IResourceTransformer> transformers = new ArrayList<IResourceTransformer>();
|
||||
private static ResourceLocation pixel = new ResourceLocation("mclib:textures/pixel.png");
|
||||
|
||||
/**
|
||||
* Get stream for multi resource location
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static IResource getStreamForMultiskin(MultiResourceLocation multi) throws IOException
|
||||
{
|
||||
if (multi.children.isEmpty())
|
||||
{
|
||||
throw new IOException("Multi-skin is empty!");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// if (true)//TODO
|
||||
// {
|
||||
// MultiskinThread.add(multi);
|
||||
//
|
||||
// return Minecraft.getMinecraft().getResourceManager().getResource(pixel);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
//MultiskinThread.clear();
|
||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
ImageIO.write(TextureProcessor.postProcess(multi), "png", stream);
|
||||
|
||||
return new SimpleResource(multi, new ByteArrayInputStream(stream.toByteArray()), null, null);
|
||||
//}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(IResourceTransformer transformer)
|
||||
{
|
||||
transformers.add(transformer);
|
||||
}
|
||||
|
||||
public static ResourceLocation create(String path)
|
||||
{
|
||||
for (IResourceTransformer transformer : transformers)
|
||||
{
|
||||
path = transformer.transform(path);
|
||||
}
|
||||
|
||||
return new TextureLocation(path);
|
||||
}
|
||||
|
||||
public static ResourceLocation create(String domain, String path)
|
||||
{
|
||||
for (IResourceTransformer transformer : transformers)
|
||||
{
|
||||
String newDomain = transformer.transformDomain(domain, path);
|
||||
String newPath = transformer.transformPath(domain, path);
|
||||
|
||||
domain = newDomain;
|
||||
path = newPath;
|
||||
}
|
||||
|
||||
return new TextureLocation(domain, path);
|
||||
}
|
||||
|
||||
public static ResourceLocation create(NBTBase base)
|
||||
{
|
||||
ResourceLocation location = MultiResourceLocation.from(base);
|
||||
|
||||
if (location != null)
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
if (base instanceof NBTTagString)
|
||||
{
|
||||
return create(((NBTTagString) base).func_150285_a_());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ResourceLocation create(JsonElement element)
|
||||
{
|
||||
ResourceLocation location = MultiResourceLocation.from(element);
|
||||
|
||||
if (location != null)
|
||||
{
|
||||
return location;
|
||||
}
|
||||
|
||||
if (element.isJsonPrimitive())
|
||||
{
|
||||
return create(element.getAsString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static NBTBase writeNbt(ResourceLocation location)
|
||||
{
|
||||
if (location instanceof IWritableLocation)
|
||||
{
|
||||
return ((IWritableLocation) location).writeNbt();
|
||||
}
|
||||
else if (location != null)
|
||||
{
|
||||
return new NBTTagString(location.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static JsonElement writeJson(ResourceLocation location)
|
||||
{
|
||||
if (location instanceof IWritableLocation)
|
||||
{
|
||||
return ((IWritableLocation) location).writeJson();
|
||||
}
|
||||
else if (location != null)
|
||||
{
|
||||
return new JsonPrimitive(location.toString());
|
||||
}
|
||||
|
||||
return JsonNull.INSTANCE;
|
||||
}
|
||||
|
||||
public static ResourceLocation clone(ResourceLocation location)
|
||||
{
|
||||
if (location instanceof IWritableLocation)
|
||||
{
|
||||
Object copy = ((IWritableLocation) location).copy();
|
||||
|
||||
if (copy instanceof ResourceLocation)
|
||||
{
|
||||
return (ResourceLocation) copy;
|
||||
}
|
||||
}
|
||||
|
||||
if (location != null)
|
||||
{
|
||||
return create(location.toString());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Texture location
|
||||
*
|
||||
* A hack class that allows to use uppercase characters in the path 1.11.2 and
|
||||
* up.
|
||||
*/
|
||||
public class TextureLocation extends ResourceLocation
|
||||
{
|
||||
public TextureLocation(String domain, String path)
|
||||
{
|
||||
super(domain, path);
|
||||
|
||||
this.set(domain, path);
|
||||
}
|
||||
|
||||
public TextureLocation(String string)
|
||||
{
|
||||
super(string);
|
||||
|
||||
this.set(string);
|
||||
}
|
||||
|
||||
public void set(String location)
|
||||
{
|
||||
String[] split = location.split(":");
|
||||
String domain = split.length > 0 ? split[0] : "minecraft";
|
||||
String path = split.length > 1 ? split[1] : "";
|
||||
|
||||
this.set(domain, path);
|
||||
}
|
||||
|
||||
public void set(String domain, String path)
|
||||
{
|
||||
/* Guess what it does */
|
||||
Field[] fields = ResourceLocation.class.getDeclaredFields();
|
||||
|
||||
for (Field field : fields)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.unlockField(field);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fields[0].set(this, domain);
|
||||
fields[1].set(this, path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
protected void unlockField(Field field) throws Exception
|
||||
{
|
||||
field.setAccessible(true);
|
||||
|
||||
Field modifiers = Field.class.getDeclaredField("modifiers");
|
||||
modifiers.setAccessible(true);
|
||||
modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.eliotlash.mclib.utils.resources;
|
||||
|
||||
import com.eliotlash.mclib.utils.Color;
|
||||
import cpw.mods.fml.relauncher.Side;
|
||||
import cpw.mods.fml.relauncher.SideOnly;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.resources.IResource;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class TextureProcessor
|
||||
{
|
||||
public static Pixels pixels = new Pixels();
|
||||
public static Pixels target = new Pixels();
|
||||
|
||||
public static BufferedImage postProcess(MultiResourceLocation multi)
|
||||
{
|
||||
BufferedImage image = process(multi);
|
||||
return image;
|
||||
}
|
||||
|
||||
public static BufferedImage process(MultiResourceLocation multi)
|
||||
{
|
||||
IResourceManager manager = Minecraft.getMinecraft().getResourceManager();
|
||||
List<BufferedImage> images = new ArrayList<BufferedImage>();
|
||||
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
|
||||
for (int i = 0; i < multi.children.size(); i++)
|
||||
{
|
||||
FilteredResourceLocation child = multi.children.get(i);
|
||||
BufferedImage image = null;
|
||||
|
||||
try
|
||||
{
|
||||
IResource resource = manager.getResource(child.path);
|
||||
|
||||
image = ImageIO.read(resource.getInputStream());
|
||||
|
||||
w = Math.max(w, child.getWidth(image.getWidth()));
|
||||
h = Math.max(h, child.getHeight(image.getHeight()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
images.add(image);
|
||||
}
|
||||
|
||||
BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics g = image.getGraphics();
|
||||
|
||||
for (int i = 0; i < multi.children.size(); i++)
|
||||
{
|
||||
BufferedImage child = images.get(i);
|
||||
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FilteredResourceLocation filter = multi.children.get(i);
|
||||
int iw = child.getWidth();
|
||||
int ih = child.getHeight();
|
||||
|
||||
if (filter.scaleToLargest)
|
||||
{
|
||||
iw = w;
|
||||
ih = h;
|
||||
}
|
||||
else if (filter.scale != 0 && filter.scale > 0)
|
||||
{
|
||||
iw = (int) (iw * filter.scale);
|
||||
ih = (int) (ih * filter.scale);
|
||||
}
|
||||
|
||||
if (iw > 0 && ih > 0)
|
||||
{
|
||||
if (filter.erase)
|
||||
{
|
||||
processErase(image, child, filter, iw, ih);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (filter.color != 0xffffff || filter.pixelate > 1)
|
||||
{
|
||||
processImage(child, filter);
|
||||
}
|
||||
|
||||
g.drawImage(child, filter.shiftX, filter.shiftY, iw, ih, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.dispose();
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply erasing
|
||||
*/
|
||||
private static void processErase(BufferedImage image, BufferedImage child, FilteredResourceLocation filter, int iw, int ih)
|
||||
{
|
||||
BufferedImage mask = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
|
||||
Graphics g2 = mask.getGraphics();
|
||||
|
||||
g2.drawImage(child, filter.shiftX, filter.shiftY, iw, ih, null);
|
||||
g2.dispose();
|
||||
|
||||
target.set(mask);
|
||||
pixels.set(image);
|
||||
|
||||
for (int p = 0, c = target.getCount(); p < c; p++)
|
||||
{
|
||||
com.eliotlash.mclib.utils.Color pixel = target.getColor(p);
|
||||
|
||||
if (pixel.a > 0.999F)
|
||||
{
|
||||
pixel = pixels.getColor(p);
|
||||
pixel.a = 0;
|
||||
pixels.setColor(p, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filters
|
||||
*/
|
||||
private static void processImage(BufferedImage child, FilteredResourceLocation frl)
|
||||
{
|
||||
pixels.set(child);
|
||||
|
||||
com.eliotlash.mclib.utils.Color filter = new com.eliotlash.mclib.utils.Color().set(frl.color);
|
||||
com.eliotlash.mclib.utils.Color pixel = new Color();
|
||||
|
||||
for (int i = 0, c = pixels.getCount(); i < c; i++)
|
||||
{
|
||||
pixel.copy(pixels.getColor(i));
|
||||
|
||||
if (pixels.hasAlpha())
|
||||
{
|
||||
if (pixel.a <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (frl.pixelate > 1)
|
||||
{
|
||||
int x = pixels.toX(i);
|
||||
int y = pixels.toY(i);
|
||||
boolean origin = x % frl.pixelate == 0 && y % frl.pixelate == 0;
|
||||
|
||||
x -= x % frl.pixelate;
|
||||
y -= y % frl.pixelate;
|
||||
|
||||
pixel.copy(pixels.getColor(x, y));
|
||||
pixels.setColor(i, pixel);
|
||||
|
||||
if (!origin)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pixel.r *= filter.r;
|
||||
pixel.g *= filter.g;
|
||||
pixel.b *= filter.b;
|
||||
pixel.a *= filter.a;
|
||||
pixels.setColor(i, pixel);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package com.eliotlash.molang;
|
||||
|
||||
import com.eliotlash.molang.functions.*;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.eliotlash.mclib.math.Constant;
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.mclib.math.MathBuilder;
|
||||
import com.eliotlash.mclib.math.Variable;
|
||||
import com.eliotlash.molang.expressions.MolangAssignment;
|
||||
import com.eliotlash.molang.expressions.MolangExpression;
|
||||
import com.eliotlash.molang.expressions.MolangMultiStatement;
|
||||
import com.eliotlash.molang.expressions.MolangValue;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MolangParser extends MathBuilder implements Serializable
|
||||
{
|
||||
public static final MolangExpression ZERO = new MolangValue(null, new Constant(0));
|
||||
public static final MolangExpression ONE = new MolangValue(null, new Constant(1));
|
||||
public static final String RETURN = "return ";
|
||||
|
||||
private MolangMultiStatement currentStatement;
|
||||
private boolean registerAsGlobals;
|
||||
|
||||
public MolangParser()
|
||||
{
|
||||
super();
|
||||
|
||||
/* Replace radian based sin and cos with degreebased */
|
||||
this.functions.put("cos", CosDegrees.class);
|
||||
this.functions.put("sin", SinDegrees.class);
|
||||
this.functions.put("acos", AcosDegrees.class);
|
||||
this.functions.put("asin", AsinDegrees.class);
|
||||
this.functions.put("atan", AtanDegrees.class);
|
||||
this.functions.put("atan2", Atan2Degrees.class);
|
||||
|
||||
/* Remap functions to be in tact with Molang specification */
|
||||
this.remap("abs", "math.abs");
|
||||
this.remap("ceil", "math.ceil");
|
||||
this.remap("clamp", "math.clamp");
|
||||
this.remap("cos", "math.cos");
|
||||
this.remap("exp", "math.exp");
|
||||
this.remap("floor", "math.floor");
|
||||
this.remap("lerp", "math.lerp");
|
||||
this.remap("lerprotate", "math.lerprotate");
|
||||
this.remap("ln", "math.ln");
|
||||
this.remap("max", "math.max");
|
||||
this.remap("min", "math.min");
|
||||
this.remap("mod", "math.mod");
|
||||
this.remap("pow", "math.pow");
|
||||
this.remap("random", "math.random");
|
||||
this.remap("round", "math.round");
|
||||
this.remap("sin", "math.sin");
|
||||
this.remap("sqrt", "math.sqrt");
|
||||
this.remap("trunc", "math.trunc");
|
||||
|
||||
/* New functions in 1.16 */
|
||||
this.remap("acos", "math.acos");
|
||||
this.remap("asin", "math.asin");
|
||||
this.remap("atan", "math.atan");
|
||||
this.remap("atan2", "math.atan2");
|
||||
this.remap("randomi", "math.random_integer");
|
||||
this.remap("roll", "math.die_roll");
|
||||
this.remap("rolli", "math.die_roll_integer");
|
||||
this.remap("hermite", "math.hermite_blend");
|
||||
|
||||
/* Remap variables as well */
|
||||
this.remapVar("PI", "math.pi");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remap function names
|
||||
*/
|
||||
public void remap(String old, String newName)
|
||||
{
|
||||
this.functions.put(newName, this.functions.remove(old));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remap variable names
|
||||
*/
|
||||
public void remapVar(String old, String newName)
|
||||
{
|
||||
this.variables.put(newName, this.variables.remove(old));
|
||||
}
|
||||
|
||||
public void setValue(String name, double value)
|
||||
{
|
||||
Variable variable = this.getVariable(name);
|
||||
|
||||
if (variable != null)
|
||||
{
|
||||
variable.set(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interactively return a new variable
|
||||
*/
|
||||
@Override
|
||||
public Variable getVariable(String name)
|
||||
{
|
||||
Variable variable = this.currentStatement == null ? null : this.currentStatement.locals.get(name);
|
||||
|
||||
if (variable == null)
|
||||
{
|
||||
variable = super.getVariable(name);
|
||||
}
|
||||
|
||||
if (variable == null)
|
||||
{
|
||||
variable = new Variable(name, 0);
|
||||
|
||||
this.register(variable);
|
||||
}
|
||||
|
||||
return variable;
|
||||
}
|
||||
|
||||
public MolangExpression parseJson(JsonElement element) throws MolangException
|
||||
{
|
||||
if (element.isJsonPrimitive())
|
||||
{
|
||||
JsonPrimitive primitive = element.getAsJsonPrimitive();
|
||||
|
||||
if (primitive.isString())
|
||||
{
|
||||
try
|
||||
{
|
||||
return new MolangValue(this, new Constant(Double.parseDouble(primitive.getAsString())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{}
|
||||
|
||||
return this.parseExpression(primitive.getAsString());
|
||||
}
|
||||
else
|
||||
{
|
||||
return new MolangValue(this, new Constant(primitive.getAsDouble()));
|
||||
}
|
||||
}
|
||||
|
||||
return ZERO;
|
||||
}
|
||||
|
||||
public MolangExpression parseGlobalJson(JsonElement element) throws MolangException
|
||||
{
|
||||
this.registerAsGlobals = true;
|
||||
|
||||
MolangExpression expression = parseJson(element);
|
||||
|
||||
this.registerAsGlobals = false;
|
||||
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a molang expression
|
||||
*/
|
||||
public MolangExpression parseExpression(String expression) throws MolangException
|
||||
{
|
||||
List<String> lines = new ArrayList<String>();
|
||||
|
||||
for (String split : expression.toLowerCase().trim().split(";"))
|
||||
{
|
||||
if (!split.trim().isEmpty())
|
||||
{
|
||||
lines.add(split);
|
||||
}
|
||||
}
|
||||
|
||||
if (lines.size() == 0)
|
||||
{
|
||||
throw new MolangException("Molang expression cannot be blank!");
|
||||
}
|
||||
|
||||
MolangMultiStatement result = new MolangMultiStatement(this);
|
||||
|
||||
this.currentStatement = result;
|
||||
|
||||
try
|
||||
{
|
||||
for (String line : lines)
|
||||
{
|
||||
result.expressions.add(this.parseOneLine(line));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.currentStatement = null;
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
this.currentStatement = null;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a single Molang statement
|
||||
*/
|
||||
protected MolangExpression parseOneLine(String expression) throws MolangException
|
||||
{
|
||||
expression = expression.trim();
|
||||
|
||||
if (expression.startsWith(RETURN))
|
||||
{
|
||||
try
|
||||
{
|
||||
return new MolangValue(this, this.parse(expression.substring(RETURN.length()))).addReturn();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MolangException("Couldn't parse return '" + expression + "' expression!");
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
List<Object> symbols = this.breakdownChars(this.breakdown(expression));
|
||||
|
||||
/* Assignment it is */
|
||||
if (symbols.size() >= 3 && symbols.get(0) instanceof String && this.isVariable(symbols.get(0)) && symbols.get(1).equals("="))
|
||||
{
|
||||
String name = (String) symbols.get(0);
|
||||
symbols = symbols.subList(2, symbols.size());
|
||||
|
||||
Variable variable = null;
|
||||
|
||||
if (!this.registerAsGlobals && !this.variables.containsKey(name) && !this.currentStatement.locals.containsKey(name))
|
||||
{
|
||||
variable = new Variable(name, 0);
|
||||
this.currentStatement.locals.put(name, variable);
|
||||
}
|
||||
else
|
||||
{
|
||||
variable = this.getVariable(name);
|
||||
}
|
||||
|
||||
return new MolangAssignment(this, variable, this.parseSymbolsMolang(symbols));
|
||||
}
|
||||
|
||||
return new MolangValue(this, this.parseSymbolsMolang(symbols));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new MolangException("Couldn't parse '" + expression + "' expression!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper around {@link #parseSymbols(List)} to throw {@link MolangException}
|
||||
*/
|
||||
private IValue parseSymbolsMolang(List<Object> symbols) throws MolangException
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.parseSymbols(symbols);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
||||
throw new MolangException("Couldn't parse an expression!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend this method to allow {@link #breakdownChars(String[])} to capture
|
||||
* "=" as an operator so it was easier to parse assignment statements
|
||||
*/
|
||||
@Override
|
||||
protected boolean isOperator(String s)
|
||||
{
|
||||
return super.isOperator(s) || s.equals("=");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package com.eliotlash.molang.expressions;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.molang.MolangParser;
|
||||
import software.bernie.geckolib3.resource.GeckoLibCache;
|
||||
import com.eliotlash.mclib.math.Variable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
public class MolangAssignment extends MolangExpression {
|
||||
public Variable variable;
|
||||
public IValue expression;
|
||||
public MolangAssignment(){}
|
||||
public MolangAssignment(MolangParser context, Variable variable, IValue expression) {
|
||||
super(context);
|
||||
this.variable = variable;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public double get() {
|
||||
double value = this.expression.get();
|
||||
this.variable.set(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.variable.getName() + " = " + this.expression.toString();
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeObject(variable);
|
||||
out.writeObject(expression);
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
|
||||
variable= (Variable) in.readObject();
|
||||
expression = (MolangExpression) in.readObject();
|
||||
context = GeckoLibCache.getInstance().parser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package com.eliotlash.molang.expressions;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.molang.MolangParser;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import software.bernie.geckolib3.resource.GeckoLibCache;
|
||||
import com.eliotlash.mclib.math.Constant;
|
||||
import com.eliotlash.mclib.math.Operation;
|
||||
|
||||
import java.io.Externalizable;
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
public abstract class MolangExpression implements IValue, Externalizable {
|
||||
public MolangParser context;
|
||||
public MolangExpression(){}
|
||||
|
||||
public static boolean isZero(MolangExpression expression) {
|
||||
return isConstant(expression, 0.0);
|
||||
}
|
||||
|
||||
public static boolean isOne(MolangExpression expression) {
|
||||
return isConstant(expression, 1.0);
|
||||
}
|
||||
|
||||
public static boolean isConstant(MolangExpression expression, double x) {
|
||||
if (!(expression instanceof MolangValue)) {
|
||||
return false;
|
||||
} else {
|
||||
MolangValue value = (MolangValue) expression;
|
||||
return value.value instanceof Constant && Operation.equals(value.value.get(), x);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isExpressionConstant(MolangExpression expression) {
|
||||
if (expression instanceof MolangValue) {
|
||||
MolangValue value = (MolangValue) expression;
|
||||
return value.value instanceof Constant;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public MolangExpression(MolangParser context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public JsonElement toJson() {
|
||||
return new JsonPrimitive(this.toString());
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
|
||||
context = GeckoLibCache.getInstance().parser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package com.eliotlash.molang.expressions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
import com.eliotlash.molang.MolangParser;
|
||||
import software.bernie.geckolib3.resource.GeckoLibCache;
|
||||
import com.eliotlash.mclib.math.Variable;
|
||||
|
||||
public class MolangMultiStatement extends MolangExpression {
|
||||
public List<MolangExpression> expressions = new ArrayList();
|
||||
public Map<String, Variable> locals = new HashMap();
|
||||
public MolangMultiStatement() {
|
||||
super();
|
||||
}
|
||||
public MolangMultiStatement(MolangParser context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public double get() {
|
||||
double value = 0.0;
|
||||
|
||||
MolangExpression expression;
|
||||
for(Iterator var3 = this.expressions.iterator(); var3.hasNext(); value = expression.get()) {
|
||||
expression = (MolangExpression)var3.next();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringJoiner builder = new StringJoiner("; ");
|
||||
Iterator var2 = this.expressions.iterator();
|
||||
|
||||
while(var2.hasNext()) {
|
||||
MolangExpression expression = (MolangExpression)var2.next();
|
||||
builder.add(expression.toString());
|
||||
if (expression instanceof MolangValue && ((MolangValue)expression).returns) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeObject(expressions);
|
||||
out.writeObject(locals);
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
|
||||
expressions = (List<MolangExpression>) in.readObject();
|
||||
locals = (Map<String, Variable>) in.readObject();
|
||||
context = GeckoLibCache.getInstance().parser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by FernFlower decompiler)
|
||||
//
|
||||
|
||||
package com.eliotlash.molang.expressions;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.molang.MolangParser;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import software.bernie.geckolib3.resource.GeckoLibCache;
|
||||
import com.eliotlash.mclib.math.Constant;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectOutput;
|
||||
|
||||
public class MolangValue extends MolangExpression {
|
||||
public IValue value;
|
||||
public boolean returns;
|
||||
public MolangValue(){}
|
||||
public MolangValue(MolangParser context, IValue value) {
|
||||
super(context);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public MolangExpression addReturn() {
|
||||
this.returns = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double get() {
|
||||
return this.value.get();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return (this.returns ? "return " : "") + this.value.toString();
|
||||
}
|
||||
|
||||
public JsonElement toJson() {
|
||||
return (JsonElement)(this.value instanceof Constant ? new JsonPrimitive(this.value.get()) : super.toJson());
|
||||
}
|
||||
|
||||
public void writeExternal(ObjectOutput out) throws IOException {
|
||||
out.writeObject(value);
|
||||
out.writeBoolean(returns);
|
||||
}
|
||||
|
||||
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
|
||||
value = (IValue) in.readObject();
|
||||
returns = in.readBoolean();
|
||||
context = GeckoLibCache.getInstance().parser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.eliotlash.molang.functions;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.mclib.math.functions.classic.ACos;
|
||||
|
||||
public class AcosDegrees extends ACos
|
||||
{
|
||||
public AcosDegrees(IValue[] values, String name) throws Exception
|
||||
{
|
||||
super(values, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double get()
|
||||
{
|
||||
return super.get() / Math.PI * 180;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.eliotlash.molang.functions;
|
||||
|
||||
import com.eliotlash.mclib.math.IValue;
|
||||
import com.eliotlash.mclib.math.functions.classic.ASin;
|
||||
|
||||
public class AsinDegrees extends ASin
|
||||
{
|
||||
public AsinDegrees(IValue[] values, String name) throws Exception
|
||||
{
|
||||
super(values, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double get()
|
||||
{
|
||||
return super.get() / Math.PI * 180;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 368 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user