pma-locals 1.0.8 → 1.0.10
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 +61 -27
- package/dist/index.d.mts +30 -0
- package/dist/index.mjs +72 -0
- package/package.json +3 -3
- package/dist/index.d.ts +0 -28
- package/dist/index.js +0 -111
package/README.md
CHANGED
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
# pma-locals
|
|
2
|
-
|
|
3
|
-
Modern TypeScript library for managing RedM ped spawning and animations.
|
|
4
|
-
|
|
5
|
-
## Installation
|
|
6
|
-
|
|
7
1
|
```bash
|
|
8
2
|
npm install pma-locals
|
|
9
3
|
# or
|
|
10
4
|
pnpm add pma-locals
|
|
11
5
|
```
|
|
12
6
|
|
|
13
|
-
##
|
|
7
|
+
## Quick Start
|
|
14
8
|
|
|
15
9
|
```typescript
|
|
16
|
-
import { registerPed, processSpawning } from "pma-locals";
|
|
10
|
+
import { registerPed, processSpawning, cleanupPeds } from "pma-locals";
|
|
17
11
|
import { Vector3, Delay } from "@nativewrappers/redm";
|
|
18
12
|
|
|
19
13
|
// Register a ped with animation
|
|
@@ -22,6 +16,7 @@ registerPed(
|
|
|
22
16
|
new Vector3(-297.74, 791.1, 118.4), // spawn coords
|
|
23
17
|
180.0, // heading
|
|
24
18
|
50.0, // spawn distance (optional, default: 100.0)
|
|
19
|
+
true, // disable collisions
|
|
25
20
|
{
|
|
26
21
|
dict: "amb_wander@world_human_smoke@male@male_a@idle_a",
|
|
27
22
|
anim: "idle_a",
|
|
@@ -31,47 +26,86 @@ registerPed(
|
|
|
31
26
|
|
|
32
27
|
// In your game loop
|
|
33
28
|
setTick(async () => {
|
|
34
|
-
const playerPed =
|
|
35
|
-
if (!playerPed) return;
|
|
29
|
+
const playerPed = Game.PlayerPed;
|
|
36
30
|
|
|
37
|
-
|
|
38
|
-
const playerPos = new Vector3(coords[0], coords[1], coords[2]);
|
|
39
|
-
|
|
40
|
-
await processSpawning(playerPos);
|
|
31
|
+
await processSpawning(playerPed.Position);
|
|
41
32
|
await Delay(500);
|
|
42
33
|
});
|
|
34
|
+
|
|
35
|
+
// Cleanup on resource stop
|
|
36
|
+
on("onResourceStop", (resourceName: string) => {
|
|
37
|
+
if (resourceName === GetCurrentResourceName()) {
|
|
38
|
+
cleanupPeds();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
43
41
|
```
|
|
44
42
|
|
|
45
|
-
## API
|
|
43
|
+
## API Reference
|
|
46
44
|
|
|
47
45
|
### `registerPed(modelName, coords, heading, spawnDistance?, animation?, propData?)`
|
|
48
46
|
|
|
49
|
-
Register a ped to spawn when players
|
|
47
|
+
Register a ped to spawn when players are within range.
|
|
50
48
|
|
|
51
49
|
**Parameters:**
|
|
52
50
|
|
|
53
51
|
- `modelName` (number): Model hash
|
|
54
52
|
- `coords` (Vector3): Spawn coordinates
|
|
55
|
-
- `heading` (number): Ped heading direction
|
|
56
|
-
- `spawnDistance
|
|
57
|
-
- `
|
|
58
|
-
- `
|
|
53
|
+
- `heading` (number): Ped heading direction (0-360)
|
|
54
|
+
- `spawnDistance?` (number): Distance threshold (default: 100.0)
|
|
55
|
+
- `collisions?` (boolean): Optional collision handler
|
|
56
|
+
- `animation?` (Animation): Optional animation config
|
|
57
|
+
- `dict` (string): Animation dictionary
|
|
58
|
+
- `anim` (string): Animation name
|
|
59
|
+
- `propData?` (Props): Optional prop attachment
|
|
60
|
+
- `model` (string): Prop model hash
|
|
61
|
+
- `boneId` (number): Bone to attach to
|
|
62
|
+
- `offset` (number[]): Position offset [x, y, z]
|
|
63
|
+
- `rotation` (number[]): Rotation [x, y, z]
|
|
59
64
|
|
|
60
65
|
### `processSpawning(playerPos: Vector3)`
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
Process ped spawning/despawning based on player position. Call this regularly in your game loop (e.g., every 500ms).
|
|
63
68
|
|
|
64
69
|
### `cleanupPeds()`
|
|
65
70
|
|
|
66
|
-
Delete all spawned peds
|
|
71
|
+
Delete all spawned peds. Use this when your resource stops to clean up entities.
|
|
72
|
+
|
|
73
|
+
## TypeScript Support
|
|
74
|
+
|
|
75
|
+
Full type definitions are included. Import types as needed:
|
|
67
76
|
|
|
68
|
-
|
|
77
|
+
```typescript
|
|
78
|
+
import type { PedConfig, Animation, Props } from "pma-locals";
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Exported Types:**
|
|
82
|
+
|
|
83
|
+
- `PedConfig` - Complete ped configuration
|
|
84
|
+
- `Animation` - Animation data structure
|
|
85
|
+
- `Props` - Prop attachment configuration
|
|
86
|
+
|
|
87
|
+
## Development
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Install dependencies
|
|
91
|
+
pnpm install
|
|
92
|
+
|
|
93
|
+
# Build package (creates dist/ with .js and .d.ts files)
|
|
94
|
+
pnpm build:package
|
|
95
|
+
|
|
96
|
+
# RedM development mode (watch)
|
|
97
|
+
pnpm watch
|
|
98
|
+
|
|
99
|
+
# Publish to npm
|
|
100
|
+
npm version patch
|
|
101
|
+
pnpm publish
|
|
102
|
+
```
|
|
69
103
|
|
|
70
|
-
|
|
104
|
+
**Built with:**
|
|
71
105
|
|
|
72
|
-
-
|
|
73
|
-
-
|
|
74
|
-
-
|
|
106
|
+
- [tsup](https://tsup.egoist.dev/) - TypeScript bundler
|
|
107
|
+
- [esbuild](https://esbuild.github.io/) - Fast JavaScript bundler
|
|
108
|
+
- [@nativewrappers/redm](https://www.npmjs.com/package/@nativewrappers/redm) - RedM type definitions
|
|
75
109
|
|
|
76
110
|
## License
|
|
77
111
|
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AnimationFlags, Vector3 } from "@nativewrappers/redm";
|
|
2
|
+
|
|
3
|
+
//#region types/index.d.ts
|
|
4
|
+
interface Animation {
|
|
5
|
+
dict: string;
|
|
6
|
+
anim: string;
|
|
7
|
+
flag: AnimationFlags;
|
|
8
|
+
}
|
|
9
|
+
interface Props {
|
|
10
|
+
model: string;
|
|
11
|
+
boneId: number;
|
|
12
|
+
offset: number[];
|
|
13
|
+
rotation: number[];
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
//#region client/ped-handler.d.ts
|
|
17
|
+
interface PedConfig {
|
|
18
|
+
modelName: string;
|
|
19
|
+
coords: Vector3;
|
|
20
|
+
heading: number;
|
|
21
|
+
spawnDistance: number;
|
|
22
|
+
collisions?: boolean;
|
|
23
|
+
animation?: Animation;
|
|
24
|
+
propData?: Props;
|
|
25
|
+
}
|
|
26
|
+
declare function registerPed(modelName: string, coords: Vector3, heading: number, spawnDistance?: number, collisions?: boolean, animation?: Animation, propData?: Props): void;
|
|
27
|
+
declare function processSpawning(playerPos: Vector3): Promise<void>;
|
|
28
|
+
declare function cleanupPeds(): void;
|
|
29
|
+
//#endregion
|
|
30
|
+
export { type Animation, type PedConfig, type Props, cleanupPeds, processSpawning, registerPed };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { IkControlFlags, Model, createPed, createProp } from "@nativewrappers/redm";
|
|
2
|
+
|
|
3
|
+
//#region client/ped-handler.ts
|
|
4
|
+
const pedConfigs = [];
|
|
5
|
+
const activePeds = /* @__PURE__ */ new Map();
|
|
6
|
+
function registerPed(modelName, coords, heading, spawnDistance = 100, collisions, animation, propData) {
|
|
7
|
+
pedConfigs.push({
|
|
8
|
+
modelName,
|
|
9
|
+
coords,
|
|
10
|
+
heading,
|
|
11
|
+
spawnDistance,
|
|
12
|
+
collisions,
|
|
13
|
+
animation,
|
|
14
|
+
propData
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function getConfigKey(config) {
|
|
18
|
+
return `${config.coords.x}_${config.coords.y}_${config.coords.z}`;
|
|
19
|
+
}
|
|
20
|
+
function isPlayerNearCoords(playerPos, targetPos, distance) {
|
|
21
|
+
const dx = playerPos.x - targetPos.x;
|
|
22
|
+
const dy = playerPos.y - targetPos.y;
|
|
23
|
+
const dz = playerPos.z - targetPos.z;
|
|
24
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz) <= distance;
|
|
25
|
+
}
|
|
26
|
+
async function processSpawning(playerPos) {
|
|
27
|
+
for (const config of pedConfigs) {
|
|
28
|
+
const key = getConfigKey(config);
|
|
29
|
+
const isNear = isPlayerNearCoords(playerPos, config.coords, config.spawnDistance);
|
|
30
|
+
const isSpawned = activePeds.has(key);
|
|
31
|
+
if (isNear && !isSpawned) await spawnPed(config, key);
|
|
32
|
+
else if (!isNear && isSpawned) despawnPed(key);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
async function spawnPed(config, key) {
|
|
36
|
+
const ped = await createPed(new Model(config.modelName), config.coords, 0, false, true);
|
|
37
|
+
if (!ped) return;
|
|
38
|
+
SetRandomOutfitVariation(ped.Handle, true);
|
|
39
|
+
ped.IsPositionFrozen = true;
|
|
40
|
+
SetEntityInvincible(ped.Handle, true);
|
|
41
|
+
if (config.collisions) SetEntityCollision(ped.Handle, false, false);
|
|
42
|
+
SetBlockingOfNonTemporaryEvents(ped.Handle, true);
|
|
43
|
+
if (config.heading) ped.Heading = config.heading;
|
|
44
|
+
if (config.animation) await ped.Tasks.playAnimation(config.animation.dict, config.animation.anim, 8, 8, -1, 1, config.animation.flag, IkControlFlags.BlockNonAnimSceneLooks);
|
|
45
|
+
let prop = null;
|
|
46
|
+
if (config.propData) {
|
|
47
|
+
prop = await createProp(new Model(config.propData.model), ped.Position, 0, false, true);
|
|
48
|
+
if (prop) AttachEntityToEntity(prop.Handle, ped.Handle, config.propData.boneId, config.propData.offset[0], config.propData.offset[1], config.propData.offset[2], config.propData.rotation[0], config.propData.rotation[1], config.propData.rotation[2], true, false, false, true, 1, true);
|
|
49
|
+
}
|
|
50
|
+
activePeds.set(key, {
|
|
51
|
+
ped,
|
|
52
|
+
config,
|
|
53
|
+
prop
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function despawnPed(key) {
|
|
57
|
+
const activePed = activePeds.get(key);
|
|
58
|
+
if (!activePed) return;
|
|
59
|
+
if (activePed.prop) activePed.prop.delete();
|
|
60
|
+
if (activePed.ped) activePed.ped.delete();
|
|
61
|
+
activePeds.delete(key);
|
|
62
|
+
}
|
|
63
|
+
function cleanupPeds() {
|
|
64
|
+
for (const [key, activePed] of activePeds) {
|
|
65
|
+
if (activePed.prop) activePed.prop.delete();
|
|
66
|
+
if (activePed.ped) activePed.ped.delete();
|
|
67
|
+
activePeds.delete(key);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
//#endregion
|
|
72
|
+
export { cleanupPeds, processSpawning, registerPed };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pma-locals",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "RedM ped spawning and management library with TypeScript support",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"@nativewrappers/redm": "^0.0.141",
|
|
34
34
|
"@types/node": "^25.0.3",
|
|
35
35
|
"esbuild": "^0.27.2",
|
|
36
|
-
"
|
|
36
|
+
"tsdown": "0.19.0-beta.3",
|
|
37
37
|
"typescript": "^5.9.3"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"watch": "node ./scripts/dev.js",
|
|
41
41
|
"build": "node ./scripts/prod.js",
|
|
42
|
-
"build:package": "
|
|
42
|
+
"build:package": "tsdown"
|
|
43
43
|
}
|
|
44
44
|
}
|
package/dist/index.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { AnimationFlags, Vector3 } from '@nativewrappers/redm';
|
|
2
|
-
|
|
3
|
-
interface Animation {
|
|
4
|
-
dict: string;
|
|
5
|
-
anim: string;
|
|
6
|
-
flag: AnimationFlags;
|
|
7
|
-
}
|
|
8
|
-
interface Props {
|
|
9
|
-
model: string;
|
|
10
|
-
boneId: number;
|
|
11
|
-
offset: number[];
|
|
12
|
-
rotation: number[];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
interface PedConfig {
|
|
16
|
-
modelName: string;
|
|
17
|
-
coords: Vector3;
|
|
18
|
-
heading: number;
|
|
19
|
-
spawnDistance: number;
|
|
20
|
-
collisions?: boolean;
|
|
21
|
-
animation?: Animation;
|
|
22
|
-
propData?: Props;
|
|
23
|
-
}
|
|
24
|
-
declare function registerPed(modelName: string, coords: Vector3, heading: number, spawnDistance?: number, collisions?: boolean, animation?: Animation, propData?: Props): void;
|
|
25
|
-
declare function processSpawning(playerPos: Vector3): Promise<void>;
|
|
26
|
-
declare function cleanupPeds(): void;
|
|
27
|
-
|
|
28
|
-
export { type Animation, type PedConfig, type Props, cleanupPeds, processSpawning, registerPed };
|
package/dist/index.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { createPed, Model, 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, collisions, animation, propData) {
|
|
7
|
-
pedConfigs.push({
|
|
8
|
-
modelName,
|
|
9
|
-
coords,
|
|
10
|
-
heading,
|
|
11
|
-
spawnDistance,
|
|
12
|
-
collisions,
|
|
13
|
-
animation,
|
|
14
|
-
propData
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
function getConfigKey(config) {
|
|
18
|
-
return `${config.coords.x}_${config.coords.y}_${config.coords.z}`;
|
|
19
|
-
}
|
|
20
|
-
function isPlayerNearCoords(playerPos, targetPos, distance) {
|
|
21
|
-
const dx = playerPos.x - targetPos.x;
|
|
22
|
-
const dy = playerPos.y - targetPos.y;
|
|
23
|
-
const dz = playerPos.z - targetPos.z;
|
|
24
|
-
return Math.sqrt(dx * dx + dy * dy + dz * dz) <= distance;
|
|
25
|
-
}
|
|
26
|
-
async function processSpawning(playerPos) {
|
|
27
|
-
for (const config of pedConfigs) {
|
|
28
|
-
const key = getConfigKey(config);
|
|
29
|
-
const isNear = isPlayerNearCoords(playerPos, config.coords, config.spawnDistance);
|
|
30
|
-
const isSpawned = activePeds.has(key);
|
|
31
|
-
if (isNear && !isSpawned) {
|
|
32
|
-
await spawnPed(config, key);
|
|
33
|
-
} else if (!isNear && isSpawned) {
|
|
34
|
-
despawnPed(key);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
async function spawnPed(config, key) {
|
|
39
|
-
const ped = await createPed(new Model(config.modelName), config.coords, 0, false, true);
|
|
40
|
-
if (!ped) return;
|
|
41
|
-
SetRandomOutfitVariation(ped.Handle, true);
|
|
42
|
-
ped.IsPositionFrozen = true;
|
|
43
|
-
SetEntityInvincible(ped.Handle, true);
|
|
44
|
-
if (config.collisions) {
|
|
45
|
-
SetEntityCollision(ped.Handle, false, false);
|
|
46
|
-
}
|
|
47
|
-
SetBlockingOfNonTemporaryEvents(ped.Handle, true);
|
|
48
|
-
if (config.heading) {
|
|
49
|
-
ped.Heading = config.heading;
|
|
50
|
-
}
|
|
51
|
-
if (config.animation) {
|
|
52
|
-
await ped.Tasks.playAnimation(
|
|
53
|
-
config.animation.dict,
|
|
54
|
-
config.animation.anim,
|
|
55
|
-
8,
|
|
56
|
-
8,
|
|
57
|
-
-1,
|
|
58
|
-
1,
|
|
59
|
-
config.animation.flag,
|
|
60
|
-
IkControlFlags.BlockNonAnimSceneLooks
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
let prop = null;
|
|
64
|
-
if (config.propData) {
|
|
65
|
-
prop = await createProp(new Model(config.propData.model), ped.Position, 0, false, true);
|
|
66
|
-
if (prop) {
|
|
67
|
-
AttachEntityToEntity(
|
|
68
|
-
prop.Handle,
|
|
69
|
-
ped.Handle,
|
|
70
|
-
config.propData.boneId,
|
|
71
|
-
config.propData.offset[0],
|
|
72
|
-
config.propData.offset[1],
|
|
73
|
-
config.propData.offset[2],
|
|
74
|
-
config.propData.rotation[0],
|
|
75
|
-
config.propData.rotation[1],
|
|
76
|
-
config.propData.rotation[2],
|
|
77
|
-
true,
|
|
78
|
-
false,
|
|
79
|
-
false,
|
|
80
|
-
true,
|
|
81
|
-
1,
|
|
82
|
-
true
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
activePeds.set(key, { ped, config, prop });
|
|
87
|
-
}
|
|
88
|
-
function despawnPed(key) {
|
|
89
|
-
const activePed = activePeds.get(key);
|
|
90
|
-
if (!activePed) return;
|
|
91
|
-
if (activePed.prop) {
|
|
92
|
-
activePed.prop.delete();
|
|
93
|
-
}
|
|
94
|
-
if (activePed.ped) {
|
|
95
|
-
activePed.ped.delete();
|
|
96
|
-
}
|
|
97
|
-
activePeds.delete(key);
|
|
98
|
-
}
|
|
99
|
-
function cleanupPeds() {
|
|
100
|
-
for (const [key, activePed] of activePeds) {
|
|
101
|
-
if (activePed.prop) {
|
|
102
|
-
activePed.prop.delete();
|
|
103
|
-
}
|
|
104
|
-
if (activePed.ped) {
|
|
105
|
-
activePed.ped.delete();
|
|
106
|
-
}
|
|
107
|
-
activePeds.delete(key);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export { cleanupPeds, processSpawning, registerPed };
|