@block_factory/lib 0.0.1 → 0.0.3

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,26 @@
1
+ import { IActionFormData } from "./FormAction";
2
+ import { IModalFormData } from "./FormModal";
3
+ import { IMessageFormData } from "./FormMessage";
4
+
5
+ export type AnyShowableForm =
6
+ | IActionFormData
7
+ | IModalFormData
8
+ | IMessageFormData;
9
+
10
+ export type AnyShowableCtor = new () => AnyShowableForm;
11
+
12
+ export interface IFormRegistration {
13
+ itemId: string;
14
+ formCtor: AnyShowableCtor;
15
+ }
16
+
17
+ /**
18
+ * Decorator factory used to bind a form class to an itemId.
19
+ *
20
+ * Usage:
21
+ * @RegisterForm("minecraft:stick")
22
+ * export class MyForm extends IMessageFormData {}
23
+ */
24
+ export declare function RegisterForm(
25
+ itemId: string
26
+ ): <T extends AnyShowableCtor>(formCtor: T) => void;
@@ -0,0 +1,43 @@
1
+ import { ItemUseAfterEvent, Player, world } from "@minecraft/server";
2
+ import { IActionFormData } from "./FormAction";
3
+ import { IModalFormData } from "./FormModal";
4
+ import { IMessageFormData } from "./FormMessage";
5
+
6
+ type AnyShowableForm = IActionFormData | IModalFormData | IMessageFormData;
7
+ type AnyShowableCtor = new () => AnyShowableForm;
8
+
9
+ export interface IFormRegistration {
10
+ itemId: string;
11
+ formCtor: AnyShowableCtor;
12
+ }
13
+
14
+ const registeredForms: IFormRegistration[] = [];
15
+
16
+ export function RegisterForm(itemId: string) {
17
+ return function <T extends AnyShowableCtor>(formCtor: T): void {
18
+ const i = registeredForms.findIndex(r => r.itemId === itemId);
19
+ if (i !== -1) registeredForms[i] = { itemId, formCtor };
20
+ else registeredForms.push({ itemId, formCtor });
21
+ };
22
+ }
23
+
24
+ function getFormForItem(itemId: string): AnyShowableCtor | undefined {
25
+ return registeredForms.find(r => r.itemId === itemId)?.formCtor;
26
+ }
27
+
28
+ world.afterEvents.itemUse.subscribe((event: ItemUseAfterEvent) => {
29
+ const player = event.source;
30
+ if (!(player instanceof Player)) return;
31
+
32
+ const item = event.itemStack;
33
+ if (!item) return;
34
+
35
+ const formCtor = getFormForItem(item.typeId);
36
+ if (!formCtor) return;
37
+
38
+ const form = new formCtor();
39
+
40
+ form.show(player).catch((e) => {
41
+ player.sendMessage(`§cForm error: ${String(e)}`);
42
+ });
43
+ });
package/util/Signal.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  export type Callback<T = void> = (data: T) => void;
2
+
2
3
  export declare class Signal<T = void> {
3
- private listeners;
4
+ private readonly listeners;
5
+
6
+ readonly count: number;
7
+
4
8
  connect(callback: Callback<T>): void;
5
- disconnect(callback?: Callback<T>): boolean;
6
- once(callback: Callback<T>): void;
9
+ disconnect(callback: Callback<T>): boolean;
10
+ clear(): void;
11
+ isConnected(callback: Callback<T>): boolean;
7
12
  emit(data: T): void;
8
13
  }
9
- //# sourceMappingURL=Signal.d.ts.map
package/util/Signal.ts CHANGED
@@ -1,72 +1,30 @@
1
- export type Callback<T = void> = (data: T) => void;
2
-
3
- /**
4
- * Signal class for event handling.
5
- * Allows connecting, disconnecting, and emitting events to listeners.
6
- *
7
- * @template T - Type of data passed to listeners.
8
- *
9
- * @example
10
- * ```typescript
11
- * import { Signal } from "./_lib/signal";
12
- *
13
- * interface ExampleEvent {
14
- * n: number;
15
- * s: string;
16
- * b: boolean;
17
- * }
18
- *
19
- * class TestObject {
20
- * example = new Signal<ExampleEvent>();
21
- * }
22
- *
23
- * const tstObject = new TestObject();
24
- * tstObject.example.connect(({n, s, b}) => console.warn(`n: ${n}, s: ${s}, b: ${b}`));
25
- *
26
- * for (let i = 0; i < 4; i++) {
27
- * let n: number = 1;
28
- * let s: string = "example";
29
- * let b: boolean = true;
30
- * tstObject.example.emit({n, s, b});
31
- * if (i === 3) { // Disconnect after 4th emit
32
- * tstObject.example.disconnect();
33
- * tstObject.example.emit({n, s, b});
34
- * }
35
- * }
36
- * ```
37
- */
1
+ export type Callback<T> = (data: T) => void;
38
2
 
39
3
  export class Signal<T = void> {
40
- private listeners: Set<Callback<T>> = new Set();
4
+ private readonly listeners = new Set<Callback<T>>();
5
+
6
+ public get count(): number {
7
+ return this.listeners.size;
8
+ }
41
9
 
42
- /** Connect a listener */
43
10
  public connect(callback: Callback<T>): void {
44
11
  this.listeners.add(callback);
45
12
  }
46
13
 
47
- /** Disconnect a listener */
48
- public disconnect(callback?: Callback<T>): boolean {
49
- if (callback) {
50
- this.listeners.delete(callback);
51
- return true;
52
- } else {
53
- this.listeners.clear();
54
- return false;
55
- }
14
+ public disconnect(callback: Callback<T>): boolean {
15
+ return this.listeners.delete(callback);
16
+ }
17
+
18
+ public clear(): void {
19
+ this.listeners.clear();
56
20
  }
57
21
 
58
- /** Connect a listener that runs only once */
59
- public once(callback: Callback<T>) {
60
- const wrapper: Callback<T> = (data) => {
61
- this.disconnect(wrapper);
62
- callback(data);
63
- };
64
- this.connect(wrapper);
22
+ public isConnected(callback: Callback<T>): boolean {
23
+ return this.listeners.has(callback);
65
24
  }
66
25
 
67
- /** Emit signal to all listeners */
68
- public emit(data: T) {
69
- for (const cb of [...this.listeners]) {
26
+ public emit(data: T): void {
27
+ for (const cb of Array.from(this.listeners)) {
70
28
  cb(data);
71
29
  }
72
30
  }
@@ -0,0 +1,4 @@
1
+ export declare namespace System {
2
+ const ProxyConstructor: (_instance: any, source: any) => any;
3
+ }
4
+ //# sourceMappingURL=System.d.ts.map
package/util/System.ts ADDED
@@ -0,0 +1,21 @@
1
+ export namespace System {
2
+ export const ProxyConstructor = ((_instance: any, source: any) => {
3
+ return new Proxy(_instance, {
4
+ get: (target, prop) => {
5
+ if (prop in target) return (target as any)[prop];
6
+ const v = (source as any)[prop];
7
+ return typeof v === "function" ? v.bind(source) : v;
8
+ },
9
+
10
+ set: (target, prop, value) => {
11
+ if (prop in target) { (target as any)[prop] = value; return true; }
12
+ (source as any)[prop] = value;
13
+ return true;
14
+ },
15
+
16
+ has: (target, prop) => prop in target || prop in source,
17
+ ownKeys: () => [...Reflect.ownKeys(source), ...Reflect.ownKeys(_instance)],
18
+ getOwnPropertyDescriptor: (_t, prop) => Object.getOwnPropertyDescriptor((prop in _instance ? _instance : source) as any, prop)
19
+ }) as any;
20
+ })
21
+ }
@@ -0,0 +1,9 @@
1
+ import { Container } from "@minecraft/server";
2
+ export type Inventory = ContainerWrapper & Container;
3
+ export declare class ContainerWrapper {
4
+ readonly source: Container;
5
+ private constructor();
6
+ static wrap(source: Container): Inventory;
7
+ reduce(slot: number, amount?: number): void;
8
+ }
9
+ //# sourceMappingURL=Container.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { Container, ItemStack} from "@minecraft/server";
2
+ import { System } from "../System";
3
+
4
+ export type Inventory = ContainerWrapper & Container;
5
+
6
+ export class ContainerWrapper {
7
+ public readonly source: Container;
8
+
9
+ private constructor(source: Container) {
10
+ this.source = source;
11
+ return System.ProxyConstructor(this, source);
12
+ }
13
+
14
+ public static wrap(source: Container): Inventory {
15
+ return new ContainerWrapper(source) as Inventory;
16
+ }
17
+
18
+ //======================== Interal ========================
19
+ public reduce(slot: number, amount: number = 1) {
20
+ let itemStack: ItemStack | undefined = this.source.getItem(slot);
21
+ let currentAmount: number = itemStack?.amount || 0;
22
+ currentAmount -= amount;
23
+
24
+ if (itemStack != undefined && currentAmount > 0) {
25
+ const newItemStack: ItemStack = itemStack;
26
+ newItemStack.amount = currentAmount;
27
+ itemStack = newItemStack
28
+
29
+ } else itemStack = undefined;
30
+
31
+ this.source.setItem(slot, itemStack);
32
+ }
33
+
34
+ }
@@ -0,0 +1,12 @@
1
+ import { Entity } from "@minecraft/server";
2
+ import { Inventory } from "./Container";
3
+ export type IEntity = IEntityWrapper & Entity;
4
+ export declare class IEntityWrapper {
5
+ readonly source: Entity;
6
+ private constructor();
7
+ static wrap(source: Entity): IEntity;
8
+ isAlive: boolean;
9
+ get inventory(): Inventory;
10
+ test(): void;
11
+ }
12
+ //# sourceMappingURL=IEntity.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { Entity, EntityInventoryComponent } from "@minecraft/server";
2
+ import { ContainerWrapper, Inventory } from "./Container";
3
+ import { System } from "../System";
4
+
5
+ export type IEntity = IEntityWrapper & Entity;
6
+
7
+ export class IEntityWrapper {
8
+ public readonly source: Entity;
9
+
10
+ private constructor(source: Entity) {
11
+ this.source = source;
12
+ return System.ProxyConstructor(this, source);
13
+ }
14
+
15
+ public static wrap(source: Entity): IEntity {
16
+ return new IEntityWrapper(source) as IEntity;
17
+ }
18
+
19
+ //======================== Interal ========================
20
+ public isAlive: boolean = false;
21
+
22
+ public get inventory(): Inventory {
23
+ const i = this.source.getComponent(
24
+ EntityInventoryComponent.componentId
25
+ ) as EntityInventoryComponent;
26
+
27
+ return ContainerWrapper.wrap(i.container);
28
+ }
29
+
30
+ public test(): void {
31
+ //this.source.sendMessage(`${this.source.name} was tested`);
32
+ }
33
+
34
+ }
@@ -0,0 +1,12 @@
1
+ import { Player } from "@minecraft/server";
2
+ import { Inventory } from "./Container";
3
+ export type IPlayer = IPlayerWrapper & Player;
4
+ export declare class IPlayerWrapper {
5
+ readonly source: Player;
6
+ private constructor();
7
+ static wrap(player: Player): IPlayer;
8
+ isAlive: boolean;
9
+ get inventory(): Inventory;
10
+ test(): void;
11
+ }
12
+ //# sourceMappingURL=IPlayer.d.ts.map
@@ -0,0 +1,34 @@
1
+ import { EntityInventoryComponent, Player } from "@minecraft/server";
2
+ import { ContainerWrapper, Inventory } from "./Container";
3
+ import { System } from "../System";
4
+
5
+ export type IPlayer = IPlayerWrapper & Player;
6
+
7
+ export class IPlayerWrapper {
8
+ public readonly source: Player;
9
+
10
+ private constructor(source: Player) {
11
+ this.source = source;
12
+ return System.ProxyConstructor(this, source);
13
+ }
14
+
15
+ public static wrap(player: Player): IPlayer {
16
+ return new IPlayerWrapper(player) as IPlayer;
17
+ }
18
+
19
+ //======================== Interal ========================
20
+ public isAlive: boolean = false;
21
+
22
+ public get inventory(): Inventory {
23
+ const i = this.source.getComponent(
24
+ EntityInventoryComponent.componentId
25
+ ) as EntityInventoryComponent;
26
+
27
+ return ContainerWrapper.wrap(i.container);
28
+ }
29
+
30
+ public test(): void {
31
+ this.source.sendMessage(`${this.source.name} was tested`);
32
+ }
33
+
34
+ }
package/util/Form.d.ts DELETED
@@ -1,75 +0,0 @@
1
- import { Player, RawMessage } from "@minecraft/server";
2
- import { ActionFormResponse, ModalFormResponse } from "@minecraft/server-ui";
3
- declare class Form {
4
- readonly isOccupied: (player: Player) => boolean;
5
- }
6
- export interface Button {
7
- indexId: string | number;
8
- text: string | RawMessage;
9
- iconPath?: string;
10
- }
11
- export interface FormActionData {
12
- response: ActionFormResponse;
13
- indexId?: string | number;
14
- }
15
- export declare class ActionForm extends Form {
16
- private readonly actionForm;
17
- private buttonMap;
18
- private buttons;
19
- private titleText;
20
- private bodyText;
21
- title(title: string | RawMessage): void;
22
- body(body: string | RawMessage): void;
23
- button(indexId: string, text: string | RawMessage, iconPath?: string): void;
24
- showForm(player: Player): Promise<FormActionData>;
25
- private generateButtons;
26
- }
27
- export interface TextField {
28
- indexId: string;
29
- label: string | RawMessage;
30
- placeholder: string | RawMessage;
31
- defaultValue?: string;
32
- }
33
- export interface Dropdown {
34
- indexId: string;
35
- label: string | RawMessage;
36
- options: string[];
37
- defaultValueIndex?: number;
38
- }
39
- export interface Slider {
40
- indexId: string;
41
- label: string | RawMessage;
42
- min: number;
43
- max: number;
44
- step: number;
45
- defaultValue?: number;
46
- }
47
- export interface Toggle {
48
- indexId: string;
49
- label: string | RawMessage;
50
- defaultValue?: boolean;
51
- }
52
- export type FormValue = string | boolean | number | undefined;
53
- export interface FormModalData {
54
- response: ModalFormResponse;
55
- indexMap?: Map<string, FormValue>;
56
- }
57
- export declare class ModalForm extends Form {
58
- private readonly modalForm;
59
- private widgitMap;
60
- private indexMap;
61
- private widgets;
62
- title(title: string | RawMessage): void;
63
- label(label: string | RawMessage): void;
64
- header(header: string | RawMessage): void;
65
- divider(): void;
66
- textField(indexId: string, label: string | RawMessage, placeholder: string | RawMessage, defaultValue?: string): void;
67
- dropdown(indexId: string, label: string | RawMessage, options: string[], defaultValueIndex?: number): void;
68
- slider(indexId: string, label: string | RawMessage, min: number, max: number, step: number, defaultValue?: number): void;
69
- toggle(indexId: string, label: string | RawMessage, defaultValue?: boolean): void;
70
- showForm(player: Player): Promise<FormModalData>;
71
- private processWidgets;
72
- private processValues;
73
- }
74
- export {};
75
- //# sourceMappingURL=Form.d.ts.map
package/util/Form.ts DELETED
@@ -1,246 +0,0 @@
1
- /*
2
- **************************************************
3
- Copyright (c) Block Factory - All rights reserved.
4
- **************************************************
5
- Author: Donthedev <https://github.com/voxeldon>
6
- **************************************************
7
- */
8
- import { Player, RawMessage } from "@minecraft/server";
9
- import { ActionFormData, ActionFormResponse, ModalFormData, ModalFormDataDropdownOptions, ModalFormDataSliderOptions, ModalFormDataTextFieldOptions, ModalFormDataToggleOptions, ModalFormResponse } from "@minecraft/server-ui";
10
-
11
- const occupiedPlayers: Set<string> = new Set();
12
-
13
- class Form {
14
- public readonly isOccupied = ((player: Player): boolean => {
15
- return occupiedPlayers.has(player.id);
16
- })
17
- }
18
-
19
- export interface Button {
20
- indexId: string | number;
21
- text: string | RawMessage;
22
- iconPath?: string;
23
- }
24
-
25
- export interface FormActionData {
26
- response: ActionFormResponse;
27
- indexId?: string | number;
28
- }
29
-
30
- export class ActionForm extends Form {
31
- private readonly actionForm: ActionFormData = new ActionFormData();
32
- private buttonMap: Map<number, string | number> = new Map<number, string | number>();
33
- private buttons: Button[] = [];
34
- private titleText: string | RawMessage | undefined;
35
- private bodyText: string | RawMessage | undefined;
36
-
37
- public title(title: string | RawMessage): void {
38
- this.titleText = title;
39
- }
40
-
41
- public body(body: string | RawMessage): void {
42
- this.bodyText = body;
43
- }
44
-
45
- public button(indexId: string, text: string | RawMessage, iconPath?: string): void {
46
- this.buttons.push({ indexId, text, iconPath });
47
- }
48
-
49
- public async showForm(player: Player): Promise<FormActionData> {
50
- if (this.titleText === undefined || this.bodyText === undefined) {
51
- throw Error('Title and body must be set before showing the form');
52
- }
53
- this.actionForm.title(this.titleText);
54
- this.actionForm.body(this.bodyText);
55
- this.generateButtons();
56
-
57
- occupiedPlayers.add(player.id);
58
-
59
- const response: ActionFormResponse = await this.actionForm.show(player).finally(() => {
60
- occupiedPlayers.delete(player.id);
61
- });
62
-
63
- const return_data: FormActionData = {
64
- response: response,
65
- indexId: undefined
66
- };
67
- if (response.selection !== undefined && response.selection !== null) {
68
- const selection: string | number | undefined = this.buttonMap.get(response.selection);
69
- return_data.indexId = selection;
70
- }
71
-
72
- return return_data;
73
- }
74
-
75
- private generateButtons() {
76
- let buttonIndex: number = 0;
77
- this.buttons.forEach(button => {
78
- if (button.iconPath) {
79
- this.actionForm.button(button.text, button.iconPath);
80
- } else {
81
- this.actionForm.button(button.text);
82
- }
83
- this.buttonMap.set(buttonIndex, button.indexId);
84
- buttonIndex++;
85
- });
86
- }
87
- }
88
-
89
- enum WidgetType {
90
- TextField = 'textField',
91
- Dropdown = 'dropdown',
92
- Slider = 'slider',
93
- Toggle = 'toggle'
94
- }
95
-
96
- interface Widget {
97
- typeId: string,
98
- widget: any
99
- };
100
-
101
- export interface TextField {
102
- indexId: string,
103
- label: string | RawMessage,
104
- placeholder: string | RawMessage,
105
- defaultValue?: string
106
- }
107
-
108
- export interface Dropdown {
109
- indexId: string,
110
- label: string | RawMessage,
111
- options: string[],
112
- defaultValueIndex?: number
113
- }
114
-
115
- export interface Slider {
116
- indexId: string,
117
- label: string | RawMessage,
118
- min: number,
119
- max: number,
120
- step: number,
121
- defaultValue?: number
122
- }
123
-
124
- export interface Toggle {
125
- indexId: string,
126
- label: string | RawMessage,
127
- defaultValue?: boolean
128
- }
129
-
130
- export type FormValue = string | boolean | number | undefined;
131
-
132
- export interface FormModalData {
133
- response: ModalFormResponse;
134
- indexMap?: Map<string, FormValue>;
135
- }
136
-
137
- export class ModalForm extends Form {
138
- private readonly modalForm: ModalFormData = new ModalFormData();
139
- private widgitMap: Map<number, string> = new Map<number, string>();
140
- private indexMap: Map<string, FormValue> = new Map<string, FormValue>();
141
- private widgets: Widget[] = [];
142
-
143
- public title(title: string | RawMessage): void {
144
- this.modalForm.title(title);
145
- }
146
-
147
- public label(label: string | RawMessage): void {
148
- this.modalForm.label(label);
149
- }
150
-
151
- public header(header: string | RawMessage): void {
152
- this.modalForm.header(header);
153
- }
154
-
155
- public divider(): void {
156
- this.modalForm.divider();
157
- }
158
-
159
- public textField(indexId: string, label: string | RawMessage, placeholder: string | RawMessage, defaultValue?: string): void {
160
- this.widgets.push({ typeId: WidgetType.TextField, widget: { indexId, label, placeholder, defaultValue } });
161
- }
162
- public dropdown(indexId: string, label: string | RawMessage, options: string[], defaultValueIndex?: number): void {
163
- this.widgets.push({ typeId: WidgetType.Dropdown, widget: { indexId, label, options, defaultValueIndex } });
164
- }
165
-
166
- public slider(indexId: string, label: string | RawMessage, min: number, max: number, step: number, defaultValue?: number): void {
167
- this.widgets.push({ typeId: WidgetType.Slider, widget: { indexId, label, min, max, step, defaultValue } });
168
- }
169
-
170
- public toggle(indexId: string, label: string | RawMessage, defaultValue?: boolean): void {
171
- this.widgets.push({ typeId: WidgetType.Toggle, widget: { indexId, label, defaultValue } });
172
- }
173
-
174
- public async showForm(player: Player): Promise<FormModalData> {
175
- this.processWidgets();
176
- occupiedPlayers.add(player.id);
177
-
178
- const response: ModalFormResponse = await this.modalForm.show(player).finally(() => {
179
- occupiedPlayers.delete(player.id);
180
- });
181
-
182
- const return_data: FormModalData = {
183
- response: response,
184
- indexMap: undefined
185
- }
186
-
187
- if (response.formValues !== null && response.formValues !== undefined) {
188
- this.processValues(response.formValues);
189
- return_data.indexMap = this.indexMap;
190
- }
191
-
192
- return return_data;
193
- }
194
-
195
- private processWidgets(): void {
196
- let widgitIndex: number = 0;
197
-
198
- for (const widget of this.widgets) {
199
- if (widget.typeId === WidgetType.TextField) {
200
- const textField: TextField = widget.widget;
201
- const options: ModalFormDataTextFieldOptions = {
202
- defaultValue: textField?.defaultValue
203
- };
204
- this.modalForm.textField(textField.label, textField.placeholder, options);
205
- this.widgitMap.set(widgitIndex, textField.indexId);
206
- }
207
- else if (widget.typeId === WidgetType.Dropdown) {
208
- const dropdown: Dropdown = widget.widget;
209
- const options: ModalFormDataDropdownOptions = {
210
- defaultValueIndex: dropdown?.defaultValueIndex
211
- };
212
- this.modalForm.dropdown(dropdown.label, dropdown.options, options);
213
- this.widgitMap.set(widgitIndex, dropdown.indexId);
214
-
215
- }
216
- else if (widget.typeId === WidgetType.Slider) {
217
- const slider: Slider = widget.widget;
218
- const options: ModalFormDataSliderOptions = {
219
- defaultValue: slider?.defaultValue,
220
- valueStep: slider.step
221
- };
222
- this.modalForm.slider(slider.label, slider.min, slider.max, options);
223
- this.widgitMap.set(widgitIndex, slider.indexId);
224
- }
225
- else if (widget.typeId === WidgetType.Toggle) {
226
- const toggle: Toggle = widget.widget;
227
- const options: ModalFormDataToggleOptions = {
228
- defaultValue: toggle?.defaultValue
229
- }
230
- this.modalForm.toggle(toggle.label, options);
231
- this.widgitMap.set(widgitIndex, toggle.indexId);
232
- }
233
- widgitIndex += 1;
234
- }
235
- }
236
-
237
- private processValues(formValues: FormValue[]): void {
238
- let widgitIndex: number = 0;
239
- for (const i of formValues) {
240
- const value: FormValue = i?.valueOf();
241
- const indexId: string | undefined = this.widgitMap.get(widgitIndex);
242
- if (indexId) this.indexMap.set(indexId, value);
243
- widgitIndex++;
244
- }
245
- }
246
- }