mirror of
https://github.com/xSquishyLiam/mc-GeyserModelEngine-plugin.git
synced 2025-12-19 14:59:19 +00:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b7f78c500b | ||
|
|
9d64d02f3d | ||
|
|
a109d21b76 | ||
|
|
be7b067889 | ||
|
|
76b857e8a4 | ||
|
|
1b759c78d6 | ||
|
|
223e4885b2 | ||
|
|
0b06963c1a | ||
|
|
d0c42c4e06 | ||
|
|
742351ec66 | ||
|
|
f82dd2b7f8 | ||
|
|
f93f49980c | ||
|
|
0c90fe4809 | ||
|
|
6892ffb519 | ||
|
|
af1984bef8 | ||
|
|
9be6efdc84 | ||
|
|
84f50af049 | ||
|
|
f93559c822 | ||
|
|
468757762f | ||
|
|
e7114faf84 | ||
|
|
63bf26d7a9 | ||
|
|
bdc75512d8 | ||
|
|
c5a34f1690 | ||
|
|
74432c2800 | ||
|
|
7f8b648685 | ||
|
|
f5f424ace2 | ||
|
|
a4fba7715d | ||
|
|
0176d86233 | ||
|
|
79f99ffebe | ||
|
|
ae3b67a733 | ||
|
|
8e36bf2829 | ||
|
|
804d2aac04 | ||
|
|
b6425ffa51 | ||
|
|
1c47fe83d2 | ||
|
|
7bbe66928c | ||
|
|
a26ea6e148 | ||
|
|
d1ef89088c | ||
|
|
c98e807827 | ||
|
|
35131c2d58 | ||
|
|
6651ae99f7 | ||
|
|
ca9a54ae71 | ||
|
|
865f5f567c | ||
|
|
b5d9d9b9ca | ||
|
|
31dac482bd | ||
|
|
b2bfa2977e | ||
|
|
84012a23b7 | ||
|
|
3943381b2c | ||
|
|
42d7ea506f | ||
|
|
e177c8af74 | ||
|
|
2c5dba8097 | ||
|
|
2a9fdec8b6 | ||
|
|
94df76b9a6 | ||
|
|
03f27514ef | ||
|
|
4679fa6f2b | ||
|
|
db99b2fe00 | ||
|
|
ffd72b0a56 | ||
|
|
e83caacd2f | ||
|
|
170e67e059 | ||
|
|
d150d7e324 | ||
|
|
db0367537e | ||
|
|
36ea0e5fa0 | ||
|
|
13c0b45d2a | ||
|
|
8f67ade51c | ||
|
|
d0fd719753 | ||
|
|
f4c5167ef5 | ||
|
|
dc4e39506d | ||
|
|
5fdf93db1e | ||
|
|
16e0dfcdfd | ||
|
|
b1969646e6 | ||
|
|
501eaaa37a | ||
|
|
f67ee6d9f8 | ||
|
|
3adb965697 | ||
|
|
4d75f0615c | ||
|
|
97e5bdefcd |
@@ -8,10 +8,10 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Setup JDK
|
||||
- name: Setup Java JDK
|
||||
@@ -19,25 +19,20 @@ jobs:
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'zulu'
|
||||
|
||||
- name: Restore Maven cache
|
||||
uses: skjolber/maven-cache-github-action@v1
|
||||
with:
|
||||
step: restore
|
||||
|
||||
|
||||
# Build
|
||||
- name: Build with Maven
|
||||
run: mvn package
|
||||
|
||||
- name: Save Maven cache
|
||||
uses: skjolber/maven-cache-github-action@v1
|
||||
with:
|
||||
step: save
|
||||
- name: Make gradlew executable
|
||||
run: chmod +x gradlew
|
||||
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
|
||||
- name: Auto release
|
||||
uses: "marvinpinto/action-automatic-releases@latest"
|
||||
with:
|
||||
repo_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
repo_token: "${{secrets.GITHUB_TOKEN}}"
|
||||
automatic_release_tag: latest
|
||||
prerelease: false
|
||||
files: |
|
||||
target/GeyserModelEngine*.jar
|
||||
paper/build/libs/GeyserModelEngine*.jar
|
||||
geyser/build/libs/GeyserModelEngine*.jar
|
||||
44
.gitignore
vendored
44
.gitignore
vendored
@@ -1,2 +1,42 @@
|
||||
# 项目排除路径
|
||||
/target/
|
||||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
#Tue May 27 16:38:57 BST 2025
|
||||
gradle.version=8.12
|
||||
Binary file not shown.
Binary file not shown.
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
4
.idea/encodings.xml
generated
4
.idea/encodings.xml
generated
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/paper/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/paper/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
||||
2
.idea/gradle.xml
generated
2
.idea/gradle.xml
generated
@@ -8,6 +8,8 @@
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
<option value="$PROJECT_DIR$/geyser" />
|
||||
<option value="$PROJECT_DIR$/paper" />
|
||||
</set>
|
||||
</option>
|
||||
</GradleProjectSettings>
|
||||
|
||||
126
.idea/workspace.xml
generated
126
.idea/workspace.xml
generated
@@ -4,15 +4,15 @@
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="ff2e9770-ec88-4715-adeb-b9dbda130e1a" name="Changes" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/commands/geysermodelenginecommands/GeyserModelEngineReloadCommand.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/re/imc/geysermodelengine/commands/geysermodelenginecommands/GeyserModelEngineReloadCommand.java" afterDir="false" />
|
||||
</list>
|
||||
<list default="true" id="ff2e9770-ec88-4715-adeb-b9dbda130e1a" name="Changes" comment="" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="DarkyenusTimeTracker">
|
||||
<option name="totalTimeSeconds" value="32226" />
|
||||
</component>
|
||||
<component name="ExternalProjectsData">
|
||||
<projectState path="$PROJECT_DIR$">
|
||||
<ProjectState />
|
||||
@@ -60,9 +60,13 @@
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="GradleScriptDefinitionsStorage" workingDir="$PROJECT_DIR$" gradleHome="C:\Users\xsqui\.gradle\wrapper\dists\gradle-9.2.0-bin\11i5gvueggl8a5cioxuftxrik\gradle-9.2.0" javaHome="C:\Program Files\Java\jdk-21" gradleVersion="9.2.0" />
|
||||
<component name="MavenRunner">
|
||||
<option name="delegateBuildToMaven" value="true" />
|
||||
</component>
|
||||
<component name="ProblemsViewState">
|
||||
<option name="selectedTabId" value="DEPENDENCY_CHECKER_PROBLEMS_TAB" />
|
||||
</component>
|
||||
<component name="ProjectColorInfo">{
|
||||
"associatedIndex": 8
|
||||
}</component>
|
||||
@@ -76,26 +80,130 @@
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"Gradle.Build GeyserModelEngine.executor": "Run",
|
||||
"Gradle.Download Sources.executor": "Run",
|
||||
"Gradle.GeyserModelEngine [buildDependents].executor": "Run",
|
||||
"Gradle.GeyserModelEngine [buildNeeded].executor": "Run",
|
||||
"Gradle.GeyserModelEngine [build].executor": "Run",
|
||||
"Gradle.GeyserModelEngine [clean].executor": "Run",
|
||||
"Gradle.GeyserModelEngine [jar].executor": "Run",
|
||||
"Maven.GeyserModelEngine [install...].executor": "Run",
|
||||
"Maven.GeyserModelEngine [install].executor": "Run",
|
||||
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"RunOnceActivity.TerminalTabsStorage.copyFrom.TerminalArrangementManager.252": "true",
|
||||
"RunOnceActivity.git.unshallow": "true",
|
||||
"git-widget-placeholder": "main",
|
||||
"last_opened_file_path": "D:/Coding/Forks/Minecraft/GeyserModelEngine",
|
||||
"ignore.virus.scanning.warn.message": "true",
|
||||
"kotlin-language-version-configured": "true",
|
||||
"last_opened_file_path": "D:/Coding/Minecraft/GeyserExtensionists/GeyserModelEngine",
|
||||
"project.structure.last.edited": "Project",
|
||||
"project.structure.proportion": "0.0",
|
||||
"project.structure.side.proportion": "0.2",
|
||||
"settings.editor.selected.configurable": "reference.settings.project.maven.runner"
|
||||
"settings.editor.selected.configurable": "reference.settingsdialog.project.gradle"
|
||||
}
|
||||
}</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine\geyser" />
|
||||
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine\paper" />
|
||||
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine\paper" />
|
||||
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine\.github\workflows" />
|
||||
<recent name="D:\Coding\Forks\Minecraft\GeyserModelEngine\libs" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<component name="RunManager" selected="Gradle.GeyserModelEngine [build]">
|
||||
<configuration name="GeyserModelEngine [buildDependents]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="buildDependents" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="GeyserModelEngine [buildNeeded]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="buildNeeded" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="GeyserModelEngine [build]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="build" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="GeyserModelEngine [clean]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="clean" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
<configuration name="GeyserModelEngine [jar]" type="GradleRunConfiguration" factoryName="Gradle" temporary="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
@@ -120,7 +228,11 @@
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Gradle.GeyserModelEngine [build]" />
|
||||
<item itemvalue="Gradle.GeyserModelEngine [jar]" />
|
||||
<item itemvalue="Gradle.GeyserModelEngine [clean]" />
|
||||
<item itemvalue="Gradle.GeyserModelEngine [buildNeeded]" />
|
||||
<item itemvalue="Gradle.GeyserModelEngine [buildDependents]" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
|
||||
19
README.md
19
README.md
@@ -20,27 +20,22 @@ Download the following plugins according to what server software you use.
|
||||
- Put `GeyserModelEngine` in the plugins folder (only Spigot or forks of Spigot supported)
|
||||
- Put either `geyserutils-spigot` in your plugins folder aswell (`geyserutils-velocity`/`geyserutils-bungeecord` in your Velocity/Bungeecord plugins folder if you use it)
|
||||
- Put `GeyserModelEnginePackGenerator` and `geyserutils-geyser` into `plugins/[Geyser-Folder]/extensions`
|
||||
- Inside `floodgate` set `send-floodgate-data` to `true` in your Velocity/Bungeecord folder and copy over the key.pem into your backend `floodgate` folders
|
||||
|
||||
Start the server to generate the relevant configuration files, and then shut down the server to convert any models.
|
||||
|
||||
# Convert Models
|
||||
This is old method to convert model:
|
||||
|
||||
`GeyserModelEnginePackGenerator` is capable of generating models all by itself. After generating it will also apply this pack automatically.
|
||||
|
||||
- First go to `plugins/[Geyser-Folder]/extensions/geysermodelenginepackgenerator/input/`
|
||||
- Create a folder in this directory with the ID of the model. (this is the same name as your model within ModelEngine 4.)
|
||||
- Firstly, install [packer plugin](https://github.com/GeyserExtensionists/GeyserModelEngineBlockbenchPacker) for your blockbench.
|
||||
|
||||
- Then, open your bbmodel, go `File -> Export -> Export GeyserModelEngine Model`, you will get a zip, just unzip it to `input` folder.
|
||||
|
||||
<img src="docsimg/example.jpg" width="500">
|
||||
|
||||
> Each model should have a separate model folder
|
||||
> Subfolders are supported if you want to categorize them
|
||||
|
||||
- Now use BlockBench and convert your model to a Bedrock Entity, this will allow you to export the Bedrock Geometry and Animations.
|
||||
- Put the geometry, animations and texture file in this folder you've made.
|
||||
|
||||
<img src="docsimg/example1.jpg" width="500">
|
||||
|
||||
- Restart the server or reload geyser to start generating the resource pack.
|
||||
- Go to `plugins/[Geyser-Folder]/extensions/geysermodelenginepackgenerator`, and you should see your pack generated!
|
||||
|
||||
@@ -49,12 +44,6 @@ This is old method to convert model:
|
||||
- Final step, reload Geyser or restart the server to load the resource pack.
|
||||
- Congratulations, you've completed this tutorial!
|
||||
|
||||
# Model Packer
|
||||
|
||||
This is new way to convert model
|
||||
- Firstly, install [packer plugin](https://github.com/GeyserExtensionists/GeyserModelEngineBlockbenchPacker) for your blockbench.
|
||||
- Then, open your bbmodel, go `File -> Export -> Export GeyserModelEngine Model`, you will get a zip, just unzip it to `input` folder.
|
||||
|
||||
# Tips
|
||||
|
||||
* Pay attention! The pack only regenerates when the number of models changes, you can technically speaking remove the generated_pack folder to force a reload aswell.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("io.github.goooler.shadow") version "8.1.7"
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
}
|
||||
|
||||
group = "re.imc"
|
||||
@@ -8,31 +8,10 @@ version = "1.0.0"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://central.sonatype.com/repository/maven-snapshots/")
|
||||
|
||||
maven("https://mvn.lumine.io/repository/maven-public/")
|
||||
|
||||
maven("https://repo.opencollab.dev/maven-releases/")
|
||||
maven("https://repo.opencollab.dev/maven-snapshots/")
|
||||
|
||||
maven("https://repo.codemc.io/repository/maven-public/")
|
||||
maven("https://repo.codemc.io/repository/maven-releases/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.7-R0.1-SNAPSHOT")
|
||||
|
||||
implementation("dev.jorel:commandapi-bukkit-shade-mojang-mapped:10.1.1")
|
||||
|
||||
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.4")
|
||||
|
||||
compileOnly(files("libs/geyserutils-spigot-1.0-SNAPSHOT.jar"))
|
||||
compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT")
|
||||
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.9.0-SNAPSHOT")
|
||||
|
||||
implementation("org.reflections:reflections:0.10.2")
|
||||
}
|
||||
|
||||
java {
|
||||
@@ -41,17 +20,4 @@ java {
|
||||
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
relocate("dev.jorel.commandapi", "re.imc.geysermodelengine.libs.commandapi")
|
||||
|
||||
relocate("com.github.retrooper", "re.imc.geysermodelengine.libs.com.github.retrooper.packetevents")
|
||||
relocate("io.github.retrooper", "re.imc.geysermodelengine.libs.io.github.retrooper.packetevents")
|
||||
|
||||
relocate("org.reflections", "re.imc.geysermodelengine.libs.reflections")
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1,8 +0,0 @@
|
||||
data-send-delay: 5
|
||||
entity-view-distance: 50
|
||||
join-send-delay: 20
|
||||
entity-position-update-period: 35
|
||||
model-entity-type: BAT # must be a living entity
|
||||
enable-part-visibility-models:
|
||||
- example
|
||||
debug: false
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
Manifest-Version: 1.0
|
||||
|
||||
35
geyser/build.gradle.kts
Normal file
35
geyser/build.gradle.kts
Normal file
@@ -0,0 +1,35 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
}
|
||||
|
||||
group = "me.zimzaza4"
|
||||
version = "1.0-SNAPSHOT"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
maven("https://repo.opencollab.dev/main/")
|
||||
|
||||
maven("https://maven.tomalbrc.de")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.geysermc.geyser:api:2.9.0-SNAPSHOT")
|
||||
|
||||
compileOnly(files("libs/geyserutils-geyser-1.0-SNAPSHOT.jar"))
|
||||
|
||||
implementation("org.spongepowered:configurate-yaml:4.2.0-GeyserMC-SNAPSHOT")
|
||||
implementation("com.google.code.gson:gson:2.13.1")
|
||||
implementation("de.tomalbrc:blockbench-import-library:1.7.0+1.21.9")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveFileName.set("${rootProject.name}Extension-${version}.jar")
|
||||
|
||||
relocate("org.spongepowered.configurate", "me.zimzaza4.geysermodelenginepackgenerator.libs.configurate")
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn("shadowJar")
|
||||
}
|
||||
BIN
geyser/libs/geyserutils-geyser-1.0-SNAPSHOT.jar
Normal file
BIN
geyser/libs/geyserutils-geyser-1.0-SNAPSHOT.jar
Normal file
Binary file not shown.
@@ -0,0 +1,71 @@
|
||||
package re.imc.geysermodelengineextension;
|
||||
|
||||
import org.geysermc.event.subscribe.Subscribe;
|
||||
import org.geysermc.geyser.api.command.Command;
|
||||
import org.geysermc.geyser.api.command.CommandSource;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent;
|
||||
import org.geysermc.geyser.api.extension.Extension;
|
||||
import org.geysermc.geyser.api.pack.PackCodec;
|
||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||
import re.imc.geysermodelengineextension.managers.ConfigManager;
|
||||
import re.imc.geysermodelengineextension.managers.resourcepack.ResourcePackManager;
|
||||
|
||||
public class GeyserModelEngineExtension implements Extension {
|
||||
|
||||
private static GeyserModelEngineExtension extension;
|
||||
|
||||
private ConfigManager configManager;
|
||||
|
||||
private ResourcePackManager resourcePackManager;
|
||||
|
||||
@Subscribe
|
||||
public void onLoad(GeyserPreInitializeEvent event) {
|
||||
extension = this;
|
||||
|
||||
loadManagers();
|
||||
|
||||
resourcePackManager.loadPack();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDefineCommand(GeyserDefineCommandsEvent event) {
|
||||
event.register(Command.builder(this)
|
||||
.name("reload")
|
||||
.source(CommandSource.class)
|
||||
.playerOnly(false)
|
||||
.description("GeyserModelPackGenerator Reload Command")
|
||||
.permission("geysermodelenginepackgenerator.commands.reload")
|
||||
.executor((source, command, args) -> {
|
||||
resourcePackManager.loadPack();
|
||||
source.sendMessage(configManager.getLang().getString("commands.geysermodelenginepackgenerator.reload.successfully-reloaded"));
|
||||
})
|
||||
.build());
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onPackLoad(GeyserDefineResourcePacksEvent event) {
|
||||
if (!configManager.getConfig().getBoolean("options.resource-pack.auto-load")) return;
|
||||
|
||||
ResourcePack resourcePack = ResourcePack.create(PackCodec.path(resourcePackManager.getGeneratedPackZipPath()));
|
||||
event.register(resourcePack);
|
||||
}
|
||||
|
||||
private void loadManagers() {
|
||||
this.configManager = new ConfigManager();
|
||||
this.resourcePackManager = new ResourcePackManager(this);
|
||||
}
|
||||
|
||||
public static GeyserModelEngineExtension getExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
public ResourcePackManager getResourcePackManager() {
|
||||
return resourcePackManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package re.imc.geysermodelengineextension.managers;
|
||||
|
||||
import re.imc.geysermodelengineextension.util.FileConfiguration;
|
||||
|
||||
public class ConfigManager {
|
||||
|
||||
private FileConfiguration config, lang;
|
||||
|
||||
public ConfigManager() {
|
||||
load();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
this.config = new FileConfiguration("config.yml");
|
||||
this.lang = new FileConfiguration("Lang/messages.yml");
|
||||
}
|
||||
|
||||
public FileConfiguration getConfig() {
|
||||
return config;
|
||||
}
|
||||
|
||||
public FileConfiguration getLang() {
|
||||
return lang;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,446 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonParser;
|
||||
import re.imc.geysermodelengineextension.GeyserModelEngineExtension;
|
||||
import re.imc.geysermodelengineextension.managers.resourcepack.generator.*;
|
||||
import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.TextureData;
|
||||
import re.imc.geysermodelengineextension.util.ZipUtil;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ResourcePackManager {
|
||||
|
||||
private final GeyserModelEngineExtension extension;
|
||||
|
||||
private final File inputFolder;
|
||||
private final File generatedPack;
|
||||
|
||||
private Path generatedPackZipPath;
|
||||
|
||||
private final HashMap<String, Entity> entityCache = new HashMap<>();
|
||||
private final HashMap<String, Animation> animationCache = new HashMap<>();
|
||||
private final HashMap<String, Geometry> geometryCache = new HashMap<>();
|
||||
private final HashMap<String, Map<String, TextureData>> textureCache = new HashMap<>();
|
||||
|
||||
private final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
public ResourcePackManager(GeyserModelEngineExtension extension) {
|
||||
this.extension = extension;
|
||||
|
||||
this.inputFolder = extension.dataFolder().resolve("input").toFile();
|
||||
this.inputFolder.mkdirs();
|
||||
|
||||
this.generatedPack = extension.dataFolder().resolve("generated_pack").toFile();
|
||||
}
|
||||
|
||||
public void loadPack() {
|
||||
generateResourcePack(inputFolder, generatedPack);
|
||||
|
||||
generatedPackZipPath = extension.dataFolder().resolve("generated_pack.zip");
|
||||
|
||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(generatedPackZipPath))) {
|
||||
ZipUtil.compressFolder(generatedPack, null, zipOutputStream);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
for (Entity entity : entityCache.values()) {
|
||||
entity.register(extension.getConfigManager().getConfig().getString("models.namespace"));
|
||||
}
|
||||
}
|
||||
|
||||
private void generateResourcePack(File inputFolder, File output) {
|
||||
generateFromFolder("", inputFolder, true);
|
||||
|
||||
File animationsFolder = new File(output, "animations");
|
||||
File entityFolder = new File(output, "entity");
|
||||
File modelsFolder = new File(output, "models/entity");
|
||||
File texturesFolder = new File(output, "textures/entity");
|
||||
File animationControllersFolder = new File(output, "animation_controllers");
|
||||
File renderControllersFolder = new File(output, "render_controllers");
|
||||
File materialsFolder = new File(output, "materials");
|
||||
|
||||
File manifestFile = new File(output, "manifest.json");
|
||||
|
||||
output.mkdirs();
|
||||
if (!manifestFile.exists()) {
|
||||
try {
|
||||
Files.writeString(manifestFile.toPath(), PackManifest.generate(), StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
animationsFolder.mkdirs();
|
||||
entityFolder.mkdirs();
|
||||
modelsFolder.mkdirs();
|
||||
texturesFolder.mkdirs();
|
||||
animationControllersFolder.mkdirs();
|
||||
renderControllersFolder.mkdirs();
|
||||
materialsFolder.mkdirs();
|
||||
|
||||
File materialFile = new File(materialsFolder, "entity.material");
|
||||
|
||||
if (!materialFile.exists()) {
|
||||
try {
|
||||
Files.writeString(materialFile.toPath(), Material.TEMPLATE, StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Animation> entry : animationCache.entrySet()) {
|
||||
Entity entity = entityCache.get(entry.getKey());
|
||||
Geometry geo = geometryCache.get(entry.getKey());
|
||||
|
||||
if (geo != null) entry.getValue().addHeadBind(geo);
|
||||
|
||||
Path path = animationsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".animation.json");
|
||||
Path pathController = animationControllersFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".animation_controllers.json");
|
||||
|
||||
pathController.toFile().getParentFile().mkdirs();
|
||||
path.toFile().getParentFile().mkdirs();
|
||||
|
||||
if (path.toFile().exists()) continue;
|
||||
|
||||
AnimationController controller = new AnimationController();
|
||||
controller.load(extension, entry.getValue(), entity);
|
||||
|
||||
try {
|
||||
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
||||
Files.writeString(pathController, controller.getJson().toString(), StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Geometry> entry : geometryCache.entrySet()) {
|
||||
entry.getValue().modify();
|
||||
Path path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".geo.json");
|
||||
path.toFile().getParentFile().mkdirs();
|
||||
String id = entry.getValue().getGeometryId();
|
||||
|
||||
Entity entity = entityCache.get(entry.getKey());
|
||||
if (entity != null) {
|
||||
ModelConfig modelConfig = entity.getModelConfig();
|
||||
if (!modelConfig.getPerTextureUvSize().isEmpty()) {
|
||||
for (Map.Entry<String, TextureData> textureEntry : entity.getTextureMap().entrySet()) {
|
||||
String name = textureEntry.getKey();
|
||||
|
||||
Integer[] size = modelConfig.getPerTextureUvSize().getOrDefault(name, new Integer[]{16, 16});
|
||||
String suffix = size[0] + "_" + size[1];
|
||||
entry.getValue().setTextureWidth(size[0]);
|
||||
entry.getValue().setTextureHeight(size[1]);
|
||||
path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + "_" + suffix + ".geo.json");
|
||||
|
||||
entry.getValue().setId(id + "_" + suffix);
|
||||
|
||||
if (path.toFile().exists()) continue;
|
||||
|
||||
try {
|
||||
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path.toFile().exists()) continue;
|
||||
|
||||
try {
|
||||
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Map<String, TextureData>> textures : textureCache.entrySet()) {
|
||||
for (Map.Entry<String, TextureData> entry : textures.getValue().entrySet()) {
|
||||
Path path = texturesFolder.toPath().resolve(entry.getValue().getPath() + textures.getKey() + "/" + entry.getKey() + ".png");
|
||||
path.toFile().getParentFile().mkdirs();
|
||||
|
||||
if (path.toFile().exists()) continue;
|
||||
|
||||
try {
|
||||
if (entry.getValue().getImage() != null) Files.write(path, entry.getValue().getImage());
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Entity> entry : entityCache.entrySet()) {
|
||||
Entity entity = entry.getValue();
|
||||
entity.modify(extension.getConfigManager().getConfig().getString("models.namespace"));
|
||||
|
||||
Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".entity.json");
|
||||
entityPath.toFile().getParentFile().mkdirs();
|
||||
|
||||
if (entityPath.toFile().exists()) continue;
|
||||
|
||||
try {
|
||||
Files.writeString(entityPath, entity.getJson().toString(), StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
// render controller part
|
||||
|
||||
String id = entity.getModelId();
|
||||
if (!geometryCache.containsKey(id)) continue;
|
||||
RenderController controller = new RenderController(id, geometryCache.get(id).getBones(), entity);
|
||||
entity.setRenderController(controller);
|
||||
Path renderPath = new File(renderControllersFolder, "controller.render." + id + ".json").toPath();
|
||||
if (renderPath.toFile().exists()) continue;
|
||||
|
||||
try {
|
||||
Files.writeString(renderPath, controller.generate(extension.getConfigManager().getConfig().getString("models.namespace")), StandardCharsets.UTF_8);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateFromFolder(String currentPath, File folder, boolean root) {
|
||||
if (folder.listFiles() == null) return;
|
||||
|
||||
String modelId = root ? "" : folder.getName().toLowerCase();
|
||||
|
||||
Entity entity = new Entity(modelId);
|
||||
ModelConfig modelConfig = new ModelConfig();
|
||||
boolean shouldOverrideConfig = false;
|
||||
File textureConfigFile = new File(folder, "config.json");
|
||||
|
||||
if (textureConfigFile.exists()) {
|
||||
try {
|
||||
modelConfig = GSON.fromJson(Files.readString(textureConfigFile.toPath()), ModelConfig.class);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
boolean canAdd = false;
|
||||
for (File file : folder.listFiles()) {
|
||||
if (file.isDirectory()) generateFromFolder(currentPath + (root ? "" : folder.getName() + "/"), file, false);
|
||||
|
||||
if (file.getName().endsWith(".zip")) {
|
||||
try {
|
||||
generateFromZip(currentPath, file.getName().replace(".zip", "").toLowerCase(Locale.ROOT), new ZipFile(file));
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (entityCache.containsKey(modelId)) continue;
|
||||
|
||||
if (file.getName().endsWith(".png")) {
|
||||
String textureName = file.getName().replace(".png", "");
|
||||
Set<String> bindingBones = new HashSet<>();
|
||||
bindingBones.add("*");
|
||||
if (modelConfig.getBingingBones().containsKey(textureName)) bindingBones = modelConfig.getBingingBones().get(textureName);
|
||||
|
||||
Map<String, TextureData> map = textureCache.computeIfAbsent(modelId, s -> new HashMap<>());
|
||||
try {
|
||||
map.put(textureName, new TextureData(modelId, currentPath, bindingBones, Files.readAllBytes(file.toPath())));
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
entity.setTextureMap(map);
|
||||
if (modelConfig.getBingingBones().isEmpty()) {
|
||||
modelConfig.getBingingBones().put(textureName, Set.of("*"));
|
||||
shouldOverrideConfig = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (file.getName().endsWith(".json")) {
|
||||
try {
|
||||
String json = Files.readString(file.toPath());
|
||||
if (isAnimationFile(json)) {
|
||||
Animation animation = new Animation();
|
||||
animation.setPath(currentPath);
|
||||
animation.setModelId(modelId);
|
||||
|
||||
animation.load(json);
|
||||
animationCache.put(modelId, animation);
|
||||
entity.setAnimation(animation);
|
||||
}
|
||||
|
||||
if (isGeometryFile(json)) {
|
||||
Geometry geometry = new Geometry();
|
||||
geometry.load(json);
|
||||
geometry.setPath(currentPath);
|
||||
geometry.setModelId(modelId);
|
||||
geometryCache.put(modelId, geometry);
|
||||
entity.setGeometry(geometry);
|
||||
canAdd = true;
|
||||
}
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canAdd) {
|
||||
// old config
|
||||
File oldConfig = new File(folder, "config.properties");
|
||||
Properties old = new Properties();
|
||||
try {
|
||||
if (oldConfig.exists()) {
|
||||
old.load(new FileReader(oldConfig));
|
||||
modelConfig.setMaterial(old.getProperty("material", "entity_alphatest_change_color"));
|
||||
modelConfig.setEnableBlendTransition(Boolean.parseBoolean(old.getProperty("blend-transition", "true")));
|
||||
modelConfig.setEnableHeadRotation(Boolean.parseBoolean(old.getProperty("head-rotation", "true")));
|
||||
shouldOverrideConfig = true;
|
||||
oldConfig.delete();
|
||||
}
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
if (shouldOverrideConfig) {
|
||||
try {
|
||||
Files.writeString(textureConfigFile.toPath(), GSON.toJson(modelConfig));
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
entity.setModelConfig(modelConfig);
|
||||
entity.setPath(currentPath);
|
||||
entityCache.put(modelId, entity);
|
||||
}
|
||||
}
|
||||
|
||||
public void generateFromZip(String currentPath, String modelId, ZipFile zip) {
|
||||
Entity entity = new Entity(modelId);
|
||||
if (entityCache.containsKey(modelId)) return;
|
||||
|
||||
ModelConfig modelConfig = new ModelConfig();
|
||||
ZipEntry textureConfigFile = null;
|
||||
|
||||
for (Iterator<? extends ZipEntry> it = zip.entries().asIterator(); it.hasNext(); ) {
|
||||
ZipEntry entry = it.next();
|
||||
if (entry.getName().endsWith("config.json")) {
|
||||
textureConfigFile = entry;
|
||||
}
|
||||
}
|
||||
|
||||
if (textureConfigFile != null) {
|
||||
try {
|
||||
modelConfig = GSON.fromJson(new InputStreamReader(zip.getInputStream(textureConfigFile)), ModelConfig.class);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
boolean canAdd = false;
|
||||
for (Iterator<? extends ZipEntry> it = zip.entries().asIterator(); it.hasNext(); ) {
|
||||
ZipEntry e = it.next();
|
||||
if (e.getName().endsWith(".png")) {
|
||||
String[] path = e.getName().split("/");
|
||||
String textureName = path[path.length - 1].replace(".png", "");
|
||||
Set<String> bindingBones = new HashSet<>();
|
||||
bindingBones.add("*");
|
||||
|
||||
if (modelConfig.getBingingBones().containsKey(textureName)) {
|
||||
bindingBones = modelConfig.getBingingBones().get(textureName);
|
||||
}
|
||||
|
||||
Map<String, TextureData> map = textureCache.computeIfAbsent(modelId, s -> new HashMap<>());
|
||||
try {
|
||||
map.put(textureName, new TextureData(modelId, currentPath, bindingBones, zip.getInputStream(e).readAllBytes()));
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
entity.setTextureMap(map);
|
||||
if (modelConfig.getBingingBones().isEmpty()) modelConfig.getBingingBones().put(textureName, Set.of("*"));
|
||||
}
|
||||
|
||||
if (e.getName().endsWith(".json")) {
|
||||
try {
|
||||
InputStream stream = zip.getInputStream(e);
|
||||
String json = new String(stream.readAllBytes());
|
||||
if (isAnimationFile(json)) {
|
||||
Animation animation = new Animation();
|
||||
animation.setPath(currentPath);
|
||||
animation.setModelId(modelId);
|
||||
|
||||
animation.load(json);
|
||||
animationCache.put(modelId, animation);
|
||||
entity.setAnimation(animation);
|
||||
}
|
||||
|
||||
if (isGeometryFile(json)) {
|
||||
Geometry geometry = new Geometry();
|
||||
geometry.load(json);
|
||||
geometry.setPath(currentPath);
|
||||
geometry.setModelId(modelId);
|
||||
geometryCache.put(modelId, geometry);
|
||||
entity.setGeometry(geometry);
|
||||
canAdd = true;
|
||||
}
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canAdd) {
|
||||
entity.setModelConfig(modelConfig);
|
||||
entity.setPath(currentPath);
|
||||
entityCache.put(modelId, entity);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGeometryFile(String json) {
|
||||
try {
|
||||
return JsonParser.parseString(json).getAsJsonObject().has("minecraft:geometry");
|
||||
} catch (Throwable ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isAnimationFile(String json) {
|
||||
try {
|
||||
return JsonParser.parseString(json).getAsJsonObject().has("animations");
|
||||
} catch (Throwable ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public File getInputFolder() {
|
||||
return inputFolder;
|
||||
}
|
||||
|
||||
public Path getGeneratedPackZipPath() {
|
||||
return generatedPackZipPath;
|
||||
}
|
||||
|
||||
public HashMap<String, Entity> getEntityCache() {
|
||||
return entityCache;
|
||||
}
|
||||
|
||||
public HashMap<String, Animation> getAnimationCache() {
|
||||
return animationCache;
|
||||
}
|
||||
|
||||
public HashMap<String, Geometry> getGeometryCache() {
|
||||
return geometryCache;
|
||||
}
|
||||
|
||||
public HashMap<String, Map<String, TextureData>> getTextureCache() {
|
||||
return textureCache;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import re.imc.geysermodelengineextension.GeyserModelEngineExtension;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Animation {
|
||||
|
||||
private String modelId;
|
||||
private JsonObject json;
|
||||
private Set<String> animationIds = new HashSet<>();
|
||||
|
||||
private String path;
|
||||
|
||||
public static final String HEAD_TEMPLATE = """
|
||||
{
|
||||
"relative_to" : {
|
||||
"rotation" : "entity"
|
||||
},
|
||||
"rotation" : [ "query.target_x_rotation - this", "query.target_y_rotation - this", 0.0 ]
|
||||
}
|
||||
""";
|
||||
|
||||
public void load(String string) {
|
||||
this.json = JsonParser.parseString(string).getAsJsonObject();
|
||||
JsonObject newAnimations = new JsonObject();
|
||||
|
||||
for (Map.Entry<String, JsonElement> element : json.get("animations").getAsJsonObject().entrySet()) {
|
||||
animationIds.add(element.getKey());
|
||||
JsonObject animation = element.getValue().getAsJsonObject();
|
||||
|
||||
if (animation.has("override_previous_animation")) {
|
||||
if (animation.get("override_previous_animation").getAsBoolean()) {
|
||||
if (!animation.has("loop")) {
|
||||
animation.addProperty("loop", "hold_on_last_frame");
|
||||
// play once but override must use this to avoid strange anim
|
||||
}
|
||||
}
|
||||
|
||||
animation.remove("override_previous_animation");
|
||||
}
|
||||
|
||||
if (animation.has("loop")) {
|
||||
if (animation.get("loop").getAsJsonPrimitive().isString()) {
|
||||
if (animation.get("loop").getAsString().equals("hold_on_last_frame")) {
|
||||
if (!animation.has("bones")) {
|
||||
continue;
|
||||
}
|
||||
for (Map.Entry<String, JsonElement> bone : animation.get("bones").getAsJsonObject().entrySet()) {
|
||||
|
||||
for (Map.Entry<String, JsonElement> anim : bone.getValue().getAsJsonObject().entrySet()) {
|
||||
float max = -1;
|
||||
JsonObject end = null;
|
||||
if (!anim.getValue().isJsonObject()) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
for (Map.Entry<String, JsonElement> timeline : anim.getValue().getAsJsonObject().entrySet()) {
|
||||
float time = Float.parseFloat(timeline.getKey());
|
||||
if (time > max) {
|
||||
max = time;
|
||||
if (timeline.getValue().isJsonObject()) {
|
||||
end = timeline.getValue().getAsJsonObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
if (end != null && end.has("lerp_mode") && end.get("lerp_mode").getAsString().equals("catmullrom")) {
|
||||
end.addProperty("lerp_mode", "linear");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newAnimations.add("animation." + modelId + "." + element.getKey().replace(" ", "_"), element.getValue());
|
||||
}
|
||||
|
||||
json.add("animations", newAnimations);
|
||||
}
|
||||
|
||||
public void addHeadBind(Geometry geometry) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.addProperty("loop", true);
|
||||
JsonObject bones = new JsonObject();
|
||||
JsonArray array = geometry.getInternal().get("bones").getAsJsonArray();
|
||||
|
||||
int i = 0;
|
||||
|
||||
for (JsonElement element : array) {
|
||||
if (element.isJsonObject()) {
|
||||
String name = element.getAsJsonObject().get("name").getAsString();
|
||||
|
||||
String parent = "";
|
||||
if (element.getAsJsonObject().has("parent")) parent = element.getAsJsonObject().get("parent").getAsString();
|
||||
if (parent.startsWith("h_") || parent.startsWith("hi_")) continue;
|
||||
|
||||
if (name.startsWith("h_") || name.startsWith("hi_")) {
|
||||
bones.add(name, JsonParser.parseString(HEAD_TEMPLATE));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 0) return;
|
||||
|
||||
GeyserModelEngineExtension.getExtension().getResourcePackManager().getEntityCache().get(modelId).setHasHeadAnimation(true);
|
||||
|
||||
object.add("bones", bones);
|
||||
json.get("animations").getAsJsonObject().add("animation." + modelId + ".look_at_target", object);
|
||||
}
|
||||
|
||||
public void setModelId(String modelId) {
|
||||
this.modelId = modelId;
|
||||
}
|
||||
|
||||
public void setJson(JsonObject json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public void setAnimationIds(Set<String> animationIds) {
|
||||
this.animationIds = animationIds;
|
||||
}
|
||||
|
||||
public String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public JsonObject getJson() {
|
||||
return json;
|
||||
}
|
||||
|
||||
public Set<String> getAnimationIds() {
|
||||
return animationIds;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import re.imc.geysermodelengineextension.GeyserModelEngineExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class AnimationController {
|
||||
|
||||
private JsonObject json;
|
||||
private Entity entity;
|
||||
|
||||
public static final String CONTROLLER_TEMPLATE =
|
||||
"""
|
||||
{
|
||||
"initial_state": "stop",
|
||||
"states": {
|
||||
"play": {
|
||||
"animations": [
|
||||
"%anim%"
|
||||
],
|
||||
"blend_transition": 0.1,
|
||||
"transitions": [{ "stop": "%query% == 0"}]
|
||||
},
|
||||
"stop": {
|
||||
"blend_transition": 0.1,
|
||||
"transitions": [{ "play": "%query% != 0"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
public void load(GeyserModelEngineExtension extension, Animation animation, Entity entity) {
|
||||
JsonObject root = new JsonObject();
|
||||
json = root;
|
||||
root.addProperty("format_version", "1.10.0");
|
||||
|
||||
JsonObject animationControllers = new JsonObject();
|
||||
root.add("animation_controllers", animationControllers);
|
||||
|
||||
List<String> sorted = new ArrayList<>(animation.getAnimationIds());
|
||||
int i = 0;
|
||||
|
||||
Collections.sort(sorted);
|
||||
for (String id : sorted) {
|
||||
id = id.replace(" ", "_");
|
||||
int n = (int) Math.pow(2, (i % 24));
|
||||
|
||||
JsonObject controller = JsonParser.parseString(CONTROLLER_TEMPLATE.replace("%anim%", id).replace("%query%", "math.mod(math.floor(query.property('" + extension.getConfigManager().getConfig().getString("models.namespace") + ":anim" + i / 24 + "') / " + n + "), 2)")).getAsJsonObject();
|
||||
animationControllers.add("controller.animation." + animation.getModelId() + "." + id, controller);
|
||||
i++;
|
||||
if (entity != null) {
|
||||
boolean blend = entity.getModelConfig().isEnableBlendTransition();
|
||||
|
||||
if (!blend) {
|
||||
for (Map.Entry<String, JsonElement> states : controller.get("states").getAsJsonObject().entrySet()) {
|
||||
states.getValue().getAsJsonObject().remove("blend_transition");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setJson(JsonObject json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public void setEntity(Entity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public JsonObject getJson() {
|
||||
return json;
|
||||
}
|
||||
|
||||
public Entity getEntity() {
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import me.zimzaza4.geyserutils.geyser.GeyserUtils;
|
||||
import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.TextureData;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Entity {
|
||||
|
||||
public static final Set<String> REGISTERED_ENTITIES = new HashSet<>();
|
||||
|
||||
private String modelId;
|
||||
private JsonObject json;
|
||||
private boolean hasHeadAnimation = false;
|
||||
private Animation animation;
|
||||
private Geometry geometry;
|
||||
private RenderController renderController;
|
||||
private String path;
|
||||
private Map<String, TextureData> textureMap = new HashMap<>();
|
||||
private ModelConfig modelConfig;
|
||||
|
||||
public static final String TEMPLATE = """
|
||||
{
|
||||
"format_version": "1.10.0",
|
||||
"minecraft:client_entity": {
|
||||
"description": {
|
||||
"identifier": "%namespace%:%entity_id%",
|
||||
"materials": {
|
||||
"default": "%material%",
|
||||
"anim": "entity_alphatest_anim_change_color_one_sided"
|
||||
},
|
||||
"textures": {
|
||||
},
|
||||
"geometry": {
|
||||
|
||||
},
|
||||
"animations": {
|
||||
"look_at_target": "%look_at_target%"
|
||||
},
|
||||
"scripts": {
|
||||
"animate": [
|
||||
"look_at_target"
|
||||
]
|
||||
},
|
||||
"render_controllers": [
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
|
||||
public Entity(String modelId) {
|
||||
this.modelId = modelId;
|
||||
}
|
||||
|
||||
public void modify(String namespace) {
|
||||
this.json = JsonParser.parseString(TEMPLATE.replace("%namespace%", namespace)
|
||||
.replace("%entity_id%", modelId)
|
||||
.replace("%geometry%", "geometry.meg_" + modelId)
|
||||
.replace("%texture%", "textures/entity/" + path + modelId)
|
||||
.replace("%look_at_target%", modelConfig.isEnableHeadRotation() ? "animation." + modelId + ".look_at_target" : "animation.none")
|
||||
.replace("%material%", modelConfig.getMaterial())).getAsJsonObject();
|
||||
|
||||
JsonObject description = json.get("minecraft:client_entity").getAsJsonObject().get("description").getAsJsonObject();
|
||||
JsonObject jsonAnimations = description.get("animations").getAsJsonObject();
|
||||
JsonObject jsonTextures = description.get("textures").getAsJsonObject();
|
||||
JsonObject jsonGeometry = description.get("geometry").getAsJsonObject();
|
||||
JsonObject jsonMaterials = description.get("materials").getAsJsonObject();
|
||||
|
||||
JsonArray jsonRenderControllers = description.get("render_controllers").getAsJsonArray();
|
||||
|
||||
Map<String, String> materials = modelConfig.getTextureMaterials();
|
||||
materials.forEach(jsonMaterials::addProperty);
|
||||
|
||||
if (modelConfig.getPerTextureUvSize().isEmpty()) {
|
||||
jsonGeometry.addProperty("default", "geometry.meg_" + modelId);
|
||||
jsonTextures.addProperty("default", "textures/entity/" + path + modelId + "/" + textureMap.keySet().stream().findFirst().orElse("def"));
|
||||
}
|
||||
|
||||
for (String name : textureMap.keySet()) {
|
||||
if (name.endsWith("_e")) continue;
|
||||
|
||||
if (modelConfig.getPerTextureUvSize().containsKey(name)) {
|
||||
Integer[] size = modelConfig.getPerTextureUvSize().getOrDefault(name, new Integer[]{16, 16});
|
||||
String suffix = size[0] + "_" + size[1];
|
||||
|
||||
jsonGeometry.addProperty("t_" + suffix, "geometry.meg_" + modelId + "_" + suffix);
|
||||
jsonTextures.addProperty(name, "textures/entity/" + path + modelId + "/" + name);
|
||||
|
||||
}
|
||||
|
||||
jsonRenderControllers.add("controller.render." + modelId + "_" + name);
|
||||
}
|
||||
|
||||
JsonArray animate = description.get("scripts").getAsJsonObject().get("animate").getAsJsonArray();
|
||||
|
||||
if (animation != null) {
|
||||
for (String animation : animation.getAnimationIds()) {
|
||||
animation = animation.replace(" ", "_");
|
||||
String controller = "controller.animation." + modelId + "." + animation;
|
||||
animate.add(animation + "_control");
|
||||
jsonAnimations.addProperty(animation, "animation." + modelId + "." + animation);
|
||||
jsonAnimations.addProperty(animation + "_control", controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void register(String namespace) {
|
||||
String id = namespace + ":" + modelId;
|
||||
|
||||
boolean registered = REGISTERED_ENTITIES.contains(id);
|
||||
if (registered) return;
|
||||
|
||||
REGISTERED_ENTITIES.add(id);
|
||||
GeyserUtils.addCustomEntity(id);
|
||||
if (geometry == null) return;
|
||||
|
||||
if (!modelConfig.isDisablePartVisibility()) {
|
||||
for (int i = 0; i < Math.ceil(geometry.getBones().size() / 24f); i++) {
|
||||
GeyserUtils.addProperty(id, namespace + ":" + "bone" + i, Integer.class);
|
||||
}
|
||||
}
|
||||
|
||||
if (animation != null) {
|
||||
for (int i = 0; i < Math.ceil(animation.getAnimationIds().size() / 24f); i++) {
|
||||
GeyserUtils.addProperty(id, namespace + ":" + "anim" + i, Integer.class);
|
||||
}
|
||||
}
|
||||
|
||||
GeyserUtils.registerProperties(id);
|
||||
}
|
||||
|
||||
public void setModelId(String modelId) {
|
||||
this.modelId = modelId;
|
||||
}
|
||||
|
||||
public void setJson(JsonObject json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public void setHasHeadAnimation(boolean hasHeadAnimation) {
|
||||
this.hasHeadAnimation = hasHeadAnimation;
|
||||
}
|
||||
|
||||
public void setAnimation(Animation animation) {
|
||||
this.animation = animation;
|
||||
}
|
||||
|
||||
public void setGeometry(Geometry geometry) {
|
||||
this.geometry = geometry;
|
||||
}
|
||||
|
||||
public void setRenderController(RenderController renderController) {
|
||||
this.renderController = renderController;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public void setTextureMap(Map<String, TextureData> textureMap) {
|
||||
this.textureMap = textureMap;
|
||||
}
|
||||
|
||||
public void setModelConfig(ModelConfig modelConfig) {
|
||||
this.modelConfig = modelConfig;
|
||||
}
|
||||
|
||||
public String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
public JsonObject getJson() {
|
||||
return json;
|
||||
}
|
||||
|
||||
public boolean isHasHeadAnimation() {
|
||||
return hasHeadAnimation;
|
||||
}
|
||||
|
||||
public Animation getAnimation() {
|
||||
return animation;
|
||||
}
|
||||
|
||||
public Geometry getGeometry() {
|
||||
return geometry;
|
||||
}
|
||||
|
||||
public RenderController getRenderController() {
|
||||
return renderController;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Map<String, TextureData> getTextureMap() {
|
||||
return textureMap;
|
||||
}
|
||||
|
||||
public ModelConfig getModelConfig() {
|
||||
return modelConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import com.google.gson.*;
|
||||
import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.BoneData;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Geometry {
|
||||
|
||||
private String modelId;
|
||||
private String geometryId;
|
||||
private JsonObject json;
|
||||
private final Map<String, BoneData> bones = new HashMap<>();
|
||||
|
||||
private String path;
|
||||
|
||||
public void load(String json) {
|
||||
this.json = JsonParser.parseString(json).getAsJsonObject();
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
geometryId = id;
|
||||
getInternal().get("description").getAsJsonObject().addProperty("identifier", id);
|
||||
}
|
||||
|
||||
public void setTextureWidth(int w) {
|
||||
getInternal().get("description").getAsJsonObject().addProperty("texture_width", w);
|
||||
}
|
||||
|
||||
public void setTextureHeight(int h) {
|
||||
getInternal().get("description").getAsJsonObject().addProperty("texture_height", h);
|
||||
}
|
||||
|
||||
public JsonObject getInternal() {
|
||||
return json.get("minecraft:geometry").getAsJsonArray().get(0).getAsJsonObject();
|
||||
}
|
||||
|
||||
public void modify() {
|
||||
JsonArray array = getInternal().get("bones").getAsJsonArray();
|
||||
Iterator<JsonElement> iterator = array.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
JsonElement element = iterator.next();
|
||||
if (element.isJsonObject()) {
|
||||
String name = element.getAsJsonObject().get("name").getAsString().toLowerCase(Locale.ROOT);
|
||||
|
||||
String parent = element.getAsJsonObject().has("parent") ? element.getAsJsonObject().get("parent").getAsString().toLowerCase() : null;
|
||||
element.getAsJsonObject().remove("name");
|
||||
element.getAsJsonObject().addProperty("name", name);
|
||||
|
||||
if (name.equals("hitbox") || name.equals("shadow") || name.equals("mount") || name.startsWith("b_") || name.startsWith("ob_")) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
bones.put(name, new BoneData(name, parent, new HashSet<>(), new HashSet<>()));
|
||||
}
|
||||
}
|
||||
|
||||
for (BoneData bone : bones.values()) {
|
||||
if (bone.getParent() != null) {
|
||||
BoneData parent = bones.get(bone.getParent());
|
||||
if (parent != null) {
|
||||
parent.getChildren().add(bone);
|
||||
addAllChildren(parent, bone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
setId("geometry.meg_" + modelId);
|
||||
}
|
||||
|
||||
public void addAllChildren(BoneData p, BoneData c) {
|
||||
p.getAllChildren().add(c);
|
||||
BoneData parent = bones.get(p.getParent());
|
||||
if (parent != null) {
|
||||
addAllChildren(parent, c);
|
||||
}
|
||||
}
|
||||
|
||||
public void setModelId(String modelId) {
|
||||
this.modelId = modelId;
|
||||
}
|
||||
|
||||
public void setGeometryId(String geometryId) {
|
||||
this.geometryId = geometryId;
|
||||
}
|
||||
|
||||
public void setJson(JsonObject json) {
|
||||
this.json = json;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
public String getGeometryId() {
|
||||
return geometryId;
|
||||
}
|
||||
|
||||
public JsonObject getJson() {
|
||||
return json;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Map<String, BoneData> getBones() {
|
||||
return bones;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
public class Material {
|
||||
|
||||
public static final String TEMPLATE = """
|
||||
{
|
||||
"materials":{
|
||||
"version":"1.0.0",
|
||||
"entity_alphatest_anim_change_color:entity_alphatest_change_color":{
|
||||
"+defines":[
|
||||
"USE_UV_ANIM"
|
||||
]
|
||||
},
|
||||
"entity_change_color_one_sided:entity": {
|
||||
"+defines": [
|
||||
"USE_OVERLAY",
|
||||
"USE_COLOR_MASK"
|
||||
]
|
||||
},
|
||||
"entity_alphatest_change_color_one_sided:entity_change_color_one_sided": {
|
||||
"+defines": [ "ALPHA_TEST" ],
|
||||
"+samplerStates": [
|
||||
{
|
||||
"samplerIndex": 1,
|
||||
"textureWrap": "Repeat"
|
||||
}
|
||||
],
|
||||
"msaaSupport": "Both"
|
||||
},
|
||||
"entity_alphatest_anim_change_color_one_sided:entity_alphatest_change_color_one_sided":{
|
||||
"+defines":[
|
||||
"USE_UV_ANIM"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
""";
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@ToString
|
||||
public class ModelConfig {
|
||||
|
||||
@SerializedName("head_rotation")
|
||||
boolean enableHeadRotation = true;
|
||||
@SerializedName("material")
|
||||
String material = "entity_alphatest_change_color_one_sided";
|
||||
@SerializedName("blend_transition")
|
||||
boolean enableBlendTransition = true;
|
||||
@SerializedName("binding_bones")
|
||||
Map<String, Set<String>> bingingBones = new HashMap<>();
|
||||
@SerializedName("anim_textures")
|
||||
Map<String, AnimTextureOptions> animTextures = new HashMap<>();
|
||||
@SerializedName("texture_materials")
|
||||
Map<String, String> textureMaterials = new HashMap<>();
|
||||
@SerializedName("per_texture_uv_size")
|
||||
Map<String, Integer[]> perTextureUvSize;
|
||||
@SerializedName("disable_part_visibility")
|
||||
boolean disablePartVisibility = true;
|
||||
|
||||
public void setEnableHeadRotation(boolean enableHeadRotation) {
|
||||
this.enableHeadRotation = enableHeadRotation;
|
||||
}
|
||||
|
||||
public void setMaterial(String material) {
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
public void setEnableBlendTransition(boolean enableBlendTransition) {
|
||||
this.enableBlendTransition = enableBlendTransition;
|
||||
}
|
||||
|
||||
public void setBingingBones(Map<String, Set<String>> bingingBones) {
|
||||
this.bingingBones = bingingBones;
|
||||
}
|
||||
|
||||
public void setAnimTextures(Map<String, AnimTextureOptions> animTextures) {
|
||||
this.animTextures = animTextures;
|
||||
}
|
||||
|
||||
public void setTextureMaterials(Map<String, String> textureMaterials) {
|
||||
this.textureMaterials = textureMaterials;
|
||||
}
|
||||
|
||||
public void setPerTextureUvSize(Map<String, Integer[]> perTextureUvSize) {
|
||||
this.perTextureUvSize = perTextureUvSize;
|
||||
}
|
||||
|
||||
public void setDisablePartVisibility(boolean disablePartVisibility) {
|
||||
this.disablePartVisibility = disablePartVisibility;
|
||||
}
|
||||
|
||||
public Map<String, String> getTextureMaterials() {
|
||||
return textureMaterials != null ? textureMaterials : Map.of();
|
||||
}
|
||||
|
||||
public Map<String, Integer[]> getPerTextureUvSize() {
|
||||
return perTextureUvSize != null ? perTextureUvSize : Map.of();
|
||||
}
|
||||
|
||||
public boolean isEnableHeadRotation() {
|
||||
return enableHeadRotation;
|
||||
}
|
||||
|
||||
public String getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public boolean isEnableBlendTransition() {
|
||||
return enableBlendTransition;
|
||||
}
|
||||
|
||||
public Map<String, Set<String>> getBingingBones() {
|
||||
return bingingBones;
|
||||
}
|
||||
|
||||
public Map<String, AnimTextureOptions> getAnimTextures() {
|
||||
return animTextures;
|
||||
}
|
||||
|
||||
public boolean isDisablePartVisibility() {
|
||||
return disablePartVisibility;
|
||||
}
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public static class AnimTextureOptions {
|
||||
float fps;
|
||||
int frames;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class PackManifest {
|
||||
|
||||
public static final String TEMPLATE = """
|
||||
{
|
||||
"format_version": 2,
|
||||
"header": {
|
||||
"name": "GeyserModelEngine",
|
||||
"description": "GeyserModelEngine For Geyser",
|
||||
"uuid": "%uuid-1%",
|
||||
"version": [0, 0, 1],
|
||||
"min_engine_version": [1, 21, 100]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "resources",
|
||||
"description": "GeyserModelEngine",
|
||||
"uuid": "%uuid-2%",
|
||||
"version": [0, 0, 1]
|
||||
}
|
||||
]
|
||||
}
|
||||
""";
|
||||
|
||||
public static String generate() {
|
||||
return TEMPLATE.replace("%uuid-1%", UUID.randomUUID().toString())
|
||||
.replace("%uuid-2%", UUID.randomUUID().toString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.BoneData;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class RenderController {
|
||||
|
||||
public static final Set<String> NEED_REMOVE_WHEN_SORT = Set.of("pbody_", "plarm_", "prarm_", "plleg_", "prleg_", "phead_", "p_");
|
||||
|
||||
private final String modelId;
|
||||
private final Map<String, BoneData> bones;
|
||||
private final Entity entity;
|
||||
|
||||
public RenderController(String modelId, Map<String, BoneData> bones, Entity entity) {
|
||||
this.modelId = modelId;
|
||||
this.bones = bones;
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
// look, I'm fine with your other code and stuff, but I ain't using templates for JSON lmao
|
||||
public String generate(String namespace) {
|
||||
List<String> se = new ArrayList<>(bones.keySet());
|
||||
Collections.sort(se);
|
||||
JsonObject root = new JsonObject();
|
||||
root.addProperty("format_version", "1.8.0");
|
||||
|
||||
JsonObject renderControllers = new JsonObject();
|
||||
root.add("render_controllers", renderControllers);
|
||||
|
||||
Set<BoneData> processedBones = new HashSet<>();
|
||||
boolean singleTexture = entity.getTextureMap().size() == 1 && entity.getModelConfig().getPerTextureUvSize().isEmpty();
|
||||
for (String key : entity.getTextureMap().keySet()) {
|
||||
if (key.endsWith("_e")) continue;
|
||||
|
||||
// Texture texture = entity.textureMap.get(key);
|
||||
Set<String> uvBonesId = entity.getModelConfig().getBingingBones().get(key);
|
||||
|
||||
if (uvBonesId == null) {
|
||||
if (!singleTexture) {
|
||||
continue;
|
||||
} else {
|
||||
uvBonesId = new HashSet<>();
|
||||
uvBonesId.add("*");
|
||||
}
|
||||
}
|
||||
ModelConfig.AnimTextureOptions anim = entity.getModelConfig().getAnimTextures().get(key);
|
||||
|
||||
JsonObject controller = new JsonObject();
|
||||
|
||||
renderControllers.add("controller.render." + modelId + "_" + key, controller);
|
||||
|
||||
if (!entity.getModelConfig().getPerTextureUvSize().isEmpty()) {
|
||||
Integer[] size = entity.getModelConfig().getPerTextureUvSize().getOrDefault(key, new Integer[]{16, 16});
|
||||
String suffix = "t_" + size[0] + "_" + size[1];
|
||||
controller.addProperty("geometry", "Geometry." + suffix);
|
||||
} else {
|
||||
controller.addProperty("geometry", "Geometry.default");
|
||||
}
|
||||
|
||||
JsonArray materials = new JsonArray();
|
||||
String material = entity.getModelConfig().getTextureMaterials().get(key);
|
||||
|
||||
JsonObject materialItem = new JsonObject();
|
||||
if (material != null) {
|
||||
materialItem.addProperty("*", "Material." + material);
|
||||
} else if (anim != null) {
|
||||
materialItem.addProperty("*", "Material.anim");
|
||||
JsonObject uvAnim = new JsonObject();
|
||||
controller.add("uv_anim", uvAnim);
|
||||
JsonArray offset = new JsonArray();
|
||||
offset.add(0.0);
|
||||
offset.add("math.mod(math.floor(q.life_time * " + anim.fps + ")," + anim.frames + ") / " + anim.frames);
|
||||
uvAnim.add("offset", offset);
|
||||
JsonArray scale = new JsonArray();
|
||||
scale.add(1.0);
|
||||
scale.add("1 / " + anim.frames);
|
||||
uvAnim.add("scale", scale);
|
||||
} else {
|
||||
materialItem.addProperty("*", "Material.default");
|
||||
}
|
||||
materials.add(materialItem);
|
||||
controller.add("materials", materials);
|
||||
|
||||
JsonArray textures = new JsonArray();
|
||||
if (singleTexture) {
|
||||
textures.add("Texture.default");
|
||||
} else {
|
||||
textures.add("Texture." + key);
|
||||
}
|
||||
|
||||
controller.add("textures", textures);
|
||||
|
||||
// if (enable) {
|
||||
JsonArray partVisibility = new JsonArray();
|
||||
JsonObject visibilityDefault = new JsonObject();
|
||||
visibilityDefault.addProperty("*", false);
|
||||
partVisibility.add(visibilityDefault);
|
||||
int i = 0;
|
||||
List<String> sorted = new ArrayList<>(bones.keySet());
|
||||
Map<String, String> originalId = new HashMap<>();
|
||||
ListIterator<String> iterator = sorted.listIterator();
|
||||
while (iterator.hasNext()) {
|
||||
String s = iterator.next();
|
||||
String o = s;
|
||||
for (String r : NEED_REMOVE_WHEN_SORT) {
|
||||
s = s.replace(r, "");
|
||||
}
|
||||
iterator.set(s);
|
||||
originalId.put(s, o);
|
||||
}
|
||||
Collections.sort(sorted);
|
||||
|
||||
Set<String> uvAllBones = new HashSet<>();
|
||||
for (String uvBone : uvBonesId) {
|
||||
if (uvBone.equals("*")) {
|
||||
uvAllBones.addAll(bones.keySet());
|
||||
}
|
||||
|
||||
if (!bones.containsKey(uvBone.toLowerCase())) continue;
|
||||
|
||||
uvAllBones.add(uvBone.toLowerCase());
|
||||
}
|
||||
|
||||
for (String boneName : sorted) {
|
||||
boneName = originalId.get(boneName);
|
||||
JsonObject visibilityItem = new JsonObject();
|
||||
BoneData bone = bones.get(boneName);
|
||||
boolean uvParent = false;
|
||||
|
||||
for (BoneData child : bone.getAllChildren()) {
|
||||
if (child.getName().startsWith("uv_")) {
|
||||
if (uvAllBones.contains(child.getName())) {
|
||||
uvParent = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (Map.Entry<String, Set<String>> entry : entity.getModelConfig().getBingingBones().entrySet()) {
|
||||
if (entry.getKey().equals(key)) continue;
|
||||
|
||||
if (entry.getValue().stream().anyMatch(boneName::equalsIgnoreCase)) {
|
||||
uvParent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!processedBones.contains(bone) && (uvParent || uvAllBones.contains(boneName) || uvBonesId.contains("*"))) {
|
||||
int index = i;
|
||||
if (boneName.startsWith("uv_")) {
|
||||
index = sorted.indexOf(bone.getParent());
|
||||
}
|
||||
|
||||
int n = (int) Math.pow(2, (index % 24));
|
||||
if (entity.getModelConfig().isDisablePartVisibility()) {
|
||||
visibilityItem.addProperty(boneName, true);
|
||||
} else {
|
||||
visibilityItem.addProperty(boneName, "math.mod(math.floor(query.property('" + namespace + ":bone" + index / 24 + "') / " + n + "), 2) == 1");
|
||||
}
|
||||
partVisibility.add(visibilityItem);
|
||||
if (!uvBonesId.contains("*")) {
|
||||
processedBones.add(bone);
|
||||
}
|
||||
}
|
||||
if (!boneName.startsWith("uv_")) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
controller.add("part_visibility", partVisibility);
|
||||
//}
|
||||
}
|
||||
|
||||
return root.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator.data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class BoneData {
|
||||
|
||||
private final String name;
|
||||
private final String parent;
|
||||
private final Set<BoneData> children;
|
||||
private final Set<BoneData> allChildren;
|
||||
|
||||
public BoneData(String name, String parent, Set<BoneData> children, Set<BoneData> allChildren) {
|
||||
this.name = name;
|
||||
this.parent = parent;
|
||||
this.children = children;
|
||||
this.allChildren = allChildren;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public Set<BoneData> getChildren() {
|
||||
return children;
|
||||
}
|
||||
|
||||
public Set<BoneData> getAllChildren() {
|
||||
return allChildren;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package re.imc.geysermodelengineextension.managers.resourcepack.generator.data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class TextureData {
|
||||
|
||||
private final String modelId;
|
||||
private final String path;
|
||||
private final Set<String> bindingBones;
|
||||
private final byte[] image;
|
||||
|
||||
public TextureData(String modelId, String path, Set<String> bindingBones, byte[] image) {
|
||||
this.modelId = modelId;
|
||||
this.path = path;
|
||||
this.bindingBones = bindingBones;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public String getModelId() {
|
||||
return modelId;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public Set<String> getBindingBones() {
|
||||
return bindingBones;
|
||||
}
|
||||
|
||||
public byte[] getImage() {
|
||||
return image;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package re.imc.geysermodelengineextension.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BooleanPacker {
|
||||
|
||||
public static final int MAX_BOOLEANS = 24;
|
||||
|
||||
public static int booleansToInt(List<Boolean> booleans) {
|
||||
int result = 0;
|
||||
int i = 1;
|
||||
|
||||
for (boolean b : booleans) {
|
||||
if (b) result += i;
|
||||
i *= 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int mapBooleansToInt(Map<String, Boolean> booleanMap) {
|
||||
int result = 0;
|
||||
int i = 1;
|
||||
List<String> keys = new ArrayList<>(booleanMap.keySet());
|
||||
Collections.sort(keys);
|
||||
|
||||
for (String key : keys) {
|
||||
if (booleanMap.get(key)) result += i;
|
||||
i *= 2;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<Integer> booleansToInts(List<Boolean> booleans) {
|
||||
List<Integer> results = new ArrayList<>();
|
||||
int result = 0;
|
||||
int i = 1;
|
||||
int i1 = 1;
|
||||
for (boolean b : booleans) {
|
||||
if (b) {
|
||||
result += i;
|
||||
}
|
||||
if (i1 % MAX_BOOLEANS == 0 || i1 == booleans.size()) {
|
||||
results.add(result);
|
||||
result = 0;
|
||||
i = 1;
|
||||
} else {
|
||||
i *= 2;
|
||||
}
|
||||
i1++;
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public static List<Integer> mapBooleansToInts(Map<String, Boolean> booleanMap) {
|
||||
List<String> keys = new ArrayList<>(booleanMap.keySet());
|
||||
List<Boolean> booleans = new ArrayList<>();
|
||||
Collections.sort(keys);
|
||||
|
||||
for (String key : keys) {
|
||||
booleans.add(booleanMap.get(key));
|
||||
}
|
||||
|
||||
return booleansToInts(booleans);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package re.imc.geysermodelengineextension.util;
|
||||
|
||||
import org.spongepowered.configurate.CommentedConfigurationNode;
|
||||
import org.spongepowered.configurate.serialize.SerializationException;
|
||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||
import re.imc.geysermodelengineextension.GeyserModelEngineExtension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
public class FileConfiguration {
|
||||
|
||||
private final GeyserModelEngineExtension extension = GeyserModelEngineExtension.getExtension();
|
||||
|
||||
private final Path dataDirectory = extension.dataFolder();
|
||||
|
||||
protected final String configFile;
|
||||
private final CommentedConfigurationNode configurationNode;
|
||||
|
||||
public FileConfiguration(String configFile) {
|
||||
this.configFile = configFile;
|
||||
this.configurationNode = load(configFile);
|
||||
}
|
||||
|
||||
public FileConfiguration(CommentedConfigurationNode configurationNode, String configFile) {
|
||||
this.configFile = configFile;
|
||||
this.configurationNode = configurationNode;
|
||||
}
|
||||
|
||||
private CommentedConfigurationNode load(String fileName) {
|
||||
try {
|
||||
if (!Files.exists(this.dataDirectory)) Files.createDirectories(this.dataDirectory);
|
||||
|
||||
Path config = this.dataDirectory.resolve(fileName);
|
||||
|
||||
FileUtils.createFiles(extension, fileName);
|
||||
|
||||
YamlConfigurationLoader loader = YamlConfigurationLoader.builder().path(config).build();
|
||||
|
||||
return loader.load();
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
public FileConfiguration getConfigurationSection(String path) {
|
||||
CommentedConfigurationNode sectionNode = getConfigurationSectionNode(path);
|
||||
if (sectionNode == null || sectionNode.virtual()) return null;
|
||||
return new FileConfiguration(sectionNode, this.configFile);
|
||||
}
|
||||
|
||||
public String getString(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null) return null;
|
||||
return node.getString();
|
||||
}
|
||||
|
||||
public List<String> getStringList(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null || node.virtual()) return List.of();
|
||||
|
||||
try {
|
||||
return node.getList(String.class, List.of());
|
||||
} catch (SerializationException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null) return 0;
|
||||
return node.getInt();
|
||||
}
|
||||
|
||||
public List<Integer> getIntegerList(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null || node.virtual()) return List.of();
|
||||
|
||||
try {
|
||||
return node.getList(Integer.class, List.of());
|
||||
} catch (SerializationException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
public double getDouble(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null) return 0;
|
||||
return node.getDouble();
|
||||
}
|
||||
|
||||
public double getLong(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null) return 0;
|
||||
return node.getLong();
|
||||
}
|
||||
|
||||
public List<Long> getLongList(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null || node.virtual()) return List.of();
|
||||
|
||||
try {
|
||||
return node.getList(Long.class, List.of());
|
||||
} catch (SerializationException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getBoolean(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
if (node == null) return false;
|
||||
return node.getBoolean();
|
||||
}
|
||||
|
||||
public boolean isBoolean(String path) {
|
||||
CommentedConfigurationNode node = getInternal(path);
|
||||
return node != null && node.raw() instanceof Boolean;
|
||||
}
|
||||
|
||||
public File toFile() {
|
||||
return this.dataDirectory.resolve(configFile).toFile();
|
||||
}
|
||||
|
||||
private CommentedConfigurationNode getInternal(String path) {
|
||||
CommentedConfigurationNode node = toSplitRoot(path, this.configurationNode);
|
||||
if (node.virtual()) return null;
|
||||
return node;
|
||||
}
|
||||
|
||||
private CommentedConfigurationNode toSplitRoot(String path, CommentedConfigurationNode node) {
|
||||
if (path == null) return node;
|
||||
path = path.startsWith(".") ? path.substring(1) : path;
|
||||
return node.node(path.contains(".") ? path.split("\\.") : new Object[]{path});
|
||||
}
|
||||
|
||||
private CommentedConfigurationNode getConfigurationSectionNode(String path) {
|
||||
return getInternal(path);
|
||||
}
|
||||
|
||||
public CommentedConfigurationNode getRootNode() {
|
||||
return configurationNode;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package re.imc.geysermodelengineextension.util;
|
||||
|
||||
import re.imc.geysermodelengineextension.GeyserModelEngineExtension;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FileUtils {
|
||||
|
||||
public static List<File> getAllFiles(File folder, String fileType) {
|
||||
List<File> files = new ArrayList<>();
|
||||
if (folder == null || !folder.exists()) return files;
|
||||
|
||||
for (File file : folder.listFiles()) {
|
||||
if (file.isDirectory()) {
|
||||
files.addAll(getAllFiles(file, fileType));
|
||||
} else if (file.getName().endsWith(fileType)) {
|
||||
files.add(file);
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
public static void createFiles(GeyserModelEngineExtension extension, String fileName) {
|
||||
Path config = extension.dataFolder().resolve(fileName);
|
||||
if (Files.exists(config)) return;
|
||||
|
||||
try {
|
||||
Path parentDirectory = config.getParent();
|
||||
if (parentDirectory != null && !Files.exists(parentDirectory)) Files.createDirectories(parentDirectory);
|
||||
|
||||
try (InputStream resourceAsStream = extension.getClass().getClassLoader().getResourceAsStream("Extension/" + fileName)) {
|
||||
if (resourceAsStream == null) {
|
||||
extension.logger().warning(fileName + " is invalid!");
|
||||
return;
|
||||
}
|
||||
|
||||
Files.copy(resourceAsStream, config);
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
} catch (IOException err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package re.imc.geysermodelengineextension.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public class ZipUtil {
|
||||
|
||||
public static void compressFolder(File folder, String folderName, ZipOutputStream zipOutputStream) throws IOException {
|
||||
File[] files = folder.listFiles();
|
||||
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
if (folderName == null) {
|
||||
compressFolder(file, file.getName(), zipOutputStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
compressFolder(file, folderName + "/" + file.getName(), zipOutputStream);
|
||||
} else {
|
||||
if (folderName == null) {
|
||||
addToZipFile(file.getName(), file, zipOutputStream);
|
||||
continue;
|
||||
}
|
||||
|
||||
addToZipFile(folderName + "/" + file.getName(), file, zipOutputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addToZipFile(String fileName, File file, ZipOutputStream zipOutputStream) throws IOException {
|
||||
ZipEntry entry = new ZipEntry(fileName);
|
||||
zipOutputStream.putNextEntry(entry);
|
||||
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int bytesRead;
|
||||
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
|
||||
zipOutputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
zipOutputStream.closeEntry();
|
||||
}
|
||||
}
|
||||
4
geyser/src/main/resources/Extension/Lang/messages.yml
Normal file
4
geyser/src/main/resources/Extension/Lang/messages.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
commands:
|
||||
geysermodelenginepackgenerator:
|
||||
reload:
|
||||
successfully-reloaded: "GeyserModelEnginePackGenerator reloaded!"
|
||||
6
geyser/src/main/resources/Extension/config.yml
Normal file
6
geyser/src/main/resources/Extension/config.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
models:
|
||||
namespace: "modelengine"
|
||||
|
||||
options:
|
||||
resource-pack:
|
||||
auto-load: true
|
||||
8
geyser/src/main/resources/extension.yml
Normal file
8
geyser/src/main/resources/extension.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
name: GeyserModelEngineExtension
|
||||
id: geysermodelengineextension
|
||||
main: re.imc.geysermodelengineextension.GeyserModelEngineExtension
|
||||
api: 2.7.0
|
||||
version: 1.0.0
|
||||
authors:
|
||||
- zimzaza4
|
||||
- xSquishyLiam
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
70
paper/build.gradle.kts
Normal file
70
paper/build.gradle.kts
Normal file
@@ -0,0 +1,70 @@
|
||||
plugins {
|
||||
id("java")
|
||||
id("com.gradleup.shadow") version "9.2.2"
|
||||
}
|
||||
|
||||
group = "re.imc"
|
||||
version = "1.0.1"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://central.sonatype.com/repository/maven-snapshots/")
|
||||
|
||||
maven("https://mvn.lumine.io/repository/maven-public/")
|
||||
|
||||
maven("https://repo.opencollab.dev/main/")
|
||||
|
||||
maven("https://repo.codemc.io/repository/maven-public/")
|
||||
maven("https://repo.codemc.io/repository/maven-releases/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("io.papermc.paper:paper-api:1.21.10-R0.1-SNAPSHOT")
|
||||
// implementation("dev.jorel:commandapi-paper-shade:11.0.0")
|
||||
|
||||
compileOnly("com.ticxo.modelengine:ModelEngine:R4.0.9")
|
||||
compileOnly("io.github.toxicity188:bettermodel:1.14.0")
|
||||
|
||||
compileOnly(files("libs/geyserutils-spigot-1.0-SNAPSHOT.jar"))
|
||||
compileOnly("org.geysermc.floodgate:api:2.2.4-SNAPSHOT")
|
||||
|
||||
implementation("com.github.retrooper:packetevents-spigot:2.11.0")
|
||||
implementation("org.bstats:bstats-bukkit:3.0.2")
|
||||
|
||||
implementation("org.reflections:reflections:0.10.2")
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain.languageVersion.set(JavaLanguageVersion.of(21))
|
||||
}
|
||||
|
||||
tasks.compileJava {
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveFileName.set("${rootProject.name}-${version}.jar")
|
||||
|
||||
relocate("dev.jorel.commandapi", "re.imc.geysermodelengine.libs.commandapi")
|
||||
|
||||
relocate("com.github.retrooper", "re.imc.geysermodelengine.libs.com.github.retrooper.packetevents")
|
||||
relocate("io.github.retrooper", "re.imc.geysermodelengine.libs.io.github.retrooper.packetevents")
|
||||
|
||||
relocate("org.bstats", "re.imc.geysermodelengine.libs.bstats")
|
||||
|
||||
relocate("org.reflections", "re.imc.geysermodelengine.libs.reflections")
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn("shadowJar")
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
val props = mapOf("version" to version)
|
||||
inputs.properties(props)
|
||||
filteringCharset = "UTF-8"
|
||||
filesMatching("paper-plugin.yml") {
|
||||
expand(props)
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -2,23 +2,20 @@ package re.imc.geysermodelengine;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
||||
import com.ticxo.modelengine.api.model.ActiveModel;
|
||||
import dev.jorel.commandapi.CommandAPI;
|
||||
import dev.jorel.commandapi.CommandAPIBukkitConfig;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import org.bstats.bukkit.Metrics;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import re.imc.geysermodelengine.hooks.FloodgateAPIHook;
|
||||
import re.imc.geysermodelengine.listener.ModelListener;
|
||||
import re.imc.geysermodelengine.listener.MountPacketListener;
|
||||
import re.imc.geysermodelengine.managers.ConfigManager;
|
||||
import re.imc.geysermodelengine.managers.commands.CommandManager;
|
||||
import re.imc.geysermodelengine.managers.model.EntityTaskManager;
|
||||
import re.imc.geysermodelengine.managers.model.ModelManager;
|
||||
import re.imc.geysermodelengine.managers.model.data.ModelEntityData;
|
||||
import re.imc.geysermodelengine.runnables.BedrockMountControlRunnable;
|
||||
import re.imc.geysermodelengine.runnables.UpdateTaskRunnable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class GeyserModelEngine extends JavaPlugin {
|
||||
@@ -30,12 +27,15 @@ public class GeyserModelEngine extends JavaPlugin {
|
||||
private ModelManager modelManager;
|
||||
private EntityTaskManager entityTaskManager;
|
||||
|
||||
private ScheduledExecutorService schedulerPool;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this));
|
||||
PacketEvents.getAPI().load();
|
||||
|
||||
CommandAPI.onLoad(new CommandAPIBukkitConfig(this));
|
||||
// CommandAPI.onLoad(new CommandAPIPaperConfig(this));
|
||||
preLoadManagers();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,6 +44,8 @@ public class GeyserModelEngine extends JavaPlugin {
|
||||
loadManagers();
|
||||
loadRunnables();
|
||||
|
||||
loadBStats();
|
||||
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new MountPacketListener(this), PacketListenerPriority.NORMAL);
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new ModelListener(this), this);
|
||||
@@ -51,25 +53,27 @@ public class GeyserModelEngine extends JavaPlugin {
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
this.modelManager.removeEntities();
|
||||
|
||||
PacketEvents.getAPI().terminate();
|
||||
|
||||
for (Map<ActiveModel, ModelEntityData> entities : modelManager.getEntitiesCache().values()) {
|
||||
entities.forEach((model, modelEntity) -> {
|
||||
modelEntity.getEntity().remove();
|
||||
});
|
||||
}
|
||||
|
||||
CommandAPI.onDisable();
|
||||
// CommandAPI.onDisable();
|
||||
}
|
||||
|
||||
private void loadHooks() {
|
||||
PacketEvents.getAPI().init();
|
||||
CommandAPI.onEnable();
|
||||
FloodgateAPIHook.loadHook(this);
|
||||
// CommandAPI.onEnable();
|
||||
}
|
||||
|
||||
private void loadBStats() {
|
||||
if (this.configManager.getConfig().getBoolean("metrics.bstats", true)) new Metrics(this, 26981);
|
||||
}
|
||||
|
||||
private void preLoadManagers() {
|
||||
this.configManager = new ConfigManager(this);
|
||||
}
|
||||
|
||||
private void loadManagers() {
|
||||
this.configManager = new ConfigManager(this);
|
||||
|
||||
this.commandManager = new CommandManager(this);
|
||||
|
||||
this.modelManager = new ModelManager(this);
|
||||
@@ -77,8 +81,9 @@ public class GeyserModelEngine extends JavaPlugin {
|
||||
}
|
||||
|
||||
private void loadRunnables() {
|
||||
Bukkit.getAsyncScheduler().runAtFixedRate(this, new UpdateTaskRunnable(this), 10, configManager.getConfig().getLong("entity-position-update-period", 35), TimeUnit.MILLISECONDS);
|
||||
Bukkit.getAsyncScheduler().runAtFixedRate(this, new BedrockMountControlRunnable(this), 1, 1, TimeUnit.MILLISECONDS);
|
||||
this.schedulerPool = Executors.newScheduledThreadPool(configManager.getConfig().getInt("models.thread-pool-size", 4));
|
||||
this.schedulerPool.scheduleAtFixedRate(new UpdateTaskRunnable(this), 10, configManager.getConfig().getLong("models.entity-position-update-period", 35), TimeUnit.MILLISECONDS);
|
||||
this.schedulerPool.scheduleAtFixedRate(new BedrockMountControlRunnable(this), 1, 1, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
public ConfigManager getConfigManager() {
|
||||
@@ -96,4 +101,8 @@ public class GeyserModelEngine extends JavaPlugin {
|
||||
public EntityTaskManager getEntityTaskManager() {
|
||||
return entityTaskManager;
|
||||
}
|
||||
|
||||
public ScheduledExecutorService getSchedulerPool() {
|
||||
return schedulerPool;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package re.imc.geysermodelengine.commands.geysermodelenginecommands;
|
||||
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
import re.imc.geysermodelengine.managers.commands.subcommands.SubCommands;
|
||||
import re.imc.geysermodelengine.util.ColourUtils;
|
||||
|
||||
public class GeyserModelEngineReloadCommand implements SubCommands {
|
||||
|
||||
private final GeyserModelEngine plugin;
|
||||
|
||||
private final ColourUtils colourUtils = new ColourUtils();
|
||||
|
||||
public GeyserModelEngineReloadCommand(GeyserModelEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public CommandAPICommand onCommand() {
|
||||
// return new CommandAPICommand("reload")
|
||||
// .withPermission("geysermodelengine.commands.reload")
|
||||
// .executes((sender, args) -> {
|
||||
// Bukkit.getAsyncScheduler().runNow(plugin, scheduledTask -> plugin.getConfigManager().load());
|
||||
// sender.sendMessage(colourUtils.miniFormat(plugin.getConfigManager().getLang().getString("commands.reload.successfully-reloaded")));
|
||||
// });
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package re.imc.geysermodelengine.hooks;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
|
||||
public class FloodgateAPIHook {
|
||||
|
||||
private static FloodgateApi floodgateAPI;
|
||||
|
||||
public static void loadHook(GeyserModelEngine plugin) {
|
||||
if (Bukkit.getPluginManager().getPlugin("floodgate") == null || !plugin.getConfigManager().getConfig().getBoolean("options.hooks.floodgate", true)) {
|
||||
plugin.getLogger().info("Floodgate hook disabled!");
|
||||
return;
|
||||
}
|
||||
|
||||
floodgateAPI = FloodgateApi.getInstance();
|
||||
plugin.getLogger().info("Floodgate hook enabled!");
|
||||
}
|
||||
|
||||
public static FloodgateApi getAPI() {
|
||||
return floodgateAPI;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package re.imc.geysermodelengine.listener;
|
||||
|
||||
import kr.toxicity.model.api.event.CreateEntityTrackerEvent;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
import re.imc.geysermodelengine.managers.model.entity.BetterModelEntityData;
|
||||
import re.imc.geysermodelengine.managers.model.model.Model;
|
||||
|
||||
public class BetterModelListener implements Listener {
|
||||
|
||||
private final GeyserModelEngine plugin;
|
||||
|
||||
public BetterModelListener(GeyserModelEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onModelSpawn(CreateEntityTrackerEvent event) {
|
||||
plugin.getModelManager().getModelHandler().createModel(event.sourceEntity(), event.getTracker(), event.tracker());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onModelDamage(EntityDamageByEntityEvent event) {
|
||||
Entity entity = event.getEntity();
|
||||
|
||||
Model model = plugin.getModelManager().getModelEntitiesCache().get(entity.getEntityId());
|
||||
if (model == null) return;
|
||||
|
||||
BetterModelEntityData entityData = (BetterModelEntityData) model.getEntityData();
|
||||
|
||||
entityData.setHurt(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package re.imc.geysermodelengine.listener;
|
||||
|
||||
import com.ticxo.modelengine.api.events.*;
|
||||
import com.ticxo.modelengine.api.model.ActiveModel;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
import re.imc.geysermodelengine.managers.model.entity.EntityData;
|
||||
import re.imc.geysermodelengine.managers.model.model.Model;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ModelEngineListener implements Listener {
|
||||
|
||||
private final GeyserModelEngine plugin;
|
||||
|
||||
public ModelEngineListener(GeyserModelEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onAddModel(AddModelEvent event) {
|
||||
if (event.isCancelled()) return;
|
||||
plugin.getModelManager().getModelHandler().createModel(event.getTarget(), event.getModel());
|
||||
}
|
||||
|
||||
// Needs Testing
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onModelMount(ModelMountEvent event) {
|
||||
if (!event.isDriver()) return;
|
||||
|
||||
ActiveModel activeModel = event.getVehicle();
|
||||
if (activeModel == null) return;
|
||||
|
||||
int entityID = activeModel.getModeledEntity().getBase().getEntityId();
|
||||
|
||||
Map<Model, EntityData> entityDataCache = plugin.getModelManager().getEntitiesCache().get(entityID);
|
||||
if (entityDataCache == null) return;
|
||||
|
||||
Model model = plugin.getModelManager().getModelEntitiesCache().get(entityID);
|
||||
|
||||
EntityData entityData = entityDataCache.get(model);
|
||||
|
||||
if (entityData != null && event.getPassenger() instanceof Player player) {
|
||||
plugin.getModelManager().getDriversCache().put(player.getUniqueId(), Pair.of(event.getVehicle(), event.getSeat()));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR)
|
||||
public void onModelDismount(ModelDismountEvent event) {
|
||||
if (event.getPassenger() instanceof Player player) {
|
||||
plugin.getModelManager().getDriversCache().remove(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package re.imc.geysermodelengine.listener;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.event.world.WorldInitEvent;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
import re.imc.geysermodelengine.util.BedrockUtils;
|
||||
|
||||
public class ModelListener implements Listener {
|
||||
|
||||
private final GeyserModelEngine plugin;
|
||||
|
||||
public ModelListener(GeyserModelEngine plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/*
|
||||
/ xSquishyLiam:
|
||||
/ May change this into a better system?
|
||||
*/
|
||||
@EventHandler
|
||||
public void onWorldInit(WorldInitEvent event) {
|
||||
World world = event.getWorld();
|
||||
world.getEntities().forEach(entity -> plugin.getModelManager().getModelHandler().processEntities(entity));
|
||||
}
|
||||
|
||||
/*
|
||||
/ xSquishyLiam:
|
||||
/ A runDelay makes sure the client doesn't see pigs on login due to the client resyncing themselves back to normal
|
||||
*/
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!BedrockUtils.isBedrockPlayer(player)) return;
|
||||
Bukkit.getGlobalRegionScheduler().runDelayed(plugin, scheduledTask -> plugin.getModelManager().getPlayerJoinedCache().add(player.getUniqueId()), 10);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
if (!BedrockUtils.isBedrockPlayer(player)) return;
|
||||
plugin.getModelManager().getPlayerJoinedCache().remove(player.getUniqueId());
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.geysermc.floodgate.api.FloodgateApi;
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
import re.imc.geysermodelengine.util.BedrockUtils;
|
||||
|
||||
public class MountPacketListener implements PacketListener {
|
||||
|
||||
@@ -23,16 +24,16 @@ public class MountPacketListener implements PacketListener {
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (event.getPacketType() != PacketType.Play.Client.ENTITY_ACTION) return;
|
||||
if (!FloodgateApi.getInstance().isFloodgatePlayer(event.getUser().getUUID())) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (!BedrockUtils.isBedrockPlayer(player)) return;
|
||||
|
||||
WrapperPlayClientEntityAction action = new WrapperPlayClientEntityAction(event);
|
||||
Pair<ActiveModel, Mount> seat = plugin.getModelManager().getDriversCache().get(player);
|
||||
Pair<ActiveModel, Mount> seat = plugin.getModelManager().getDriversCache().get(player.getUniqueId());
|
||||
|
||||
if (seat == null) return;
|
||||
if (action.getAction() != WrapperPlayClientEntityAction.Action.START_SNEAKING) return;
|
||||
|
||||
ModelEngineAPI.getMountPairManager().tryDismount(event.getPlayer());
|
||||
ModelEngineAPI.getMountPairManager().tryDismount(player);
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ public class CommandManager {
|
||||
for (Class<?> clazz : new Reflections(path).getSubTypesOf(CommandManagers.class)) {
|
||||
try {
|
||||
CommandManagers commandManager = (CommandManagers) clazz.getDeclaredConstructor(GeyserModelEngine.class).newInstance(plugin);
|
||||
plugin.getLogger().warning("Loading Command Manager - " + commandManager.name());
|
||||
commandManagersCache.put(commandManager.name(), commandManager);
|
||||
plugin.getLogger().info("Loading Command Manager - " + commandManager.getName());
|
||||
commandManagersCache.put(commandManager.getName(), commandManager);
|
||||
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException err) {
|
||||
plugin.getLogger().severe("Failed to load Command Manager " + clazz.getName());
|
||||
throw new RuntimeException(err);
|
||||
@@ -6,7 +6,13 @@ import java.util.ArrayList;
|
||||
|
||||
public interface CommandManagers {
|
||||
|
||||
String name();
|
||||
/**
|
||||
* Gets the name of the command manager
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Gets the command manager subcommands
|
||||
*/
|
||||
ArrayList<SubCommands> getCommands();
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package re.imc.geysermodelengine.managers.commands.managers.geysermodelengine;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import re.imc.geysermodelengine.GeyserModelEngine;
|
||||
import re.imc.geysermodelengine.commands.geysermodelenginecommands.GeyserModelEngineReloadCommand;
|
||||
import re.imc.geysermodelengine.managers.commands.CommandManagers;
|
||||
@@ -19,15 +18,15 @@ public class GeyserModelEngineCommandManager implements CommandManagers {
|
||||
}
|
||||
|
||||
private void registerCommand() {
|
||||
CommandAPICommand geyserModelEngineCommand = new CommandAPICommand(name());
|
||||
|
||||
commands.forEach(subCommands -> geyserModelEngineCommand.withSubcommand(subCommands.onCommand()));
|
||||
|
||||
geyserModelEngineCommand.register();
|
||||
// CommandAPICommand geyserModelEngineCommand = new CommandAPICommand(getName());
|
||||
//
|
||||
// commands.forEach(subCommands -> geyserModelEngineCommand.withSubcommand(subCommands.onCommand()));
|
||||
//
|
||||
// geyserModelEngineCommand.register();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String name() {
|
||||
public String getName() {
|
||||
return "geysermodelengine";
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user