@starktma/minecraft-utils 1.0.1 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,194 @@
1
+ import {
2
+ system,
3
+ world,
4
+ Player,
5
+ ButtonState,
6
+ EntityEquippableComponent,
7
+ EntityInventoryComponent,
8
+ EquipmentSlot,
9
+ InputButton,
10
+ ItemStack,
11
+ } from "@minecraft/server";
12
+ import { NAMESPACE } from "./constants";
13
+
14
+ type EventCallback<T = CustomPlayer> = (player: T) => void;
15
+
16
+ enum CustomPlayerEvents {
17
+ Tick = "tick",
18
+ JumpStart = "jumpStart",
19
+ JumpHold = "jumpHold",
20
+ JumpEnd = "jumpEnd",
21
+ SneakStart = "sneakStart",
22
+ SneakHold = "sneakHold",
23
+ SneakEnd = "sneakEnd",
24
+ }
25
+
26
+ enum PropertyIDs {
27
+ OriginalNameTag = `${NAMESPACE}:original_name_tag`,
28
+ }
29
+
30
+ type PlayerEventType = CustomPlayerEvents | string;
31
+
32
+ class EventGroup<T = CustomPlayer> {
33
+ private callbacks = new Map<PlayerEventType, EventCallback<T>[]>();
34
+
35
+ constructor() {
36
+ // Initialize with core events
37
+ Object.values(CustomPlayerEvents).forEach((event) => {
38
+ this.callbacks.set(event, []);
39
+ });
40
+ }
41
+
42
+ private run(callbacks: EventCallback<T>[], player: T) {
43
+ for (const cb of callbacks) cb(player);
44
+ }
45
+
46
+ trigger(type: PlayerEventType, player: T) {
47
+ const callbacks = this.callbacks.get(type);
48
+ if (callbacks) {
49
+ this.run(callbacks, player);
50
+ }
51
+ }
52
+
53
+ on(type: PlayerEventType, callback: EventCallback<T>) {
54
+ if (!this.callbacks.has(type)) {
55
+ this.callbacks.set(type, []);
56
+ }
57
+ this.callbacks.get(type)!.push(callback);
58
+ }
59
+
60
+ // Simple way to remove listeners
61
+ off(type: PlayerEventType, callback: EventCallback<T>) {
62
+ const callbacks = this.callbacks.get(type);
63
+ if (callbacks) {
64
+ const index = callbacks.indexOf(callback);
65
+ if (index > -1) {
66
+ callbacks.splice(index, 1);
67
+ }
68
+ }
69
+ }
70
+ }
71
+
72
+ class CustomPlayer {
73
+ player: Player;
74
+ stateTick = 0;
75
+ JumpTick = 0;
76
+ SneakTick = 0;
77
+
78
+ constructor(player: Player) {
79
+ this.player = player;
80
+ this.reset();
81
+ }
82
+
83
+ get equippableComponent() {
84
+ return this.player.getComponent(EntityEquippableComponent.componentId) as EntityEquippableComponent;
85
+ }
86
+
87
+ get inventoryComponent() {
88
+ return this.player.getComponent(EntityInventoryComponent.componentId) as EntityInventoryComponent;
89
+ }
90
+
91
+ getEquippedItem(): ItemStack | undefined {
92
+ return this.equippableComponent.getEquipment(EquipmentSlot.Mainhand);
93
+ }
94
+
95
+ reset() {
96
+ this.player.nameTag = (this.player.getDynamicProperty(PropertyIDs.OriginalNameTag) as string | undefined) ?? this.player.nameTag;
97
+ this.stateTick = 0;
98
+ this.JumpTick = 0;
99
+ this.player.camera.clear();
100
+ }
101
+
102
+ tick() {
103
+ this.stateTick++;
104
+
105
+ if (this.player.inputInfo.getButtonState(InputButton.Jump) === ButtonState.Pressed && !this.player.isOnGround) {
106
+ this.JumpTick++;
107
+ } else if (this.JumpTick > 0) {
108
+ this.JumpTick = -1;
109
+ } else {
110
+ this.JumpTick = 0;
111
+ }
112
+
113
+ if (this.player.inputInfo.getButtonState(InputButton.Sneak) === ButtonState.Pressed) {
114
+ this.SneakTick++;
115
+ } else if (this.SneakTick > 0) {
116
+ this.SneakTick = -1;
117
+ } else {
118
+ this.SneakTick = 0;
119
+ }
120
+ }
121
+ }
122
+
123
+ class PlayerManager<T extends CustomPlayer = CustomPlayer> {
124
+ private players = new Map<string, T>();
125
+ private events = new Map<string, EventGroup<T>>();
126
+
127
+ protected constructor() {
128
+ world.afterEvents.playerSpawn.subscribe(({ player, initialSpawn }) => {
129
+ const id = player.id;
130
+ const existing = this.getPlayer(id);
131
+
132
+ if (initialSpawn || !existing) {
133
+ this.addPlayer(player);
134
+ } else {
135
+ existing.reset();
136
+ }
137
+ });
138
+
139
+ world.afterEvents.playerLeave.subscribe(({ playerId }) => {
140
+ this.removePlayer(playerId);
141
+ });
142
+
143
+ world.afterEvents.worldLoad.subscribe(() => {
144
+ world.getAllPlayers().forEach((player) => this.addPlayer(player));
145
+ });
146
+
147
+ world.afterEvents.worldLoad.subscribe(() => {
148
+ system.runInterval(() => {
149
+ this.tick();
150
+ });
151
+ });
152
+ }
153
+
154
+ protected createPlayerManager(player: Player): T {
155
+ return new CustomPlayer(player) as T;
156
+ }
157
+
158
+ getPlayer(id: string) {
159
+ return this.players.get(id);
160
+ }
161
+
162
+ removePlayer(id: string) {
163
+ this.players.delete(id);
164
+ }
165
+
166
+ addPlayer(player: Player) {
167
+ if (this.players.has(player.id)) return;
168
+ this.players.set(player.id, this.createPlayerManager(player));
169
+ }
170
+
171
+ registerEvents(eventID: string) {
172
+ const eventGroup = new EventGroup<T>();
173
+ this.events.set(eventID, eventGroup);
174
+ return { event: eventGroup };
175
+ }
176
+
177
+ getEvents(eventID: string) {
178
+ return this.events.get(eventID);
179
+ }
180
+
181
+ tick() {
182
+ for (const manager of this.players.values()) {
183
+ const { player } = manager;
184
+ if (!player.isValid) continue;
185
+
186
+ manager.tick();
187
+ this.events.forEach((eventGroup) => {
188
+ eventGroup.trigger(CustomPlayerEvents.Tick, manager);
189
+ });
190
+ }
191
+ }
192
+ }
193
+
194
+ export { CustomPlayerEvents, PropertyIDs, CustomPlayer, PlayerManager };
package/tsconfig.json CHANGED
@@ -1,22 +1,22 @@
1
- {
2
- "compilerOptions": {
3
- "module": "esnext",
4
- "moduleResolution": "bundler",
5
- "target": "ES2022",
6
- "esModuleInterop": true,
7
- "sourceMap": true,
8
- "strict": true,
9
- "forceConsistentCasingInFileNames": true,
10
- "resolveJsonModule": true,
11
-
12
- "composite": true,
13
- "declaration": true,
14
- "declarationMap": true,
15
- "incremental": true,
16
- "skipLibCheck": true,
17
- "noEmitOnError": true,
18
- "typeRoots": ["./node_modules/@types"],
19
- "outDir": "./dist",
20
- "rootDir": "./src"
21
- }
22
- }
1
+ {
2
+ "compilerOptions": {
3
+ "module": "esnext",
4
+ "moduleResolution": "bundler",
5
+ "target": "ES2022",
6
+ "esModuleInterop": true,
7
+ "sourceMap": true,
8
+ "strict": true,
9
+ "forceConsistentCasingInFileNames": true,
10
+ "resolveJsonModule": true,
11
+
12
+ "composite": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "incremental": true,
16
+ "skipLibCheck": true,
17
+ "noEmitOnError": true,
18
+ "typeRoots": ["./node_modules/@types"],
19
+ "outDir": "./dist",
20
+ "rootDir": "./src"
21
+ }
22
+ }