├── .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