├── .github └── workflows │ └── maven.yml ├── .gitignore ├── .idea ├── .gitignore ├── encodings.xml ├── misc.xml └── uiDesigner.xml ├── LICENSE ├── README.md ├── bungee ├── pom.xml └── src │ └── main │ ├── java │ └── me │ │ └── zimzaza4 │ │ └── geyserutils │ │ └── bungee │ │ └── GeyserUtils.java │ └── resources │ └── bungee.yml ├── common ├── pom.xml └── src │ └── main │ └── java │ └── me │ └── zimzaza4 │ └── geyserutils │ └── common │ ├── animation │ └── Animation.java │ ├── camera │ ├── data │ │ ├── CameraPreset.java │ │ ├── Color.java │ │ ├── Ease.java │ │ ├── EaseType.java │ │ ├── Rot.java │ │ └── Time.java │ └── instruction │ │ ├── ClearInstruction.java │ │ ├── FadeInstruction.java │ │ ├── Instruction.java │ │ └── SetInstruction.java │ ├── channel │ └── GeyserUtilsChannels.java │ ├── form │ └── element │ │ └── NpcDialogueButton.java │ ├── manager │ └── PacketManager.java │ ├── packet │ ├── AnimateEntityCustomPayloadPacket.java │ ├── BundlePacket.java │ ├── CameraInstructionCustomPayloadPacket.java │ ├── CameraLockCustomPayloadPacket.java │ ├── CameraShakeCustomPayloadPacket.java │ ├── CustomEntityDataPacket.java │ ├── CustomEntityPacket.java │ ├── CustomParticleEffectPayloadPacket.java │ ├── CustomPayloadPacket.java │ ├── CustomSkinPayloadPacket.java │ ├── EntityPropertyPacket.java │ ├── EntityPropertyRegisterPacket.java │ ├── NpcDialogueFormDataCustomPayloadPacket.java │ └── NpcFormResponseCustomPayloadPacket.java │ ├── particle │ └── CustomParticle.java │ └── util │ ├── CustomPayloadPacketUtils.java │ └── Pos.java ├── geyser ├── libs │ └── Geyser-Standalone.jar ├── pom.xml └── src │ └── main │ ├── java │ └── me │ │ └── zimzaza4 │ │ └── geyserutils │ │ └── geyser │ │ ├── GeyserUtils.java │ │ ├── MountFix.java │ │ ├── camera │ │ └── CameraPresetDefinition.java │ │ ├── form │ │ ├── NpcDialogueForm.java │ │ ├── NpcDialogueForms.java │ │ └── element │ │ │ └── Button.java │ │ ├── replace │ │ └── JavaAddEntityTranslatorReplace.java │ │ ├── translator │ │ └── NPCFormResponseTranslator.java │ │ └── util │ │ ├── Converter.java │ │ ├── DeltaUtils.java │ │ └── ReflectionUtils.java │ └── resources │ └── extension.yml ├── pom.xml ├── spigot ├── pom.xml └── src │ └── main │ ├── java │ └── me │ │ └── zimzaza4 │ │ └── geyserutils │ │ └── spigot │ │ ├── GeyserUtils.java │ │ └── api │ │ ├── EntityUtils.java │ │ ├── PlayerUtils.java │ │ └── form │ │ └── NpcDialogueForm.java │ └── resources │ └── plugin.yml └── velocity ├── pom.xml └── src └── main └── java └── me └── zimzaza4 └── geyserutils └── velocity └── GeyserUtils.java /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Auto Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | build: 10 | name: Build 11 | runs-on: ubuntu-20.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v2 15 | 16 | # Setup JDK 17 | - name: Setup Java JDK 18 | uses: actions/setup-java@v3 19 | with: 20 | java-version: 17 21 | distribution: 'zulu' 22 | 23 | # Build 24 | - name: Build with Maven 25 | run: mvn -B package --file pom.xml 26 | 27 | 28 | - name: Auto release 29 | uses: "marvinpinto/action-automatic-releases@latest" 30 | with: 31 | repo_token: "${{ secrets.GITHUB_TOKEN }}" 32 | automatic_release_tag: latest 33 | prerelease: false 34 | files: | 35 | spigot/target/geyserutils-*.jar 36 | geyser/target/geyserutils-*.jar 37 | velocity/target/geyserutils-*.jar 38 | bungee/target/geyserutils-*.jar 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/modules.xml 8 | .idea/jarRepositories.xml 9 | .idea/compiler.xml 10 | .idea/libraries/ 11 | *.iws 12 | *.iml 13 | *.ipr 14 | 15 | ### Eclipse ### 16 | .apt_generated 17 | .classpath 18 | .factorypath 19 | .project 20 | .settings 21 | .springBeans 22 | .sts4-cache 23 | 24 | ### NetBeans ### 25 | /nbproject/private/ 26 | /nbbuild/ 27 | /dist/ 28 | /nbdist/ 29 | /.nb-gradle/ 30 | build/ 31 | !**/src/main/**/build/ 32 | !**/src/test/**/build/ 33 | 34 | ### VS Code ### 35 | .vscode/ 36 | 37 | ### Mac OS ### 38 | .DS_Store -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # 默认忽略的文件 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 zimzaza4 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GeyserUtils 2 | - camera shake 3 | - NPC form 4 | - animation 5 | - camera features(require modify geyser's startgamepacket by yourself XP) 6 | - (and thank daoge cmd so much ❤️ XD) 7 | 8 | _Install_ 9 | - GeyserUtils-Spigot -> your spigot server plugins folder 10 | - GeyserUtils-Velocity -> your velocity proxy (if exists) 11 | - GeyserUtils-Geyser -> your geyser extensions folder 12 | -------------------------------------------------------------------------------- /bungee/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | 8 | me.zimzaza4 9 | GeyserUtils 10 | 1.0-SNAPSHOT 11 | 12 | 13 | geyserutils-bungee 14 | 15 | 16 | 17 | 1.8 18 | UTF-8 19 | 20 | 21 | 22 | clean package 23 | 24 | 25 | org.apache.maven.plugins 26 | maven-compiler-plugin 27 | 3.8.1 28 | 29 | ${java.version} 30 | ${java.version} 31 | 32 | 33 | 34 | org.apache.maven.plugins 35 | maven-shade-plugin 36 | 3.2.4 37 | 38 | 39 | package 40 | 41 | shade 42 | 43 | 44 | false 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | src/main/resources 53 | true 54 | 55 | 56 | 57 | 58 | 59 | 60 | sonatype 61 | https://oss.sonatype.org/content/groups/public/ 62 | 63 | 64 | 65 | 66 | 67 | net.md-5 68 | bungeecord-api 69 | 1.20-R0.3-SNAPSHOT 70 | provided 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /bungee/src/main/java/me/zimzaza4/geyserutils/bungee/GeyserUtils.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.bungee; 2 | 3 | import net.md_5.bungee.api.ProxyServer; 4 | import net.md_5.bungee.api.plugin.Plugin; 5 | 6 | public final class GeyserUtils extends Plugin { 7 | 8 | @Override 9 | public void onEnable() { 10 | ProxyServer.getInstance() 11 | .registerChannel("geyserutils:main"); 12 | // Plugin startup logic 13 | } 14 | 15 | @Override 16 | public void onDisable() { 17 | // Plugin shutdown logic 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /bungee/src/main/resources/bungee.yml: -------------------------------------------------------------------------------- 1 | name: GeyserUtils 2 | version: '${project.version}' 3 | main: me.zimzaza4.geyserutils.bungee.GeyserUtils 4 | -------------------------------------------------------------------------------- /common/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.zimzaza4 8 | GeyserUtils 9 | 1.0-SNAPSHOT 10 | 11 | 12 | geyserutils-common 13 | 14 | 15 | 11 16 | 11 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-shade-plugin 25 | 3.4.1 26 | 27 | 28 | 29 | com.fasterxml.jackson 30 | me.zimzaza4.geyserutils.relocations.jackson 31 | 32 | 33 | 34 | 35 | 36 | package 37 | 38 | shade 39 | 40 | 41 | false 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | src/main/resources 50 | true 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | org.projectlombok 60 | lombok 61 | 1.18.28 62 | compile 63 | 64 | 65 | com.fasterxml.jackson.core 66 | jackson-core 67 | 2.15.2 68 | 69 | 70 | com.fasterxml.jackson.core 71 | jackson-databind 72 | 2.15.2 73 | 74 | 75 | org.jetbrains 76 | annotations 77 | 24.0.1 78 | compile 79 | 80 | 81 | org.jetbrains 82 | annotations 83 | 24.0.1 84 | compile 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/animation/Animation.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.animation; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | 6 | @Builder 7 | @Getter 8 | public class Animation { 9 | public static final float DEFAULT_BLEND_OUT_TIME = 0.0f; 10 | public static final String DEFAULT_STOP_EXPRESSION = "query.any_animation_finished"; 11 | public static final String DEFAULT_CONTROLLER = "__runtime_controller"; 12 | public static final String DEFAULT_NEXT_STATE = "default"; 13 | public static final int DEFAULT_STOP_EXPRESSION_VERSION = 16777216; 14 | 15 | private String animation; 16 | @Builder.Default 17 | private String nextState = DEFAULT_NEXT_STATE; 18 | @Builder.Default 19 | private float blendOutTime = DEFAULT_BLEND_OUT_TIME; 20 | @Builder.Default 21 | private String stopExpression = DEFAULT_STOP_EXPRESSION; 22 | @Builder.Default 23 | private String controller = DEFAULT_CONTROLLER; 24 | @Builder.Default 25 | private int stopExpressionVersion = DEFAULT_STOP_EXPRESSION_VERSION; 26 | } -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/data/CameraPreset.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.data; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import me.zimzaza4.geyserutils.common.util.Pos; 6 | import org.jetbrains.annotations.Nullable; 7 | 8 | import java.util.Map; 9 | import java.util.TreeMap; 10 | 11 | @Getter 12 | public class CameraPreset { 13 | private static final Map PRESETS = new TreeMap<>(); 14 | public static CameraPreset FIRST_PERSON; 15 | public static CameraPreset FREE; 16 | public static CameraPreset THIRD_PERSON; 17 | public static CameraPreset THIRD_PERSON_FRONT; 18 | private String identifier; 19 | @Getter 20 | private String inheritFrom; 21 | @Getter 22 | @Nullable 23 | private Pos pos; 24 | @Getter 25 | @Nullable 26 | private Rot rot; 27 | @Getter 28 | private int id; 29 | @Builder 30 | public CameraPreset(String identifier, String inheritFrom, @Nullable Pos pos, @Nullable Rot rot) { 31 | this.identifier = identifier; 32 | this.inheritFrom = inheritFrom != null ? inheritFrom : ""; 33 | this.pos = pos; 34 | this.rot = rot; 35 | } 36 | protected CameraPreset() { 37 | 38 | } 39 | 40 | public static Map getPresets() { 41 | return PRESETS; 42 | } 43 | 44 | public static CameraPreset getPreset(String identifier) { 45 | return getPresets().get(identifier); 46 | } 47 | 48 | public static void registerCameraPresets(CameraPreset... presets) { 49 | for (var preset : presets) { 50 | if (PRESETS.containsKey(preset.getIdentifier())) { 51 | continue; 52 | } 53 | PRESETS.put(preset.getIdentifier(), preset); 54 | } 55 | int id = 0; 56 | //重新分配id 57 | for (var preset : presets) { 58 | preset.id = id++; 59 | } 60 | } 61 | 62 | public static void load() { 63 | FIRST_PERSON = CameraPreset.builder() 64 | .identifier("minecraft:first_person") 65 | .build(); 66 | FREE = CameraPreset.builder() 67 | .identifier("minecraft:free") 68 | .pos(new Pos(0, 0, 0)) 69 | .rot(new Rot(0, 0)) 70 | .build(); 71 | THIRD_PERSON = CameraPreset.builder() 72 | .identifier("minecraft:third_person") 73 | .build(); 74 | THIRD_PERSON_FRONT = CameraPreset.builder() 75 | .identifier("minecraft:third_person_front") 76 | .build(); 77 | 78 | registerCameraPresets(FIRST_PERSON, FREE, THIRD_PERSON, THIRD_PERSON_FRONT); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/data/Color.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.Accessors; 7 | 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | @Accessors(fluent = true) 11 | @Data 12 | public class Color { 13 | float r; 14 | float g; 15 | float b; 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/data/Ease.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.data; 2 | 3 | import lombok.Data; 4 | import lombok.NoArgsConstructor; 5 | import lombok.experimental.Accessors; 6 | 7 | @NoArgsConstructor 8 | @Accessors(fluent = true) 9 | @Data 10 | public class Ease { 11 | 12 | float time; 13 | int easeType; 14 | 15 | public Ease(float time, EaseType easeType) { 16 | this.time = time; 17 | this.easeType = easeType.getIndex(); 18 | } 19 | 20 | public Ease easeType(EaseType easeType) { 21 | this.easeType = easeType.getIndex(); 22 | return this; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/data/EaseType.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.data; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum EaseType { 7 | LINEAR("linear", 0), 8 | SPRING("spring", 1), 9 | EASE_IN_SINE("in_sine", 2), 10 | EASE_OUT_SINE("out_sine", 3), 11 | EASE_IN_OUT_SINE("in_out_sine", 4), 12 | EASE_IN_QUAD("in_quad", 5), 13 | EASE_OUT_QUAD("out_quad", 6), 14 | EASE_IN_OUT_QUAD("in_out_quad", 7), 15 | EASE_IN_CUBIC("in_cubic", 8), 16 | EASE_OUT_CUBIC("out_cubic", 9), 17 | EASE_IN_OUT_CUBIC("in_out_cubic", 10), 18 | EASE_IN_QUART("in_quart", 11), 19 | EASE_OUT_QUART("out_quart", 12), 20 | EASE_IN_OUT_QUART("in_out_quart", 13), 21 | EASE_IN_QUINT("in_quint", 14), 22 | EASE_OUT_QUINT("out_quint", 15), 23 | EASE_IN_OUT_QUINT("in_out_quint", 16), 24 | EASE_IN_EXPO("in_expo", 17), 25 | EASE_OUT_EXPO("out_expo", 18), 26 | EASE_IN_OUT_EXPO("in_out_expo", 19), 27 | EASE_IN_CIRC("in_circ", 20), 28 | EASE_OUT_CIRC("out_circ", 21), 29 | EASE_IN_OUT_CIRC("in_out_circ", 22), 30 | EASE_IN_BACK("in_back", 23), 31 | EASE_OUT_BACK("out_back", 24), 32 | EASE_IN_OUT_BACK("in_out_back", 25), 33 | EASE_IN_ELASTIC("in_elastic", 26), 34 | EASE_OUT_ELASTIC("out_elastic", 27), 35 | EASE_IN_OUT_ELASTIC("in_out_elastic", 28), 36 | EASE_IN_BOUNCE("in_bounce", 29), 37 | EASE_OUT_BOUNCE("out_bounce", 30), 38 | EASE_IN_OUT_BOUNCE("in_out_bounce", 31); 39 | 40 | 41 | private final String type; 42 | private final int index; 43 | 44 | EaseType(String type, int index) { 45 | this.type = type; 46 | this.index = index; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/data/Rot.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.Accessors; 7 | 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | @Accessors(fluent = true) 11 | @Data 12 | public class Rot { 13 | float x; 14 | float y; 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/data/Time.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.data; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.Accessors; 7 | 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | @Accessors(fluent = true) 11 | @Data 12 | public class Time { 13 | float fadeIn; 14 | float hold; 15 | float fadeOut; 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/instruction/ClearInstruction.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.instruction; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class ClearInstruction implements Instruction { 7 | private static final ClearInstruction INSTANCE = new ClearInstruction(); 8 | private final int clear = 1; 9 | 10 | private ClearInstruction() { 11 | } 12 | 13 | public static ClearInstruction instance() { 14 | return INSTANCE; 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/instruction/FadeInstruction.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.instruction; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import me.zimzaza4.geyserutils.common.camera.data.Color; 7 | import me.zimzaza4.geyserutils.common.camera.data.Time; 8 | import org.jetbrains.annotations.Nullable; 9 | 10 | @Builder 11 | @AllArgsConstructor 12 | @Getter 13 | public class FadeInstruction implements Instruction { 14 | @Nullable 15 | private Color color; 16 | @Nullable 17 | private Time time; 18 | 19 | protected FadeInstruction() { 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/instruction/Instruction.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.instruction; 2 | 3 | import java.io.Serializable; 4 | 5 | public interface Instruction extends Serializable { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/camera/instruction/SetInstruction.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.camera.instruction; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import me.zimzaza4.geyserutils.common.camera.data.CameraPreset; 7 | import me.zimzaza4.geyserutils.common.camera.data.Ease; 8 | import me.zimzaza4.geyserutils.common.camera.data.Rot; 9 | import me.zimzaza4.geyserutils.common.util.Pos; 10 | import org.jetbrains.annotations.Nullable; 11 | 12 | @AllArgsConstructor 13 | @Builder 14 | @Getter 15 | public class SetInstruction implements Instruction { 16 | 17 | @Nullable 18 | private Ease ease; 19 | @Nullable 20 | private Pos pos; 21 | @Nullable 22 | private Rot rot; 23 | @Nullable 24 | private Pos facing; 25 | private CameraPreset preset; 26 | @Nullable 27 | private FadeInstruction fade; 28 | 29 | protected SetInstruction() { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/channel/GeyserUtilsChannels.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.channel; 2 | 3 | public class GeyserUtilsChannels { 4 | public static final String MAIN = "geyserutils:main"; 5 | } 6 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/form/element/NpcDialogueButton.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.form.element; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import lombok.experimental.Accessors; 6 | 7 | import java.util.List; 8 | 9 | @Setter 10 | @Getter 11 | @Accessors(fluent = true) 12 | public class NpcDialogueButton { 13 | private String text; 14 | private List commands; 15 | private ButtonMode mode; 16 | private boolean hasNextForm; 17 | 18 | public enum ButtonMode { 19 | BUTTON_MODE, 20 | ON_ENTER, 21 | ON_EXIT 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/manager/PacketManager.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.manager; 2 | 3 | 4 | import com.fasterxml.jackson.annotation.JsonAutoDetect; 5 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 6 | import com.fasterxml.jackson.annotation.PropertyAccessor; 7 | import com.fasterxml.jackson.core.JsonProcessingException; 8 | import com.fasterxml.jackson.databind.ObjectMapper; 9 | import me.zimzaza4.geyserutils.common.packet.CustomPayloadPacket; 10 | 11 | import java.io.IOException; 12 | 13 | public class PacketManager { 14 | 15 | private final ObjectMapper objectMapper; 16 | 17 | public PacketManager() { 18 | objectMapper = new ObjectMapper(); 19 | objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.EVERYTHING, JsonTypeInfo.As.PROPERTY); 20 | objectMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY); 21 | } 22 | 23 | 24 | public byte[] encodePacket(CustomPayloadPacket packet) { 25 | 26 | try { 27 | return objectMapper.writeValueAsBytes(packet); 28 | } catch (JsonProcessingException e) { 29 | throw new RuntimeException(e); 30 | } 31 | 32 | } 33 | 34 | public CustomPayloadPacket decodePacket(byte[] bytes) { 35 | try { 36 | return objectMapper.readValue(bytes, CustomPayloadPacket.class); 37 | } catch (IOException e) { 38 | throw new RuntimeException(e); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/AnimateEntityCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import me.zimzaza4.geyserutils.common.animation.Animation; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | @Setter 11 | @Getter 12 | public class AnimateEntityCustomPayloadPacket extends CustomPayloadPacket { 13 | private String animation; 14 | private String nextState; 15 | private String stopExpression; 16 | private int stopExpressionVersion; 17 | private String controller; 18 | private float blendOutTime; 19 | private List entityJavaIds = new ArrayList<>(); 20 | 21 | public void parseFromAnimation(Animation ani) { 22 | this.animation = ani.getAnimation(); 23 | this.nextState = ani.getNextState(); 24 | this.blendOutTime = ani.getBlendOutTime(); 25 | this.stopExpression = ani.getStopExpression(); 26 | this.controller = ani.getController(); 27 | this.stopExpressionVersion = ani.getStopExpressionVersion(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/BundlePacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Getter 14 | @Setter 15 | public class BundlePacket extends CustomPayloadPacket { 16 | 17 | private List packets = new ArrayList<>(); 18 | 19 | public void addPacket(CustomPayloadPacket packet) { 20 | this.packets.add(packet); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CameraInstructionCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import me.zimzaza4.geyserutils.common.camera.instruction.Instruction; 6 | 7 | @Setter 8 | @Getter 9 | public class CameraInstructionCustomPayloadPacket extends CustomPayloadPacket { 10 | private Instruction instruction; 11 | } 12 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CameraLockCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Getter 9 | @AllArgsConstructor 10 | @NoArgsConstructor 11 | public class CameraLockCustomPayloadPacket extends CustomPayloadPacket { 12 | boolean lock; 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CameraShakeCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class CameraShakeCustomPayloadPacket extends CustomPayloadPacket { 11 | 12 | float intensity; 13 | float duration; 14 | int type; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomEntityDataPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | @Getter 11 | @Setter 12 | public class CustomEntityDataPacket extends CustomPayloadPacket { 13 | private int entityId; 14 | private Float height; 15 | private Float width; 16 | private Float scale; 17 | private Integer color; 18 | private Integer variant; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomEntityPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class CustomEntityPacket extends CustomPayloadPacket { 13 | private int entityId; 14 | private String identifier; 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomParticleEffectPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import me.zimzaza4.geyserutils.common.particle.CustomParticle; 8 | import me.zimzaza4.geyserutils.common.util.Pos; 9 | 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | @Getter 13 | @Setter 14 | public class CustomParticleEffectPayloadPacket extends CustomPayloadPacket { 15 | private CustomParticle particle; 16 | private Pos pos; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | 4 | public abstract class CustomPayloadPacket { 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomSkinPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class CustomSkinPayloadPacket extends CustomPayloadPacket { 13 | private int entityId; 14 | private String skinId; 15 | } 16 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/EntityPropertyPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class EntityPropertyPacket extends CustomPayloadPacket { 13 | private int entityId; 14 | 15 | private String identifier; 16 | private T value; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/EntityPropertyRegisterPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | 8 | @Setter 9 | @Getter 10 | @AllArgsConstructor 11 | @NoArgsConstructor 12 | public class EntityPropertyRegisterPacket extends CustomPayloadPacket { 13 | private int entityId; 14 | 15 | private String identifier; 16 | private Class type; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/NpcDialogueFormDataCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import lombok.experimental.Accessors; 8 | import me.zimzaza4.geyserutils.common.form.element.NpcDialogueButton; 9 | 10 | import java.util.List; 11 | 12 | @AllArgsConstructor 13 | @NoArgsConstructor 14 | @Accessors(fluent = true) 15 | @Getter 16 | @Setter 17 | public class NpcDialogueFormDataCustomPayloadPacket extends CustomPayloadPacket { 18 | 19 | String formId; 20 | String title; 21 | String dialogue; 22 | String skinData; 23 | int bindEntity; 24 | List buttons; 25 | String action; 26 | boolean hasNextForm; 27 | 28 | } 29 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/packet/NpcFormResponseCustomPayloadPacket.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.packet; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @AllArgsConstructor 8 | @NoArgsConstructor 9 | @Getter 10 | public class NpcFormResponseCustomPayloadPacket extends CustomPayloadPacket { 11 | String formId; 12 | int buttonId; 13 | } 14 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/particle/CustomParticle.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.particle; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | import lombok.Setter; 7 | import lombok.experimental.Accessors; 8 | import me.zimzaza4.geyserutils.common.util.Pos; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | @Accessors(fluent = true) 14 | @Getter 15 | @Setter 16 | public class CustomParticle { 17 | private Pos position; 18 | private String identifier; 19 | @Nullable 20 | private String molangVariablesJson; 21 | } 22 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/util/CustomPayloadPacketUtils.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.util; 2 | 3 | public class CustomPayloadPacketUtils { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /common/src/main/java/me/zimzaza4/geyserutils/common/util/Pos.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.common.util; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | import lombok.experimental.Accessors; 7 | 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | @Accessors(fluent = true) 11 | @Data 12 | public class Pos { 13 | float x; 14 | float y; 15 | float z; 16 | } 17 | -------------------------------------------------------------------------------- /geyser/libs/Geyser-Standalone.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GeyserExtensionists/GeyserUtils/4e1cd6cbf7847bedd987a85a95fe1478ba7678b2/geyser/libs/Geyser-Standalone.jar -------------------------------------------------------------------------------- /geyser/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | me.zimzaza4 8 | GeyserUtils 9 | 1.0-SNAPSHOT 10 | 11 | 12 | geyserutils-geyser 13 | 14 | 15 | 17 16 | 17 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | org.apache.maven.plugins 24 | maven-shade-plugin 25 | 3.4.1 26 | 27 | 28 | package 29 | 30 | shade 31 | 32 | 33 | false 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | src/main/resources 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | opencollab-release-repo 51 | https://repo.opencollab.dev/maven-releases/ 52 | 53 | true 54 | 55 | 56 | true 57 | 58 | 59 | 60 | opencollab-snapshot-repo 61 | https://repo.opencollab.dev/maven-snapshots/ 62 | 63 | false 64 | 65 | 66 | true 67 | 68 | 69 | 70 | sonatype-oss-snapshots1 71 | https://s01.oss.sonatype.org/content/repositories/snapshots/ 72 | 73 | 74 | jitpack.io 75 | https://jitpack.io 76 | 77 | 78 | 79 | 80 | org.geysermc.geyser 81 | core 82 | 2.6.0-SNAPSHOT 83 | system 84 | ${project.basedir}/libs/Geyser-Standalone.jar 85 | 86 | 87 | me.zimzaza4 88 | geyserutils-common 89 | 1.0-SNAPSHOT 90 | compile 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /geyser/src/main/java/me/zimzaza4/geyserutils/geyser/GeyserUtils.java: -------------------------------------------------------------------------------- 1 | package me.zimzaza4.geyserutils.geyser; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.google.gson.JsonElement; 6 | import com.google.gson.JsonParser; 7 | import lombok.Getter; 8 | import me.zimzaza4.geyserutils.common.camera.data.CameraPreset; 9 | import me.zimzaza4.geyserutils.common.camera.instruction.ClearInstruction; 10 | import me.zimzaza4.geyserutils.common.camera.instruction.FadeInstruction; 11 | import me.zimzaza4.geyserutils.common.camera.instruction.SetInstruction; 12 | import me.zimzaza4.geyserutils.common.channel.GeyserUtilsChannels; 13 | import me.zimzaza4.geyserutils.common.form.element.NpcDialogueButton; 14 | import me.zimzaza4.geyserutils.common.manager.PacketManager; 15 | import me.zimzaza4.geyserutils.common.packet.*; 16 | import me.zimzaza4.geyserutils.geyser.form.NpcDialogueForm; 17 | import me.zimzaza4.geyserutils.geyser.form.NpcDialogueForms; 18 | import me.zimzaza4.geyserutils.geyser.form.element.Button; 19 | import me.zimzaza4.geyserutils.geyser.replace.JavaAddEntityTranslatorReplace; 20 | import me.zimzaza4.geyserutils.geyser.translator.NPCFormResponseTranslator; 21 | import me.zimzaza4.geyserutils.geyser.util.Converter; 22 | import me.zimzaza4.geyserutils.geyser.util.DeltaUtils; 23 | import me.zimzaza4.geyserutils.geyser.util.ReflectionUtils; 24 | import org.cloudburstmc.nbt.NbtMap; 25 | import org.cloudburstmc.nbt.NbtType; 26 | import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 27 | import org.cloudburstmc.protocol.bedrock.data.skin.ImageData; 28 | import org.cloudburstmc.protocol.bedrock.data.skin.SerializedSkin; 29 | import org.cloudburstmc.protocol.bedrock.packet.*; 30 | import org.geysermc.event.subscribe.Subscribe; 31 | import org.geysermc.geyser.GeyserImpl; 32 | import org.geysermc.geyser.api.bedrock.camera.CameraShake; 33 | import org.geysermc.geyser.api.connection.GeyserConnection; 34 | import org.geysermc.geyser.api.event.bedrock.SessionDisconnectEvent; 35 | import org.geysermc.geyser.api.event.bedrock.SessionLoginEvent; 36 | import org.geysermc.geyser.api.event.lifecycle.GeyserDefineCommandsEvent; 37 | import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent; 38 | import org.geysermc.geyser.api.extension.Extension; 39 | import org.geysermc.geyser.api.skin.Cape; 40 | import org.geysermc.geyser.api.skin.Skin; 41 | import org.geysermc.geyser.api.skin.SkinData; 42 | import org.geysermc.geyser.api.skin.SkinGeometry; 43 | import org.geysermc.geyser.entity.EntityDefinition; 44 | import org.geysermc.geyser.entity.properties.GeyserEntityProperties; 45 | import org.geysermc.geyser.entity.type.Entity; 46 | import org.geysermc.geyser.entity.type.player.PlayerEntity; 47 | import org.geysermc.geyser.registry.Registries; 48 | import org.geysermc.geyser.session.GeyserSession; 49 | import org.geysermc.geyser.util.DimensionUtils; 50 | import org.geysermc.mcprotocollib.network.Session; 51 | import org.geysermc.mcprotocollib.network.event.session.PacketSendingEvent; 52 | import org.geysermc.mcprotocollib.network.event.session.SessionAdapter; 53 | import org.geysermc.mcprotocollib.network.packet.Packet; 54 | import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundCustomPayloadPacket; 55 | import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket; 56 | import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundAddEntityPacket; 57 | import org.jetbrains.annotations.NotNull; 58 | 59 | import javax.imageio.ImageIO; 60 | import java.io.ByteArrayInputStream; 61 | import java.io.File; 62 | import java.io.FileReader; 63 | import java.io.IOException; 64 | import java.nio.charset.StandardCharsets; 65 | import java.nio.file.Files; 66 | import java.util.*; 67 | import java.util.concurrent.ConcurrentHashMap; 68 | import java.util.concurrent.Executors; 69 | import java.util.concurrent.ScheduledExecutorService; 70 | import java.util.concurrent.TimeUnit; 71 | 72 | public class GeyserUtils implements Extension { 73 | 74 | 75 | public static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); 76 | private static final Map>>> properties = new HashMap<>(); 77 | @Getter 78 | public static PacketManager packetManager = new PacketManager(); 79 | public static List REGISTERED_ENTITIES = new ArrayList<>(); 80 | public static boolean GEYSER_LOADED = false; 81 | @Getter 82 | public static Map LOADED_SKIN_DATA = new HashMap<>(); 83 | @Getter 84 | public static Map LOADED_ENTITY_DEFINITIONS = new HashMap<>(); 85 | @Getter 86 | public static Map> CUSTOM_ENTITIES = new ConcurrentHashMap<>(); 87 | static Cape EMPTY_CAPE = new Cape("", "no-cape", new byte[0], true); 88 | private static List ENTITIES_WAIT_FOR_LOAD = new ArrayList<>(); 89 | @Getter 90 | private static GeyserUtils instance; 91 | 92 | public GeyserUtils() { 93 | instance = this; 94 | } 95 | 96 | // the static here is crazy ;( 97 | private static GeyserEntityProperties getProperties(String id) { 98 | if (!properties.containsKey(id)) return null; 99 | 100 | GeyserEntityProperties.Builder builder = new GeyserEntityProperties.Builder(); 101 | List>> pairs = properties.get(id); 102 | pairs.forEach(p -> { 103 | // only bool, float and int support for now 104 | if (p.getValue() == Boolean.class) builder.addBoolean(p.getKey()); 105 | else if (p.getValue() == Float.class) builder.addFloat(p.getKey()); 106 | else if (p.getValue() == Integer.class) builder.addInt(p.getKey()); 107 | else instance.logger().info("Found unknown property: " + p.getKey()); 108 | }); 109 | 110 | return builder.build(); 111 | } 112 | 113 | private static boolean containsProperty(String entityId, String identifier) { 114 | if (!properties.containsKey(entityId)) return false; 115 | 116 | return properties.get(entityId).stream().anyMatch(p -> p.getKey().equalsIgnoreCase(identifier)); 117 | } 118 | 119 | public static void addProperty(String entityId, String identifier, Class type) { 120 | if (containsProperty(entityId, identifier)) return; 121 | 122 | List>> pairs = properties.getOrDefault(entityId, new ArrayList<>()); 123 | pairs.add(new AbstractMap.SimpleEntry<>(identifier, type)); 124 | 125 | if (properties.containsKey(entityId)) properties.replace(entityId, pairs); 126 | else properties.put(entityId, pairs); 127 | } 128 | 129 | public static void registerProperties(String entityId) { 130 | if (GEYSER_LOADED) { 131 | registerProperties(entityId); 132 | } 133 | ENTITIES_WAIT_FOR_LOAD.add(entityId); 134 | } 135 | 136 | public static void registerPropertiesForGeyser(String entityId) { 137 | 138 | GeyserEntityProperties entityProperties = getProperties(entityId); 139 | if (entityProperties == null) return; 140 | properties.values().stream() 141 | .flatMap(List::stream) 142 | .map(Map.Entry::getKey) 143 | .forEach(id -> { 144 | Registries.BEDROCK_ENTITY_PROPERTIES.get().removeIf(i -> i.containsKey(id)); 145 | }); 146 | 147 | 148 | Registries.BEDROCK_ENTITY_PROPERTIES.get().add(entityProperties.toNbtMap(entityId)); 149 | 150 | EntityDefinition old = LOADED_ENTITY_DEFINITIONS.get(entityId); 151 | LOADED_ENTITY_DEFINITIONS.replace(entityId, new EntityDefinition(old.factory(), old.entityType(), old.identifier(), 152 | old.width(), old.height(), old.offset(), entityProperties, old.translators())); 153 | 154 | instance.logger().info("Defined entity: " + entityId + " in registry."); 155 | } 156 | 157 | public static void addCustomEntity(String id) { 158 | /* 159 | LOADED_ENTITY_DEFINITIONS.put(id, 160 | EntityDefinition.builder() 161 | .identifier(EntityIdentifier.builder().identifier(id) 162 | .summonable(true) 163 | .spawnEgg(false).build()) 164 | .height(0.6f) 165 | .width(0.6f) 166 | .build()); 167 | 168 | */ 169 | if (GEYSER_LOADED) { 170 | registerEntityToGeyser(id); 171 | } 172 | REGISTERED_ENTITIES.add(id); 173 | } 174 | 175 | public static void registerEntityToGeyser(String id) { 176 | NbtMap registry = Registries.BEDROCK_ENTITY_IDENTIFIERS.get(); 177 | List idList = new ArrayList<>(registry.getList("idlist", NbtType.COMPOUND)); 178 | idList.add(NbtMap.builder() 179 | .putString("id", id) 180 | .putString("bid", "") 181 | .putBoolean("hasspawnegg", false) 182 | .putInt("rid", idList.size() + 1) 183 | .putBoolean("summonable", false).build() 184 | ); 185 | 186 | Registries.BEDROCK_ENTITY_IDENTIFIERS.set(NbtMap.builder() 187 | .putList("idlist", NbtType.COMPOUND, idList).build() 188 | ); 189 | 190 | EntityDefinition def = EntityDefinition.builder(null) 191 | .height(0.1f).width(0.1f).identifier(id).registeredProperties(getProperties(id)).build(); 192 | 193 | LOADED_ENTITY_DEFINITIONS.put(id, def); 194 | } 195 | 196 | @NotNull 197 | private static AnimateEntityPacket getAnimateEntityPacket(AnimateEntityCustomPayloadPacket animateEntityCustomPayloadPacket) { 198 | AnimateEntityPacket animateEntityPacket = new AnimateEntityPacket(); 199 | animateEntityPacket.setAnimation(animateEntityCustomPayloadPacket.getAnimation()); 200 | animateEntityPacket.setController(animateEntityCustomPayloadPacket.getController()); 201 | animateEntityPacket.setBlendOutTime(animateEntityCustomPayloadPacket.getBlendOutTime()); 202 | animateEntityPacket.setNextState(animateEntityCustomPayloadPacket.getNextState()); 203 | animateEntityPacket.setStopExpressionVersion(animateEntityCustomPayloadPacket.getStopExpressionVersion()); 204 | animateEntityPacket.setStopExpression(animateEntityCustomPayloadPacket.getStopExpression()); 205 | return animateEntityPacket; 206 | } 207 | 208 | public static void sendSkinPacket(GeyserSession session, PlayerEntity entity, SkinData skinData) { 209 | Skin skin = skinData.skin(); 210 | Cape cape = skinData.cape(); 211 | SkinGeometry geometry = skinData.geometry(); 212 | 213 | if (entity.getUuid().equals(session.getPlayerEntity().getUuid())) { 214 | PlayerListPacket.Entry updatedEntry = buildEntryManually( 215 | session, 216 | entity.getUuid(), 217 | entity.getUsername(), 218 | entity.getGeyserId(), 219 | skin, 220 | cape, 221 | geometry 222 | ); 223 | 224 | PlayerListPacket playerAddPacket = new PlayerListPacket(); 225 | playerAddPacket.setAction(PlayerListPacket.Action.ADD); 226 | playerAddPacket.getEntries().add(updatedEntry); 227 | session.sendUpstreamPacket(playerAddPacket); 228 | } else { 229 | PlayerSkinPacket packet = new PlayerSkinPacket(); 230 | packet.setUuid(entity.getUuid()); 231 | packet.setOldSkinName(""); 232 | packet.setNewSkinName(skin.textureUrl()); 233 | packet.setSkin(getSkin(skin.textureUrl(), skin, cape, geometry)); 234 | packet.setTrustedSkin(true); 235 | session.sendUpstreamPacket(packet); 236 | } 237 | } 238 | 239 | public static PlayerListPacket.Entry buildEntryManually(GeyserSession session, UUID uuid, String username, long geyserId, 240 | Skin skin, 241 | Cape cape, 242 | SkinGeometry geometry) { 243 | SerializedSkin serializedSkin = getSkin(skin.textureUrl(), skin, cape, geometry); 244 | 245 | String xuid = ""; 246 | GeyserSession playerSession = GeyserImpl.getInstance().connectionByUuid(uuid); 247 | 248 | if (playerSession != null) { 249 | xuid = playerSession.getAuthData().xuid(); 250 | } 251 | 252 | PlayerListPacket.Entry entry; 253 | if (session.getPlayerEntity().getUuid().equals(uuid)) { 254 | entry = new PlayerListPacket.Entry(session.getAuthData().uuid()); 255 | } else { 256 | entry = new PlayerListPacket.Entry(uuid); 257 | } 258 | 259 | entry.setName(username); 260 | entry.setEntityId(geyserId); 261 | entry.setSkin(serializedSkin); 262 | entry.setXuid(xuid); 263 | entry.setPlatformChatId(""); 264 | entry.setTeacher(false); 265 | entry.setTrustedSkin(true); 266 | return entry; 267 | } 268 | 269 | private static SerializedSkin getSkin(String skinId, Skin skin, Cape cape, SkinGeometry geometry) { 270 | 271 | try { 272 | ImageData image = ImageData.from(ImageIO.read(new ByteArrayInputStream(skin.skinData()))); 273 | return SerializedSkin.of(skinId, "", geometry.geometryName(), image, Collections.emptyList(), ImageData.of(cape.capeData()), geometry.geometryData(), "", true, false, false, cape.capeId(), skinId); 274 | } catch (IOException e) { 275 | throw new RuntimeException(e); 276 | } 277 | } 278 | 279 | public static Cape getEmptyCapeData() { 280 | return EMPTY_CAPE; 281 | } 282 | 283 | private static int getColor(int argb) { 284 | int r = (argb >> 16) & 0xFF; 285 | int g = (argb >> 8) & 0xFF; 286 | int b = argb & 0xFF; 287 | 288 | double[] colorLab = DeltaUtils.rgbToLab(r, g, b); 289 | 290 | List colors = Arrays.asList( 291 | new int[]{249, 255, 254}, // 0: White 292 | new int[]{249, 128, 29}, // 1: Orange 293 | new int[]{199, 78, 189}, // 2: Magenta 294 | new int[]{58, 179, 218}, // 3: Light Blue 295 | new int[]{254, 216, 61}, // 4: Yellow 296 | new int[]{128, 199, 31}, // 5: Lime 297 | new int[]{243, 139, 170}, // 6: Pink 298 | new int[]{71, 79, 82}, // 7: Gray 299 | new int[]{159, 157, 151}, // 8: Light Gray 300 | new int[]{22, 156, 156}, // 9: Cyan 301 | new int[]{137, 50, 184}, // 10: Purple 302 | new int[]{60, 68, 170}, // 11: Blue 303 | new int[]{131, 84, 50}, // 12: Brown 304 | new int[]{94, 124, 22}, // 13: Green 305 | new int[]{176, 46, 38}, // 14: Red 306 | new int[]{29, 29, 33} // 15: Black 307 | ); 308 | 309 | int closestColorIndex = -1; 310 | double minDeltaE = Double.MAX_VALUE; 311 | 312 | for (int i = 0; i < colors.size(); i++) { 313 | int[] rgb = colors.get(i); 314 | double[] lab = DeltaUtils.rgbToLab(rgb[0], rgb[1], rgb[2]); 315 | double deltaE = DeltaUtils.calculateDeltaE(colorLab, lab); 316 | if (deltaE < minDeltaE) { 317 | minDeltaE = deltaE; 318 | closestColorIndex = i; 319 | } 320 | } 321 | 322 | return closestColorIndex; 323 | } 324 | 325 | @Subscribe 326 | public void onEnable(GeyserPostInitializeEvent event) { 327 | Registries.BEDROCK_PACKET_TRANSLATORS.register(NpcRequestPacket.class, new NPCFormResponseTranslator()); 328 | loadSkins(); 329 | ReflectionUtils.init(); 330 | CameraPreset.load(); 331 | 332 | replaceTranslator(); 333 | GEYSER_LOADED = true; 334 | for (String registeredEntity : REGISTERED_ENTITIES) { 335 | registerEntityToGeyser(registeredEntity); 336 | } 337 | for (String id : ENTITIES_WAIT_FOR_LOAD) { 338 | registerPropertiesForGeyser(id); 339 | } 340 | logger().info("Defined " + LOADED_ENTITY_DEFINITIONS.size() + " entities"); 341 | MountFix.start(); 342 | } 343 | 344 | public void replaceTranslator() { 345 | Registries.JAVA_PACKET_TRANSLATORS 346 | .register(ClientboundAddEntityPacket.class, new JavaAddEntityTranslatorReplace()); 347 | } 348 | 349 | @Subscribe 350 | public void onLoadCommand(GeyserDefineCommandsEvent event) { 351 | 352 | } 353 | 354 | public void loadSkins() { 355 | LOADED_SKIN_DATA.clear(); 356 | File folder = this.dataFolder().resolve("skins").toFile(); 357 | if (!folder.exists()) { 358 | folder.mkdirs(); 359 | } 360 | for (File file : folder.listFiles()) { 361 | if (file.isDirectory()) { 362 | File textureFile = null; 363 | File geometryFile = null; 364 | 365 | for (File folderFile : file.listFiles()) { 366 | if (folderFile.getName().endsWith(".png")) { 367 | textureFile = folderFile; 368 | } 369 | if (folderFile.getName().endsWith(".json")) { 370 | geometryFile = folderFile; 371 | } 372 | 373 | } 374 | 375 | loadSkin(file.getName(), geometryFile, textureFile); 376 | 377 | 378 | } 379 | } 380 | } 381 | 382 | public void loadSkin(String skinId, File geometryFile, File textureFile) { 383 | try { 384 | Skin skin = new Skin(skinId, Files.readAllBytes(textureFile.toPath()), false); 385 | 386 | String geoId = ""; 387 | JsonElement json = new JsonParser().parse(new FileReader(geometryFile)); 388 | for (JsonElement element : json.getAsJsonObject().get("minecraft:geometry").getAsJsonArray()) { 389 | if (element.isJsonObject() && element.getAsJsonObject().has("description")) { 390 | geoId = element.getAsJsonObject().get("description").getAsJsonObject().get("identifier").getAsString(); 391 | break; 392 | } 393 | } 394 | String geoName = "{\"geometry\" :{\"default\" :\"" + geoId + "\"}}"; 395 | SkinGeometry geometry = new SkinGeometry(geoName, Files.readString(geometryFile.toPath())); 396 | LOADED_SKIN_DATA.put(skinId, new SkinData(skin, getEmptyCapeData(), geometry)); 397 | this.logger().info("Loaded skin: " + skinId + "| geo:" + geoName); 398 | } catch (Exception e) { 399 | e.printStackTrace(); 400 | } 401 | } 402 | 403 | @Subscribe 404 | public void onSessionJoin(SessionLoginEvent event) { 405 | CUSTOM_ENTITIES.put(event.connection(), CacheBuilder.newBuilder().expireAfterWrite(30, TimeUnit.SECONDS).build()); 406 | if (event.connection() instanceof GeyserSession session) { 407 | registerPacketListener(session); 408 | } 409 | } 410 | 411 | @Subscribe 412 | public void onSessionQuit(SessionDisconnectEvent event) { 413 | CUSTOM_ENTITIES.remove(event.connection()); 414 | } 415 | 416 | public void registerPacketListener(GeyserSession session) { 417 | 418 | scheduler.schedule(() -> { 419 | if (session.getDownstream() == null) { 420 | registerPacketListener(session); 421 | return; 422 | } 423 | 424 | session.getDownstream().getSession().addListener(new SessionAdapter() { 425 | 426 | @Override 427 | public void packetSending(PacketSendingEvent event) { 428 | Packet packet = event.getPacket(); 429 | if (packet instanceof ServerboundCustomPayloadPacket payloadPacket) { 430 | if (ReflectionUtils.getChannel(payloadPacket).toString().equals("minecraft:register")) { 431 | String channels = new String(payloadPacket.getData(), StandardCharsets.UTF_8); 432 | channels = channels + "\0" + GeyserUtilsChannels.MAIN; 433 | event.setPacket(ReflectionUtils.buildServerboundPayloadPacket("minecraft:register", channels.getBytes(StandardCharsets.UTF_8))); 434 | } 435 | } 436 | } 437 | 438 | @Override 439 | public void packetReceived(Session tcpSession, Packet packet) { 440 | if (packet instanceof ClientboundCustomPayloadPacket payloadPacket) { 441 | if (ReflectionUtils.getChannel(payloadPacket).toString().equals(GeyserUtilsChannels.MAIN)) { 442 | CustomPayloadPacket customPacket = packetManager.decodePacket(payloadPacket.getData()); 443 | handleCustomPacket(session, customPacket); 444 | } 445 | } 446 | } 447 | }); 448 | }, 80, TimeUnit.MILLISECONDS); 449 | } 450 | 451 | private void handleCustomPacket(GeyserSession session, CustomPayloadPacket customPacket) { 452 | if (customPacket instanceof BundlePacket bundlePacket) { 453 | bundlePacket.getPackets().forEach(p -> handleCustomPacket(session, p)); 454 | } else if (customPacket instanceof CameraShakeCustomPayloadPacket cameraShakePacket) { 455 | session.camera().shakeCamera(cameraShakePacket.getIntensity(), cameraShakePacket.getDuration(), CameraShake.values()[cameraShakePacket.getType()]); 456 | } else if (customPacket instanceof NpcDialogueFormDataCustomPayloadPacket formData) { 457 | 458 | if (formData.action().equals("CLOSE")) { 459 | NpcDialogueForm openForm = NpcDialogueForms.getOpenNpcDialogueForms(session); 460 | if (openForm != null) { 461 | openForm.close(session); 462 | } 463 | return; 464 | } 465 | 466 | NpcDialogueForm form = new NpcDialogueForm(); 467 | form.title(formData.title()) 468 | .dialogue(formData.dialogue()) 469 | .bindEntity(session.getEntityCache().getEntityByJavaId(formData.bindEntity())) 470 | .hasNextForm(formData.hasNextForm()); 471 | 472 | if (formData.skinData() != null) { 473 | form.skinData(formData.skinData()); 474 | } 475 | 476 | 477 | List