@sagl/server 0.0.0-stage → 0.1.0-next.51
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.
- package/LICENSE +21 -0
- package/README.md +61 -2
- package/dist/actions.d.ts +46 -0
- package/dist/actions.js +80 -0
- package/dist/actions.js.map +1 -0
- package/dist/animations.d.ts +32 -0
- package/dist/animations.js +95 -0
- package/dist/animations.js.map +1 -0
- package/dist/audio.d.ts +180 -0
- package/dist/audio.js +353 -0
- package/dist/audio.js.map +1 -0
- package/dist/audio_effects.d.ts +219 -0
- package/dist/audio_effects.js +84 -0
- package/dist/audio_effects.js.map +1 -0
- package/dist/camera.d.ts +188 -0
- package/dist/camera.js +247 -0
- package/dist/camera.js.map +1 -0
- package/dist/claims.d.ts +27 -0
- package/dist/claims.js +48 -0
- package/dist/claims.js.map +1 -0
- package/dist/commands.d.ts +135 -0
- package/dist/commands.js +373 -0
- package/dist/commands.js.map +1 -0
- package/dist/console.d.ts +21 -0
- package/dist/console.js +100 -0
- package/dist/console.js.map +1 -0
- package/dist/constants.d.ts +654 -0
- package/dist/constants.js +657 -0
- package/dist/constants.js.map +1 -0
- package/dist/cutscene.d.ts +47 -0
- package/dist/cutscene.js +190 -0
- package/dist/cutscene.js.map +1 -0
- package/dist/draw.d.ts +106 -0
- package/dist/draw.js +132 -0
- package/dist/draw.js.map +1 -0
- package/dist/effects.d.ts +91 -0
- package/dist/effects.js +116 -0
- package/dist/effects.js.map +1 -0
- package/dist/gangzones.d.ts +47 -0
- package/dist/gangzones.js +122 -0
- package/dist/gangzones.js.map +1 -0
- package/dist/geo.d.ts +11 -0
- package/dist/geo.js +25 -0
- package/dist/geo.js.map +1 -0
- package/dist/hud.d.ts +159 -0
- package/dist/hud.js +247 -0
- package/dist/hud.js.map +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/interaction.d.ts +81 -0
- package/dist/interaction.js +143 -0
- package/dist/interaction.js.map +1 -0
- package/dist/junctions.d.ts +1 -0
- package/dist/junctions.js +330 -0
- package/dist/junctions.js.map +1 -0
- package/dist/map.d.ts +55 -0
- package/dist/map.js +71 -0
- package/dist/map.js.map +1 -0
- package/dist/menu.d.ts +96 -0
- package/dist/menu.js +129 -0
- package/dist/menu.js.map +1 -0
- package/dist/mission.d.ts +482 -0
- package/dist/mission.js +1258 -0
- package/dist/mission.js.map +1 -0
- package/dist/models.d.ts +56 -0
- package/dist/models.js +71 -0
- package/dist/models.js.map +1 -0
- package/dist/modshop.d.ts +229 -0
- package/dist/modshop.js +904 -0
- package/dist/modshop.js.map +1 -0
- package/dist/modshop_data.d.ts +44 -0
- package/dist/modshop_data.js +287 -0
- package/dist/modshop_data.js.map +1 -0
- package/dist/native.d.ts +809 -0
- package/dist/native.js +27 -0
- package/dist/native.js.map +1 -0
- package/dist/objects.d.ts +249 -0
- package/dist/objects.js +455 -0
- package/dist/objects.js.map +1 -0
- package/dist/paint.d.ts +124 -0
- package/dist/paint.js +84 -0
- package/dist/paint.js.map +1 -0
- package/dist/paynspray.d.ts +44 -0
- package/dist/paynspray.js +177 -0
- package/dist/paynspray.js.map +1 -0
- package/dist/ped.d.ts +335 -0
- package/dist/ped.js +536 -0
- package/dist/ped.js.map +1 -0
- package/dist/player.d.ts +685 -0
- package/dist/player.js +1163 -0
- package/dist/player.js.map +1 -0
- package/dist/screeneffects.d.ts +99 -0
- package/dist/screeneffects.js +257 -0
- package/dist/screeneffects.js.map +1 -0
- package/dist/scripts.d.ts +69 -0
- package/dist/scripts.js +125 -0
- package/dist/scripts.js.map +1 -0
- package/dist/server.d.ts +713 -0
- package/dist/server.js +1080 -0
- package/dist/server.js.map +1 -0
- package/dist/shopblips.d.ts +9 -0
- package/dist/shopblips.js +30 -0
- package/dist/shopblips.js.map +1 -0
- package/dist/special.d.ts +33 -0
- package/dist/special.js +26 -0
- package/dist/special.js.map +1 -0
- package/dist/splash.d.ts +42 -0
- package/dist/splash.js +55 -0
- package/dist/splash.js.map +1 -0
- package/dist/text.d.ts +19 -0
- package/dist/text.js +25 -0
- package/dist/text.js.map +1 -0
- package/dist/ui.d.ts +141 -0
- package/dist/ui.js +243 -0
- package/dist/ui.js.map +1 -0
- package/dist/vehicle.d.ts +306 -0
- package/dist/vehicle.js +612 -0
- package/dist/vehicle.js.map +1 -0
- package/dist/vehiclecolors.d.ts +26 -0
- package/dist/vehiclecolors.js +49 -0
- package/dist/vehiclecolors.js.map +1 -0
- package/dist/world.d.ts +222 -0
- package/dist/world.js +227 -0
- package/dist/world.js.map +1 -0
- package/dist/zone.d.ts +89 -0
- package/dist/zone.js +140 -0
- package/dist/zone.js.map +1 -0
- package/package.json +33 -4
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { NativeServer } from "./native.js";
|
|
2
|
+
import type { Player } from "./player.js";
|
|
3
|
+
export interface CutsceneOptions {
|
|
4
|
+
/**
|
|
5
|
+
* How it's skipped (the game's skip button):
|
|
6
|
+
* - `"vote"` (the default): each press is a vote, and it skips for
|
|
7
|
+
* everyone once a majority of those watching have voted (`skipVotes`);
|
|
8
|
+
* - `"leader"`: the first player's press skips it for everyone;
|
|
9
|
+
* - `"anyone"`: anyone's press skips it for everyone;
|
|
10
|
+
* - `"none"`: it can't be skipped.
|
|
11
|
+
*
|
|
12
|
+
* Nobody skips it on their own: everyone sees the same thing.
|
|
13
|
+
*/
|
|
14
|
+
skip?: "vote" | "leader" | "anyone" | "none";
|
|
15
|
+
/**
|
|
16
|
+
* For `"vote"`: it skips once more than this share of the watchers have
|
|
17
|
+
* voted (everyone at most). Default 0.5, a majority: 2 of 2, 2 of 3, 3 of
|
|
18
|
+
* 4. 1: everyone.
|
|
19
|
+
*/
|
|
20
|
+
skipVotes?: number;
|
|
21
|
+
/** How long to wait for slow loaders before starting without them (ms). Default 20 s. */
|
|
22
|
+
loadTimeout?: number;
|
|
23
|
+
}
|
|
24
|
+
export interface CutsceneResult {
|
|
25
|
+
/** Whether it was skipped for everyone (or stopped). */
|
|
26
|
+
skipped: boolean;
|
|
27
|
+
/** Who watched it (loaded in time and stayed). */
|
|
28
|
+
players: Player[];
|
|
29
|
+
}
|
|
30
|
+
/** A cutscene playing for a group of players (`server.playCutscene()`). */
|
|
31
|
+
export declare class CutscenePlay {
|
|
32
|
+
#private;
|
|
33
|
+
readonly id: number;
|
|
34
|
+
readonly name: string;
|
|
35
|
+
/** Resolves when everyone's has finished (or it was stopped). Never rejects. */
|
|
36
|
+
readonly done: Promise<CutsceneResult>;
|
|
37
|
+
/** @internal */
|
|
38
|
+
constructor(native: NativeServer, id: number, players: Player[], name: string, options: CutsceneOptions, finished: (play: CutscenePlay) => void);
|
|
39
|
+
/** Whether it has finished for everyone. */
|
|
40
|
+
get over(): boolean;
|
|
41
|
+
/** Stops it for everyone (or, before it starts, cancels it). */
|
|
42
|
+
stop(): void;
|
|
43
|
+
/** @internal */
|
|
44
|
+
state(player: Player, state: "loaded" | "finished" | "failed" | "skipVote", skipped: boolean): void;
|
|
45
|
+
/** @internal A player left. */
|
|
46
|
+
left(player: Player): void;
|
|
47
|
+
}
|
package/dist/cutscene.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
const ACTION = { load: 0, start: 1, stop: 2 };
|
|
2
|
+
/** A cutscene playing for a group of players (`server.playCutscene()`). */
|
|
3
|
+
export class CutscenePlay {
|
|
4
|
+
id;
|
|
5
|
+
name;
|
|
6
|
+
/** Resolves when everyone's has finished (or it was stopped). Never rejects. */
|
|
7
|
+
done;
|
|
8
|
+
#native;
|
|
9
|
+
#options;
|
|
10
|
+
#players;
|
|
11
|
+
#phase = new Map();
|
|
12
|
+
#watched = new Set();
|
|
13
|
+
#skipped = false;
|
|
14
|
+
#started = false;
|
|
15
|
+
#over = false;
|
|
16
|
+
#resolve;
|
|
17
|
+
#timer;
|
|
18
|
+
#votes = new Set();
|
|
19
|
+
#voteText = new Map();
|
|
20
|
+
#finished;
|
|
21
|
+
/** @internal */
|
|
22
|
+
constructor(native, id, players, name, options, finished) {
|
|
23
|
+
this.#native = native;
|
|
24
|
+
this.id = id;
|
|
25
|
+
this.name = name;
|
|
26
|
+
this.#options = options;
|
|
27
|
+
this.#players = players.filter((p) => p.connected);
|
|
28
|
+
this.#finished = finished;
|
|
29
|
+
this.done = new Promise((resolve) => (this.#resolve = resolve));
|
|
30
|
+
for (const p of this.#players) {
|
|
31
|
+
this.#phase.set(p, "loading");
|
|
32
|
+
native.cutscene(p.id, id, ACTION.load, name);
|
|
33
|
+
}
|
|
34
|
+
this.#timer = setTimeout(() => this.#start(), options.loadTimeout ?? 20_000);
|
|
35
|
+
this.#check();
|
|
36
|
+
}
|
|
37
|
+
/** Whether it has finished for everyone. */
|
|
38
|
+
get over() {
|
|
39
|
+
return this.#over;
|
|
40
|
+
}
|
|
41
|
+
/** Stops it for everyone (or, before it starts, cancels it). */
|
|
42
|
+
stop() {
|
|
43
|
+
if (this.#over)
|
|
44
|
+
return;
|
|
45
|
+
this.#skipped = true;
|
|
46
|
+
for (const [p, phase] of this.#phase) {
|
|
47
|
+
if (phase !== "done" && p.connected)
|
|
48
|
+
this.#native.cutscene(p.id, this.id, ACTION.stop);
|
|
49
|
+
}
|
|
50
|
+
// Their games report back; don't wait on anyone who never does.
|
|
51
|
+
setTimeout(() => this.#finish(), 3000);
|
|
52
|
+
}
|
|
53
|
+
/** @internal */
|
|
54
|
+
state(player, state, skipped) {
|
|
55
|
+
if (this.#over)
|
|
56
|
+
return;
|
|
57
|
+
const phase = this.#phase.get(player);
|
|
58
|
+
if (!phase || phase === "done")
|
|
59
|
+
return;
|
|
60
|
+
if (state === "skipVote") {
|
|
61
|
+
if (phase === "playing")
|
|
62
|
+
this.#vote(player);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (state === "loaded") {
|
|
66
|
+
if (this.#started) {
|
|
67
|
+
// Too late: everyone else has started.
|
|
68
|
+
this.#native.cutscene(player.id, this.id, ACTION.stop);
|
|
69
|
+
this.#phase.set(player, "done");
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
this.#phase.set(player, "loaded");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.#phase.set(player, "done");
|
|
77
|
+
}
|
|
78
|
+
this.#check();
|
|
79
|
+
}
|
|
80
|
+
// A press of the skip button.
|
|
81
|
+
#vote(player) {
|
|
82
|
+
const mode = this.#options.skip ?? "vote";
|
|
83
|
+
if (mode === "none")
|
|
84
|
+
return;
|
|
85
|
+
if (mode === "anyone" || (mode === "leader" && player === this.#players[0])) {
|
|
86
|
+
this.stop();
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (mode !== "vote")
|
|
90
|
+
return;
|
|
91
|
+
this.#votes.add(player);
|
|
92
|
+
this.#tally();
|
|
93
|
+
}
|
|
94
|
+
// The vote as it stands: skipped once it has a majority (more than
|
|
95
|
+
// `skipVotes` of those watching, everyone at most), else shown on screen.
|
|
96
|
+
#tally() {
|
|
97
|
+
if (this.#over || (this.#options.skip ?? "vote") !== "vote")
|
|
98
|
+
return;
|
|
99
|
+
const watching = [...this.#phase].filter(([p, phase]) => phase === "playing" && p.connected).map(([p]) => p);
|
|
100
|
+
if (watching.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
const votes = watching.filter((p) => this.#votes.has(p)).length;
|
|
103
|
+
const share = Math.min(1, Math.max(0, this.#options.skipVotes ?? 0.5));
|
|
104
|
+
const needed = Math.min(watching.length, Math.floor(watching.length * share) + 1);
|
|
105
|
+
if (votes >= needed) {
|
|
106
|
+
this.stop();
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
for (const p of watching) {
|
|
110
|
+
const text = this.#votes.has(p)
|
|
111
|
+
? `Skip ~y~${votes}/${needed}~w~: waiting for the others`
|
|
112
|
+
: `Skip ~y~${votes}/${needed}~w~: press ~y~Space~w~ or ~y~Enter`;
|
|
113
|
+
this.#prompt(p, text);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Bottom right of their screen, over the cutscene.
|
|
117
|
+
#prompt(player, text) {
|
|
118
|
+
const d = this.#voteText.get(player);
|
|
119
|
+
if (d)
|
|
120
|
+
d.set({ text });
|
|
121
|
+
else
|
|
122
|
+
this.#voteText.set(player, player.draw.text(text, -16, -40, { anchor: "bottom-right", align: "right", font: "sa-menu", size: 14, outline: 1 }));
|
|
123
|
+
}
|
|
124
|
+
/** @internal A player left. */
|
|
125
|
+
left(player) {
|
|
126
|
+
if (!this.#phase.has(player))
|
|
127
|
+
return;
|
|
128
|
+
this.#phase.set(player, "done");
|
|
129
|
+
this.#watched.delete(player);
|
|
130
|
+
this.#voteText.delete(player);
|
|
131
|
+
this.#check();
|
|
132
|
+
if (this.#started)
|
|
133
|
+
this.#tally(); // fewer watching: fewer votes needed
|
|
134
|
+
}
|
|
135
|
+
#check() {
|
|
136
|
+
const phases = [...this.#phase.values()];
|
|
137
|
+
if (!this.#started && !phases.includes("loading"))
|
|
138
|
+
this.#start();
|
|
139
|
+
if (this.#started && phases.every((p) => p === "done"))
|
|
140
|
+
this.#finish();
|
|
141
|
+
}
|
|
142
|
+
// Starts it for everyone whose has loaded; whoever is still loading misses it.
|
|
143
|
+
#start() {
|
|
144
|
+
if (this.#started)
|
|
145
|
+
return;
|
|
146
|
+
this.#started = true;
|
|
147
|
+
if (this.#timer)
|
|
148
|
+
clearTimeout(this.#timer);
|
|
149
|
+
this.#timer = null;
|
|
150
|
+
for (const [p, phase] of this.#phase) {
|
|
151
|
+
if (!p.connected)
|
|
152
|
+
continue;
|
|
153
|
+
if (phase === "loaded") {
|
|
154
|
+
this.#phase.set(p, "playing");
|
|
155
|
+
this.#watched.add(p);
|
|
156
|
+
this.#native.cutscene(p.id, this.id, ACTION.start);
|
|
157
|
+
}
|
|
158
|
+
else if (phase === "loading") {
|
|
159
|
+
this.#phase.set(p, "done");
|
|
160
|
+
this.#native.cutscene(p.id, this.id, ACTION.stop);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// How to skip, from the start.
|
|
164
|
+
const mode = this.#options.skip ?? "vote";
|
|
165
|
+
if (mode === "vote")
|
|
166
|
+
this.#tally();
|
|
167
|
+
else if (mode === "anyone")
|
|
168
|
+
for (const p of this.#watched)
|
|
169
|
+
this.#prompt(p, "Press ~y~Space~w~ or ~y~Enter~w~ to skip");
|
|
170
|
+
else if (mode === "leader" && this.#watched.has(this.#players[0]))
|
|
171
|
+
this.#prompt(this.#players[0], "Press ~y~Space~w~ or ~y~Enter~w~ to skip");
|
|
172
|
+
this.#check();
|
|
173
|
+
}
|
|
174
|
+
#finish() {
|
|
175
|
+
if (this.#over)
|
|
176
|
+
return;
|
|
177
|
+
this.#over = true;
|
|
178
|
+
if (this.#timer)
|
|
179
|
+
clearTimeout(this.#timer);
|
|
180
|
+
this.#timer = null;
|
|
181
|
+
for (const p of this.#phase.keys())
|
|
182
|
+
this.#phase.set(p, "done");
|
|
183
|
+
for (const d of this.#voteText.values())
|
|
184
|
+
d.remove();
|
|
185
|
+
this.#voteText.clear();
|
|
186
|
+
this.#finished(this);
|
|
187
|
+
this.#resolve({ skipped: this.#skipped, players: [...this.#watched].filter((p) => p.connected) });
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=cutscene.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cutscene.js","sourceRoot":"","sources":["../src/cutscene.ts"],"names":[],"mappings":"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"}
|
package/dist/draw.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { NativeDraw, NativeServer } from "./native.js";
|
|
2
|
+
import { type MapColor } from "./map.js";
|
|
3
|
+
import type { Player } from "./player.js";
|
|
4
|
+
/** A font for drawn text: the game's own, or Inter. */
|
|
5
|
+
export type DrawFont = "pricedown" | "sa-menu" | "sa-text" | "sa-gothic" | "Inter";
|
|
6
|
+
/**
|
|
7
|
+
* Where on the screen a draw's position is measured from: a corner, the
|
|
8
|
+
* middle of an edge, or the centre. `"canvas"`: SA-MP's 640x448 canvas,
|
|
9
|
+
* stretched to the screen, for code ported from SA-MP.
|
|
10
|
+
*/
|
|
11
|
+
export type Anchor = "top-left" | "top" | "top-right" | "left" | "center" | "right" | "bottom-left" | "bottom" | "bottom-right" | "canvas";
|
|
12
|
+
/** Where a draw sits. */
|
|
13
|
+
export interface PlaceOptions {
|
|
14
|
+
/** Default `"top-left"`. */
|
|
15
|
+
anchor?: Anchor;
|
|
16
|
+
/** Higher on top. */
|
|
17
|
+
layer?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* How drawn text looks. Positions and sizes are in units of 1/448 of the
|
|
21
|
+
* screen height (the same horizontally: nothing stretches), from `anchor`.
|
|
22
|
+
*/
|
|
23
|
+
export interface TextOptions extends PlaceOptions {
|
|
24
|
+
/** Default `"sa-text"` (the game's subtitle font). */
|
|
25
|
+
font?: DrawFont;
|
|
26
|
+
/** Text height on the canvas. Default 12. */
|
|
27
|
+
size?: number;
|
|
28
|
+
/** `"#RRGGBB[AA]"` or 0xRRGGBBAA. Default white. */
|
|
29
|
+
color?: MapColor;
|
|
30
|
+
/** A black outline this thick (canvas units); the game's look is about 1. */
|
|
31
|
+
outline?: number;
|
|
32
|
+
/** A black drop shadow this far (canvas units), instead of an outline. */
|
|
33
|
+
shadow?: number;
|
|
34
|
+
/** The outline's or shadow's colour instead of black (SA-MP's TextDrawBackgroundColor). */
|
|
35
|
+
outlineColor?: MapColor;
|
|
36
|
+
/** A box behind the text in this colour. */
|
|
37
|
+
box?: MapColor;
|
|
38
|
+
/** Space between the text and its box. */
|
|
39
|
+
boxPadding?: number;
|
|
40
|
+
/** Which edge `x` is: `"left"` (default), `"center"`, `"right"`. */
|
|
41
|
+
align?: "left" | "center" | "right";
|
|
42
|
+
/** Wraps at this width; left out, one line. */
|
|
43
|
+
width?: number;
|
|
44
|
+
}
|
|
45
|
+
/** What a draw can change to (`drawn.set()`). */
|
|
46
|
+
export type DrawChanges = TextOptions & {
|
|
47
|
+
text?: string;
|
|
48
|
+
x?: number;
|
|
49
|
+
y?: number;
|
|
50
|
+
height?: number;
|
|
51
|
+
file?: string;
|
|
52
|
+
};
|
|
53
|
+
/** @internal */
|
|
54
|
+
export declare function encodeDraw(o: DrawChanges): Partial<NativeDraw>;
|
|
55
|
+
/** Something drawn on screen: change it with `set()`, take it away with `remove()`. */
|
|
56
|
+
export declare class Drawn {
|
|
57
|
+
#private;
|
|
58
|
+
/** @internal */
|
|
59
|
+
constructor(spec: NativeDraw, send: (spec: NativeDraw) => void);
|
|
60
|
+
get id(): number;
|
|
61
|
+
/** Changes it: text, position, colour, ... */
|
|
62
|
+
set(changes: DrawChanges): this;
|
|
63
|
+
remove(): void;
|
|
64
|
+
/** @internal */
|
|
65
|
+
get removed(): boolean;
|
|
66
|
+
/** @internal */
|
|
67
|
+
get spec(): NativeDraw;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Drawing on screen, SA-MP textdraw style: text, boxes and images at
|
|
71
|
+
* offsets from an anchor point of the screen (a corner, an edge, the
|
|
72
|
+
* centre), in units of 1/448 of the screen height, the same both ways, so
|
|
73
|
+
* nothing stretches and things stay by their edge on any screen. `player.draw`
|
|
74
|
+
* is one player's; `server.draw` everyone's (players joining later too).
|
|
75
|
+
* Client scripts have the same, apart (`sagl.draw`).
|
|
76
|
+
*/
|
|
77
|
+
export declare class ScreenDraw {
|
|
78
|
+
#private;
|
|
79
|
+
/** @internal */
|
|
80
|
+
constructor(send: (spec: NativeDraw) => void, nextId: () => number);
|
|
81
|
+
/**
|
|
82
|
+
* Text at `x`, `y` from its anchor (`y` is its top; `align` picks which of
|
|
83
|
+
* its edges `x` is). Negative offsets go left / up.
|
|
84
|
+
*/
|
|
85
|
+
text(text: string, x: number, y: number, options?: TextOptions): Drawn;
|
|
86
|
+
/** A filled rectangle. */
|
|
87
|
+
box(x: number, y: number, width: number, height: number, color?: MapColor, options?: PlaceOptions & {
|
|
88
|
+
align?: "left" | "center" | "right";
|
|
89
|
+
}): Drawn;
|
|
90
|
+
/** An image: a client file (PNG or JPEG), optionally tinted with `color`. */
|
|
91
|
+
image(file: string, x: number, y: number, width: number, height: number, options?: PlaceOptions & {
|
|
92
|
+
color?: MapColor;
|
|
93
|
+
align?: "left" | "center" | "right";
|
|
94
|
+
}): Drawn;
|
|
95
|
+
}
|
|
96
|
+
/** @internal Everyone's draws: kept, so players joining later get them. */
|
|
97
|
+
export declare class ServerDraw extends ScreenDraw {
|
|
98
|
+
#private;
|
|
99
|
+
constructor(native: NativeServer, players: () => Player[], nextId: () => number);
|
|
100
|
+
/** @internal Wraps creation to remember it. */
|
|
101
|
+
text(...a: Parameters<ScreenDraw["text"]>): Drawn;
|
|
102
|
+
box(...a: Parameters<ScreenDraw["box"]>): Drawn;
|
|
103
|
+
image(...a: Parameters<ScreenDraw["image"]>): Drawn;
|
|
104
|
+
/** @internal A player joined: everything drawn for everyone. */
|
|
105
|
+
replay(player: Player): void;
|
|
106
|
+
}
|
package/dist/draw.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { mapColor } from "./map.js";
|
|
2
|
+
const ANCHOR = {
|
|
3
|
+
"top-left": 0, top: 1, "top-right": 2, left: 3, center: 4, right: 5,
|
|
4
|
+
"bottom-left": 6, bottom: 7, "bottom-right": 8, canvas: 9,
|
|
5
|
+
};
|
|
6
|
+
const ALIGN = { left: 0, center: 1, right: 2 };
|
|
7
|
+
/** @internal */
|
|
8
|
+
export function encodeDraw(o) {
|
|
9
|
+
const out = {};
|
|
10
|
+
for (const k of ["x", "y", "width", "height", "size", "outline", "shadow", "boxPadding", "layer", "font"]) {
|
|
11
|
+
if (o[k] !== undefined)
|
|
12
|
+
out[k] = o[k];
|
|
13
|
+
}
|
|
14
|
+
if (o.text !== undefined)
|
|
15
|
+
out.text = String(o.text).slice(0, 511);
|
|
16
|
+
if (o.file !== undefined)
|
|
17
|
+
out.text = o.file;
|
|
18
|
+
if (o.color !== undefined)
|
|
19
|
+
out.color = mapColor(o.color, 0xffffffff);
|
|
20
|
+
if (o.box !== undefined)
|
|
21
|
+
out.boxColor = o.box ? mapColor(o.box, 0x00000080) : 0;
|
|
22
|
+
if (o.outlineColor !== undefined)
|
|
23
|
+
out.outlineColor = mapColor(o.outlineColor, 0x000000ff);
|
|
24
|
+
if (o.align !== undefined)
|
|
25
|
+
out.align = ALIGN[o.align];
|
|
26
|
+
if (o.anchor !== undefined)
|
|
27
|
+
out.anchor = ANCHOR[o.anchor];
|
|
28
|
+
return out;
|
|
29
|
+
}
|
|
30
|
+
/** Something drawn on screen: change it with `set()`, take it away with `remove()`. */
|
|
31
|
+
export class Drawn {
|
|
32
|
+
#spec;
|
|
33
|
+
#send;
|
|
34
|
+
#removed = false;
|
|
35
|
+
/** @internal */
|
|
36
|
+
constructor(spec, send) {
|
|
37
|
+
this.#spec = spec;
|
|
38
|
+
this.#send = send;
|
|
39
|
+
send(spec);
|
|
40
|
+
}
|
|
41
|
+
get id() {
|
|
42
|
+
return this.#spec.id;
|
|
43
|
+
}
|
|
44
|
+
/** Changes it: text, position, colour, ... */
|
|
45
|
+
set(changes) {
|
|
46
|
+
if (this.#removed)
|
|
47
|
+
return this;
|
|
48
|
+
this.#spec = { ...this.#spec, ...encodeDraw(changes) };
|
|
49
|
+
this.#send(this.#spec);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
remove() {
|
|
53
|
+
if (this.#removed)
|
|
54
|
+
return;
|
|
55
|
+
this.#removed = true;
|
|
56
|
+
this.#send({ id: this.#spec.id, remove: true });
|
|
57
|
+
}
|
|
58
|
+
/** @internal */
|
|
59
|
+
get removed() {
|
|
60
|
+
return this.#removed;
|
|
61
|
+
}
|
|
62
|
+
/** @internal */
|
|
63
|
+
get spec() {
|
|
64
|
+
return this.#spec;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Drawing on screen, SA-MP textdraw style: text, boxes and images at
|
|
69
|
+
* offsets from an anchor point of the screen (a corner, an edge, the
|
|
70
|
+
* centre), in units of 1/448 of the screen height, the same both ways, so
|
|
71
|
+
* nothing stretches and things stay by their edge on any screen. `player.draw`
|
|
72
|
+
* is one player's; `server.draw` everyone's (players joining later too).
|
|
73
|
+
* Client scripts have the same, apart (`sagl.draw`).
|
|
74
|
+
*/
|
|
75
|
+
export class ScreenDraw {
|
|
76
|
+
#send;
|
|
77
|
+
#nextId;
|
|
78
|
+
/** @internal */
|
|
79
|
+
constructor(send, nextId) {
|
|
80
|
+
this.#send = send;
|
|
81
|
+
this.#nextId = nextId;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Text at `x`, `y` from its anchor (`y` is its top; `align` picks which of
|
|
85
|
+
* its edges `x` is). Negative offsets go left / up.
|
|
86
|
+
*/
|
|
87
|
+
text(text, x, y, options = {}) {
|
|
88
|
+
return new Drawn({ id: this.#nextId(), kind: 0, ...encodeDraw({ ...options, text, x, y }) }, this.#send);
|
|
89
|
+
}
|
|
90
|
+
/** A filled rectangle. */
|
|
91
|
+
box(x, y, width, height, color = 0x00000080, options = {}) {
|
|
92
|
+
return new Drawn({ id: this.#nextId(), kind: 1, ...encodeDraw({ x, y, width, height, color, ...options }) }, this.#send);
|
|
93
|
+
}
|
|
94
|
+
/** An image: a client file (PNG or JPEG), optionally tinted with `color`. */
|
|
95
|
+
image(file, x, y, width, height, options = {}) {
|
|
96
|
+
return new Drawn({ id: this.#nextId(), kind: 2, ...encodeDraw({ file, x, y, width, height, ...options }) }, this.#send);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** @internal Everyone's draws: kept, so players joining later get them. */
|
|
100
|
+
export class ServerDraw extends ScreenDraw {
|
|
101
|
+
#all = new Map();
|
|
102
|
+
#native;
|
|
103
|
+
#players;
|
|
104
|
+
constructor(native, players, nextId) {
|
|
105
|
+
let self = null;
|
|
106
|
+
super((spec) => self.#broadcast(spec), nextId);
|
|
107
|
+
self = this;
|
|
108
|
+
this.#native = native;
|
|
109
|
+
this.#players = players;
|
|
110
|
+
}
|
|
111
|
+
#broadcast(spec) {
|
|
112
|
+
for (const p of this.#players())
|
|
113
|
+
this.#native.draw(p.id, spec);
|
|
114
|
+
if (spec.remove)
|
|
115
|
+
this.#all.delete(spec.id);
|
|
116
|
+
}
|
|
117
|
+
/** @internal Wraps creation to remember it. */
|
|
118
|
+
text(...a) { return this.#keep(super.text(...a)); }
|
|
119
|
+
box(...a) { return this.#keep(super.box(...a)); }
|
|
120
|
+
image(...a) { return this.#keep(super.image(...a)); }
|
|
121
|
+
#keep(d) {
|
|
122
|
+
this.#all.set(d.id, d);
|
|
123
|
+
return d;
|
|
124
|
+
}
|
|
125
|
+
/** @internal A player joined: everything drawn for everyone. */
|
|
126
|
+
replay(player) {
|
|
127
|
+
for (const d of this.#all.values())
|
|
128
|
+
if (!d.removed)
|
|
129
|
+
this.#native.draw(player.id, d.spec);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=draw.js.map
|
package/dist/draw.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"draw.js","sourceRoot":"","sources":["../src/draw.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { NativeServer } from "./native.js";
|
|
2
|
+
import { GameObject, Broadcast } from "./objects.js";
|
|
3
|
+
import { type MapColor } from "./map.js";
|
|
4
|
+
import { Ped } from "./ped.js";
|
|
5
|
+
import { Player, type Vector3 } from "./player.js";
|
|
6
|
+
import { Vehicle } from "./vehicle.js";
|
|
7
|
+
/** Where an effect is: a spot, or a player, ped, vehicle or object it follows. */
|
|
8
|
+
export type EffectTarget = Vector3 | Player | Ped | Vehicle | GameObject;
|
|
9
|
+
export interface EffectOptions {
|
|
10
|
+
/** From what it's on (m, in its own space), or from the spot. */
|
|
11
|
+
offset?: Vector3;
|
|
12
|
+
/**
|
|
13
|
+
* Runs until `stop()` (a fire, smoke from a chimney), and is shown to
|
|
14
|
+
* players joining later. Default false: it plays once, as the game's
|
|
15
|
+
* effect does.
|
|
16
|
+
*/
|
|
17
|
+
loop?: boolean;
|
|
18
|
+
/** Who sees it. Default everyone. */
|
|
19
|
+
to?: readonly Player[];
|
|
20
|
+
}
|
|
21
|
+
export interface DustOptions {
|
|
22
|
+
/** Default white. */
|
|
23
|
+
color?: MapColor;
|
|
24
|
+
/** Instead: a colour of the game's car palette (0-127), as `vehicle.colors` has. */
|
|
25
|
+
carColor?: number;
|
|
26
|
+
/** Each puff's size (m). Default 1. */
|
|
27
|
+
size?: number;
|
|
28
|
+
/** Puffs. Default 20, at most 200. */
|
|
29
|
+
count?: number;
|
|
30
|
+
/** How far out from the spot they start (m). Default 1. */
|
|
31
|
+
spread?: number;
|
|
32
|
+
/** How fast they drift up (m/s). Default 0.3. */
|
|
33
|
+
rise?: number;
|
|
34
|
+
/** How long they last, as a scale of the game's smoke. Default 1. */
|
|
35
|
+
life?: number;
|
|
36
|
+
/** From what it's on (m), or from the spot. */
|
|
37
|
+
offset?: Vector3;
|
|
38
|
+
/** Who sees it. Default everyone. */
|
|
39
|
+
to?: readonly Player[];
|
|
40
|
+
}
|
|
41
|
+
type EffectSpec = Parameters<NativeServer["effect"]>[1] & {
|
|
42
|
+
id: number;
|
|
43
|
+
};
|
|
44
|
+
/** An effect (`server.effects.play()`). */
|
|
45
|
+
export declare class Effect {
|
|
46
|
+
#private;
|
|
47
|
+
readonly id: number;
|
|
48
|
+
readonly name: string;
|
|
49
|
+
/** @internal */
|
|
50
|
+
constructor(id: number, name: string, b: Broadcast<EffectSpec>, forget: (e: Effect) => void);
|
|
51
|
+
/** False once stopped. A one-off effect stays "playing" until stopped, as far as the server knows. */
|
|
52
|
+
get playing(): boolean;
|
|
53
|
+
/** Stops it (its last particles fade out). */
|
|
54
|
+
stop(): void;
|
|
55
|
+
/** @internal */
|
|
56
|
+
replay(player: Player): void;
|
|
57
|
+
/** @internal */
|
|
58
|
+
get loops(): boolean;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* `server.effects`: the game's particle effects, by name (`"explosion_crate"`,
|
|
62
|
+
* `"fire"`, `"riot_smoke"`...: the game's effects.fxp), and puffs of
|
|
63
|
+
* coloured dust.
|
|
64
|
+
*/
|
|
65
|
+
export declare class ServerEffects {
|
|
66
|
+
#private;
|
|
67
|
+
/** @internal */
|
|
68
|
+
constructor(native: NativeServer, players: () => Player[]);
|
|
69
|
+
/**
|
|
70
|
+
* Plays one of the game's effects, at a spot or on something it follows.
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* server.effects.play("explosion_crate", crate.position);
|
|
74
|
+
* const fire = server.effects.play("fire", car, { loop: true, offset: { x: 0, y: 2, z: 0.5 } });
|
|
75
|
+
* fire.stop();
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
play(name: string, at: EffectTarget, options?: EffectOptions): Effect;
|
|
79
|
+
/**
|
|
80
|
+
* Puffs of coloured dust (the game's smoke, tinted): a Pay 'n' Spray's
|
|
81
|
+
* cloud, a car skidding on sand.
|
|
82
|
+
*
|
|
83
|
+
* ```ts
|
|
84
|
+
* server.effects.dust(car, { color: "#c03030", count: 40, spread: 2.5, size: 1.5 });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
dust(at: EffectTarget, options?: DustOptions): void;
|
|
88
|
+
/** @internal A player joined: the loops playing for everyone. */
|
|
89
|
+
replay(player: Player): void;
|
|
90
|
+
}
|
|
91
|
+
export {};
|