pma-locals 1.0.0 → 1.0.2

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/README.md ADDED
@@ -0,0 +1,78 @@
1
+ # pma-locals
2
+
3
+ Modern TypeScript library for managing RedM ped spawning and animations.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install pma-locals
9
+ # or
10
+ pnpm add pma-locals
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```typescript
16
+ import { registerPed, processSpawning } from "pma-locals";
17
+ import { Vector3, Delay } from "@nativewrappers/redm";
18
+
19
+ // Register a ped with animation
20
+ registerPed(
21
+ 0x12345678, // model hash
22
+ new Vector3(-297.74, 791.1, 118.4), // spawn coords
23
+ 180.0, // heading
24
+ 50.0, // spawn distance (optional, default: 100.0)
25
+ {
26
+ dict: "amb_wander@world_human_smoke@male@male_a@idle_a",
27
+ anim: "idle_a",
28
+ }, // optional animation
29
+ undefined // optional prop data
30
+ );
31
+
32
+ // In your game loop
33
+ setTick(async () => {
34
+ const playerPed = PlayerPedId();
35
+ if (!playerPed) return;
36
+
37
+ const coords = GetEntityCoords(playerPed, true, true);
38
+ const playerPos = new Vector3(coords[0], coords[1], coords[2]);
39
+
40
+ await processSpawning(playerPos);
41
+ await Delay(500);
42
+ });
43
+ ```
44
+
45
+ ## API
46
+
47
+ ### `registerPed(modelName, coords, heading, spawnDistance?, animation?, propData?)`
48
+
49
+ Register a ped to spawn when players approach.
50
+
51
+ **Parameters:**
52
+
53
+ - `modelName` (number): Model hash
54
+ - `coords` (Vector3): Spawn coordinates
55
+ - `heading` (number): Ped heading direction
56
+ - `spawnDistance` (number): Distance threshold (default: 100.0)
57
+ - `animation` (Animation): Optional animation data
58
+ - `propData` (Props): Optional prop attachment
59
+
60
+ ### `processSpawning(playerPos: Vector3)`
61
+
62
+ Update ped spawning based on player position. Call this in your game loop.
63
+
64
+ ### `cleanupPeds()`
65
+
66
+ Delete all spawned peds (useful for resource cleanup).
67
+
68
+ ## Types
69
+
70
+ Full TypeScript support with exported types:
71
+
72
+ - `PedConfig`
73
+ - `Animation`
74
+ - `Props`
75
+
76
+ ## License
77
+
78
+ ISC
@@ -0,0 +1,26 @@
1
+ import { Vector3 } from '@nativewrappers/redm';
2
+
3
+ interface Animation {
4
+ dict: string;
5
+ anim: string;
6
+ }
7
+ interface Props {
8
+ model: string;
9
+ boneId: number;
10
+ offset: number[];
11
+ rotation: number[];
12
+ }
13
+
14
+ interface PedConfig {
15
+ modelName: number;
16
+ coords: Vector3;
17
+ heading: number;
18
+ spawnDistance: number;
19
+ animation?: Animation;
20
+ propData?: Props;
21
+ }
22
+ declare function registerPed(modelName: number, coords: Vector3, heading: number, spawnDistance?: number, animation?: Animation, propData?: Props): void;
23
+ declare function processSpawning(playerPos: Vector3): Promise<void>;
24
+ declare function cleanupPeds(): void;
25
+
26
+ export { type Animation, type PedConfig, type Props, cleanupPeds, processSpawning, registerPed };
package/dist/index.js ADDED
@@ -0,0 +1,104 @@
1
+ import { createPed, Model, AnimationFlags, IkControlFlags, createProp } from '@nativewrappers/redm';
2
+
3
+ // client/ped-handler.ts
4
+ var pedConfigs = [];
5
+ var activePeds = /* @__PURE__ */ new Map();
6
+ function registerPed(modelName, coords, heading, spawnDistance = 100, animation, propData) {
7
+ pedConfigs.push({
8
+ modelName,
9
+ coords,
10
+ heading,
11
+ spawnDistance,
12
+ animation,
13
+ propData
14
+ });
15
+ }
16
+ function getConfigKey(config) {
17
+ return `${config.coords.x}_${config.coords.y}_${config.coords.z}`;
18
+ }
19
+ function isPlayerNearCoords(playerPos, targetPos, distance) {
20
+ const dx = playerPos.x - targetPos.x;
21
+ const dy = playerPos.y - targetPos.y;
22
+ const dz = playerPos.z - targetPos.z;
23
+ return Math.sqrt(dx * dx + dy * dy + dz * dz) <= distance;
24
+ }
25
+ async function processSpawning(playerPos) {
26
+ for (const config of pedConfigs) {
27
+ const key = getConfigKey(config);
28
+ const isNear = isPlayerNearCoords(playerPos, config.coords, config.spawnDistance);
29
+ const isSpawned = activePeds.has(key);
30
+ if (isNear && !isSpawned) {
31
+ await spawnPed(config, key);
32
+ } else if (!isNear && isSpawned) {
33
+ despawnPed(key);
34
+ }
35
+ }
36
+ }
37
+ async function spawnPed(config, key) {
38
+ const ped = await createPed(new Model(config.modelName), config.coords, 0, false, true);
39
+ if (!ped) return;
40
+ SetRandomOutfitVariation(ped.Handle, true);
41
+ if (config.heading) {
42
+ ped.Heading = config.heading;
43
+ }
44
+ if (config.animation) {
45
+ await ped.Tasks.playAnimation(
46
+ config.animation.dict,
47
+ config.animation.anim,
48
+ 8,
49
+ 8,
50
+ -1,
51
+ 1,
52
+ AnimationFlags.Looping,
53
+ IkControlFlags.UpperBody
54
+ );
55
+ }
56
+ let prop = null;
57
+ if (config.propData) {
58
+ prop = await createProp(new Model(config.propData.model), ped.Position, 0, true, true);
59
+ if (prop) {
60
+ AttachEntityToEntity(
61
+ prop.Handle,
62
+ ped.Handle,
63
+ config.propData.boneId,
64
+ config.propData.offset[0],
65
+ config.propData.offset[1],
66
+ config.propData.offset[2],
67
+ config.propData.rotation[0],
68
+ config.propData.rotation[1],
69
+ config.propData.rotation[2],
70
+ true,
71
+ false,
72
+ false,
73
+ true,
74
+ 1,
75
+ true
76
+ );
77
+ }
78
+ }
79
+ activePeds.set(key, { ped, config, prop });
80
+ }
81
+ function despawnPed(key) {
82
+ const activePed = activePeds.get(key);
83
+ if (!activePed) return;
84
+ if (activePed.prop) {
85
+ activePed.prop.delete();
86
+ }
87
+ if (activePed.ped) {
88
+ activePed.ped.delete();
89
+ }
90
+ activePeds.delete(key);
91
+ }
92
+ function cleanupPeds() {
93
+ for (const [key, activePed] of activePeds) {
94
+ if (activePed.prop) {
95
+ activePed.prop.delete();
96
+ }
97
+ if (activePed.ped) {
98
+ activePed.ped.delete();
99
+ }
100
+ activePeds.delete(key);
101
+ }
102
+ }
103
+
104
+ export { cleanupPeds, processSpawning, registerPed };
package/package.json CHANGED
@@ -1,25 +1,44 @@
1
1
  {
2
2
  "name": "pma-locals",
3
- "version": "1.0.0",
4
- "description": "",
5
- "main": "index.js",
3
+ "version": "1.0.2",
4
+ "description": "RedM ped spawning and management library with TypeScript support",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
6
7
  "type": "module",
7
- "scripts": {
8
- "watch": "node ./scripts/dev.js",
9
- "build": "node ./scripts/prod.js"
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
10
13
  },
11
- "keywords": [],
14
+ "files": [
15
+ "dist",
16
+ "README.md"
17
+ ],
18
+ "keywords": [
19
+ "redm",
20
+ "fivem",
21
+ "ped",
22
+ "npc",
23
+ "typescript"
24
+ ],
12
25
  "author": "",
13
26
  "license": "ISC",
14
- "packageManager": "pnpm@10.15.0",
15
- "dependencies": {
16
- "@nativewrappers/redm": "^0.0.141",
17
- "@nativewrappers/server": "^0.0.141",
18
- "esbuild": "^0.27.2"
27
+ "peerDependencies": {
28
+ "@nativewrappers/redm": "^0.0.141"
19
29
  },
20
30
  "devDependencies": {
21
31
  "@citizenfx/client": "2.0.23683-1",
22
32
  "@citizenfx/server": "2.0.23683-1",
23
- "@types/node": "^25.0.3"
33
+ "@nativewrappers/redm": "^0.0.141",
34
+ "@types/node": "^25.0.3",
35
+ "esbuild": "^0.27.2",
36
+ "tsup": "^8.5.1",
37
+ "typescript": "^5.9.3"
38
+ },
39
+ "scripts": {
40
+ "watch": "node ./scripts/dev.js",
41
+ "build": "node ./scripts/prod.js",
42
+ "build:package": "tsup"
24
43
  }
25
44
  }
package/client/main.ts DELETED
@@ -1,33 +0,0 @@
1
- import { Delay, Vector3 } from "@nativewrappers/redm";
2
- import { cleanupPeds, processSpawning } from "./ped-handler";
3
-
4
- // Example: Register peds with their spawn coordinates
5
- // registerPed(
6
- // 0x12345678, // model hash
7
- // new Vector3(-297.74, 791.1, 118.4), // spawn coords
8
- // 180.0, // heading
9
- // 50.0, // spawn distance
10
- // { dict: "amb_wander@world_human_smoke@male@male_a@idle_a", anim: "idle_a" }, // optional animation
11
- // undefined // optional prop data
12
- // );
13
-
14
- setTick(async () => {
15
- const playerPed = PlayerPedId();
16
- if (!playerPed) {
17
- await Delay(500);
18
- return;
19
- }
20
-
21
- const coords = GetEntityCoords(playerPed, true, true);
22
- const playerPos = new Vector3(coords[0], coords[1], coords[2]);
23
-
24
- await processSpawning(playerPos);
25
-
26
- await Delay(500);
27
- });
28
-
29
- on("onResourceStop", (resourceName: string) => {
30
- if (resourceName !== GetCurrentResourceName()) return;
31
- console.log(`Restarting ${resourceName}`);
32
- cleanupPeds();
33
- });
@@ -1,151 +0,0 @@
1
- import { Animation, Props } from "$types/index";
2
- import {
3
- AnimationFlags,
4
- createPed,
5
- createProp,
6
- IkControlFlags,
7
- Model,
8
- Prop,
9
- Vector3,
10
- } from "@nativewrappers/redm";
11
-
12
- export interface PedConfig {
13
- modelName: number;
14
- coords: Vector3;
15
- heading: number;
16
- spawnDistance: number;
17
- animation?: Animation;
18
- propData?: Props;
19
- }
20
-
21
- interface ActivePedData {
22
- ped: any;
23
- config: PedConfig;
24
- prop: Prop | null;
25
- }
26
-
27
- // Module-level state
28
- const pedConfigs: PedConfig[] = [];
29
- const activePeds: Map<string, ActivePedData> = new Map();
30
-
31
- export function registerPed(
32
- modelName: number,
33
- coords: Vector3,
34
- heading: number,
35
- spawnDistance: number = 100.0,
36
- animation?: Animation,
37
- propData?: Props
38
- ) {
39
- pedConfigs.push({
40
- modelName,
41
- coords,
42
- heading,
43
- spawnDistance,
44
- animation,
45
- propData,
46
- });
47
- }
48
-
49
- function getConfigKey(config: PedConfig): string {
50
- return `${config.coords.x}_${config.coords.y}_${config.coords.z}`;
51
- }
52
-
53
- function isPlayerNearCoords(playerPos: Vector3, targetPos: Vector3, distance: number): boolean {
54
- const dx = playerPos.x - targetPos.x;
55
- const dy = playerPos.y - targetPos.y;
56
- const dz = playerPos.z - targetPos.z;
57
- return Math.sqrt(dx * dx + dy * dy + dz * dz) <= distance;
58
- }
59
-
60
- export async function processSpawning(playerPos: Vector3) {
61
- for (const config of pedConfigs) {
62
- const key = getConfigKey(config);
63
- const isNear = isPlayerNearCoords(playerPos, config.coords, config.spawnDistance);
64
- const isSpawned = activePeds.has(key);
65
-
66
- if (isNear && !isSpawned) {
67
- // Player is within range and ped is not spawned -> spawn it
68
- await spawnPed(config, key);
69
- } else if (!isNear && isSpawned) {
70
- // Player is outside range and ped is spawned -> delete it
71
- despawnPed(key);
72
- }
73
- }
74
- }
75
-
76
- async function spawnPed(config: PedConfig, key: string) {
77
- const ped = await createPed(new Model(config.modelName), config.coords, 0.0, false, true);
78
- if (!ped) return;
79
- SetRandomOutfitVariation(ped.Handle, true);
80
- if (config.heading) {
81
- ped.Heading = config.heading;
82
- }
83
-
84
- if (config.animation) {
85
- await ped.Tasks.playAnimation(
86
- config.animation.dict,
87
- config.animation.anim,
88
- 8.0,
89
- 8.0,
90
- -1,
91
- 1,
92
- AnimationFlags.Looping,
93
- IkControlFlags.UpperBody
94
- );
95
- }
96
-
97
- let prop: Prop | null = null;
98
- if (config.propData) {
99
- prop = await createProp(new Model(config.propData.model), ped.Position, 0, true, true);
100
- if (prop) {
101
- AttachEntityToEntity(
102
- prop.Handle,
103
- ped.Handle,
104
- config.propData.boneId,
105
- config.propData.offset[0],
106
- config.propData.offset[1],
107
- config.propData.offset[2],
108
- config.propData.rotation[0],
109
- config.propData.rotation[1],
110
- config.propData.rotation[2],
111
- true,
112
- false,
113
- false,
114
- true,
115
- 1,
116
- true
117
- );
118
- }
119
- }
120
-
121
- activePeds.set(key, { ped, config, prop });
122
- }
123
-
124
- function despawnPed(key: string) {
125
- const activePed = activePeds.get(key);
126
- if (!activePed) return;
127
-
128
- if (activePed.prop) {
129
- activePed.prop.delete();
130
- }
131
-
132
- if (activePed.ped) {
133
- activePed.ped.delete();
134
- }
135
-
136
- activePeds.delete(key);
137
- }
138
-
139
- export function cleanupPeds() {
140
- for (const [key, activePed] of activePeds) {
141
- if (activePed.prop) {
142
- activePed.prop.delete();
143
- }
144
-
145
- if (activePed.ped) {
146
- activePed.ped.delete();
147
- }
148
-
149
- activePeds.delete(key);
150
- }
151
- }
@@ -1,29 +0,0 @@
1
- {
2
- "extends": "../tsconfig.json",
3
- "compilerOptions": {
4
- "baseUrl": ".",
5
- "composite": true,
6
- "types": [
7
- "@types/node",
8
- "@citizenfx/client",
9
- "@nativewrappers/redm",
10
- "../definitions/index.ts"
11
- ],
12
- "paths": {
13
- "$types/*": [
14
- "../types/*",
15
- "../definitions/index.ts"
16
- ],
17
- "$shared/*": [
18
- "../shared/*"
19
- ]
20
- },
21
- "resolveJsonModule": true,
22
- "esModuleInterop": true
23
- },
24
- "include": [
25
- "./",
26
- "../types/*",
27
- "../shared/*",
28
- ]
29
- }
@@ -1,205 +0,0 @@
1
- /* eslint-disable */
2
-
3
- interface IntPtrInitialized {}
4
- interface FloatPtrInitialized {}
5
- interface IntPtr {}
6
- interface FloatPtr {}
7
- interface VectorPtr {}
8
- interface ReturnResultAnyway {}
9
- interface ResultAsInteger {}
10
- interface ResultAsFloat {}
11
- interface ResultAsString {}
12
- interface ResultAsVector {}
13
- interface ResultAsLong {}
14
- interface ResultAsObject {}
15
-
16
- type InputArgument =
17
- | string
18
- | number
19
- | IntPtrInitialized
20
- | FloatPtrInitialized
21
- | IntPtr
22
- | FloatPtr
23
- | VectorPtr
24
- | ReturnResultAnyway
25
- | ResultAsInteger
26
- | ResultAsFloat
27
- | ResultAsString
28
- | ResultAsVector
29
- | ResultAsLong
30
- | ResultAsObject;
31
-
32
- interface StateBagInterface {
33
- [key: string]: any;
34
- set(key: string, value: any, replicated: boolean): void;
35
- }
36
-
37
- interface EntityInterface {
38
- state: StateBagInterface;
39
- }
40
-
41
- interface CitizenInterface {
42
- trace(...args: string[]): void;
43
- setTickFunction(callback: Function): void;
44
- setEventFunction(callback: Function): void;
45
-
46
- setCallRefFunction(callback: Function): void;
47
- setDeleteRefFunction(callback: Function): void;
48
- setDuplicateRefFunction(callback: Function): void;
49
- canonicalizeRef(ref: number): string;
50
- invokeFunctionReference(ref: string, args: Uint8Array): Uint8Array;
51
-
52
- getTickCount(): number;
53
- invokeNative<T = void>(hash: string, ...args: InputArgument[]): T;
54
- invokeNativeByHash<T = void>(
55
- hash1: number,
56
- hash2: number,
57
- ...args: InputArgument[]
58
- ): T;
59
- startProfiling(name?: string): void;
60
- stopProfiling(name?: string): {};
61
-
62
- pointerValueIntInitialized(): IntPtrInitialized;
63
- pointerValueFloatInitialized(): FloatPtrInitialized;
64
- pointerValueInt(): IntPtr;
65
- pointerValueFloat(): FloatPtr;
66
- pointerValueVector(): VectorPtr;
67
- returnResultAnyway(): ReturnResultAnyway;
68
- resultAsInteger(): ResultAsInteger;
69
- resultAsFloat(): ResultAsFloat;
70
- resultAsString(): ResultAsString;
71
- resultAsVector(): ResultAsVector;
72
- resultAsLong(): ResultAsLong;
73
- resultAsObject(): ResultAsObject;
74
-
75
- makeRefFunction(refFunction: Function): string;
76
- }
77
-
78
- interface CitizenTimer {
79
- ref(): CitizenTimer;
80
- unref(): CitizenTimer;
81
- hasRef(): boolean;
82
- refresh(): CitizenTimer;
83
- [Symbol.toPrimitive](): number;
84
- }
85
-
86
- type CitizenImmediate = Omit<CitizenTimer, "refresh">;
87
-
88
- declare let Citizen: CitizenInterface;
89
-
90
- declare function addRawEventListener(
91
- eventName: string,
92
- callback: Function,
93
- ): void;
94
-
95
- declare function addEventListener(
96
- eventName: string,
97
- callback: Function,
98
- netSafe?: boolean,
99
- ): void;
100
- declare function on(eventName: string, callback: Function): void;
101
- declare function AddEventHandler(eventName: string, callback: Function): void;
102
-
103
- declare function addNetEventListener(
104
- eventName: string,
105
- callback: Function,
106
- ): void;
107
- declare function onNet(eventName: string, callback: Function): void;
108
-
109
- declare function emit(eventName: string, ...args: any[]): void;
110
- declare function TriggerEvent(eventName: string, ...args: any[]): void;
111
-
112
- declare function emitNet(eventName: string, ...args: any[]): void;
113
- declare function TriggerServerEvent(eventName: string, ...args: any[]): void;
114
- declare function TriggerLatentServerEvent(
115
- eventName: string,
116
- bps: number,
117
- ...args: any[]
118
- ): void;
119
-
120
- declare function getPlayerIdentifiers(player: number | string): string[];
121
- declare function getPlayerTokens(player: number | string): string[];
122
- declare function getPlayers(): string[];
123
-
124
- declare function SendNUIMessage(data: any): void;
125
-
126
- declare function emitNet(
127
- eventName: string,
128
- target: number | string,
129
- ...args: any[]
130
- ): void;
131
- declare function TriggerClientEvent(
132
- eventName: string,
133
- target: number | string,
134
- ...args: any[]
135
- ): void;
136
- declare function TriggerLatentClientEvent(
137
- eventName: string,
138
- target: number | string,
139
- bps: number,
140
- ...args: any[]
141
- ): void;
142
-
143
- declare function removeEventListener(
144
- eventName: string,
145
- callback: Function,
146
- ): void;
147
-
148
- declare function setTimeout<T extends any[]>(
149
- callback: (...args: T) => void,
150
- ms?: number,
151
- ...args: T
152
- ): CitizenTimer;
153
- declare function clearTimeout(timeout: CitizenTimer): void;
154
-
155
- declare function setInterval<T extends any[]>(
156
- callback: (...args: T) => void,
157
- ms?: number,
158
- ...args: T
159
- ): CitizenTimer;
160
- declare function clearInterval(interval: CitizenTimer): void;
161
-
162
- declare function setImmediate<T extends any[]>(
163
- callback: (...args: T) => void,
164
- ...args: T
165
- ): CitizenImmediate;
166
- declare function clearImmediate(immediate: CitizenImmediate): void;
167
-
168
- declare function setTick(callback: Function): number;
169
- declare function clearTick(callback: number): void;
170
-
171
- declare function NewStateBag(name: string): StateBagInterface;
172
- declare function Entity(entity: number): EntityInterface;
173
- declare let GlobalState: StateBagInterface;
174
- declare function Player(entity: number | string): EntityInterface;
175
- declare let LocalPlayer: EntityInterface;
176
-
177
- declare let exports: any;
178
-
179
- declare let source: number;
180
-
181
- // Commented methods are not implemented yet
182
- interface Console {
183
- assert(condition?: boolean, ...data: any[]): void;
184
- // clear(): void;
185
- count(label?: string): void;
186
- countReset(label?: string): void;
187
- debug(...data: any[]): void;
188
- dir(item?: any, options?: any): void;
189
- // dirxml(...data: any[]): void;
190
- error(...data: any[]): void;
191
- // group(...data: any[]): void;
192
- // groupCollapsed(...data: any[]): void;
193
- // groupEnd(): void;
194
- info(...data: any[]): void;
195
- log(...data: any[]): void;
196
- // table(tabularData?: any, properties?: string[]): void;
197
- time(label?: string): void;
198
- timeEnd(label?: string): void;
199
- // timeLog(label?: string, ...data: any[]): void;
200
- // timeStamp(label?: string): void;
201
- trace(...data: any[]): void;
202
- warn(...data: any[]): void;
203
- }
204
-
205
- declare let console: Console;
@@ -1,4 +0,0 @@
1
- /// <reference path="./Citizen.d.ts" />
2
- /// <reference path="./redm.d.ts" />
3
- /// <reference path="./json.d.ts" />
4
- /// <reference path="../web/src/png.d.ts" />
@@ -1,4 +0,0 @@
1
- declare module "*.json" {
2
- const value: any;
3
- export default value;
4
- }