Skip to content

Conversation

@AmyrAhmady
Copy link
Member

@AmyrAhmady AmyrAhmady commented Apr 17, 2024

Info

This PR is made to follow progress of NPC component development
Also creating this PR allows our build CIs to run so people can grab server builds from this PR to test NPCs

(Note: Some stuff are taken from this branch https://github.com/openmultiplayer/open.mp/tree/Alasnkz/npc like NPC network class and some move calculations)

Current Pawn scripting API

All content has been moved to HERE

Videos:

Short video of basic usage:
https://cdn.discordapp.com/attachments/966398440051445790/1229681168878669895/ompnpc.mp4

@AmyrAhmady AmyrAhmady self-assigned this Apr 17, 2024
@AmyrAhmady AmyrAhmady changed the title NPC Component NPC Component (WIP) Apr 17, 2024
@eakwarp
Copy link

eakwarp commented Apr 17, 2024

Good job!
I'll try this on my walking npcs)

@eakwarp
Copy link

eakwarp commented Apr 17, 2024

native NPC_StopMove(npcid, Float:x, Float:y, Float:z, moveType);


SCRIPT_API(NPC_StopMove, bool(INPC& npc))
{
	npc.stopMove();
	return true;
}

error in native?

@ksenonadv
Copy link
Member

native NPC_StopMove(npcid, Float:x, Float:y, Float:z, moveType);


SCRIPT_API(NPC_StopMove, bool(INPC& npc))
{
	npc.stopMove();
	return true;
}

error in native?

Edited.

@eakwarp
Copy link

eakwarp commented Apr 17, 2024

[2024-04-17T13:02:50+0300] [Info] [connection] incoming connection: 7f00:1:a4ff:ffff:a4ff:ffff:b94b:d7f7:63392 id: 0
[2024-04-17T13:02:50+0300] [Info] WalkNPC 0 Load, skin 31 node 2245
[2024-04-17T13:02:50+0300] [Info] [npc:part] FortCarson has left the server (0:2)
[2024-04-17T13:02:50+0300] [Info] [debug] Server crashed due to an unknown error

The first tests look interesting))

@eakwarp
Copy link

eakwarp commented Apr 17, 2024

image
not bad not bad.)) 500 npc slots, 50 player slots))
Server crashed when i try to spawn npc in OnNPCConnect.

@AmyrAhmady
Copy link
Member Author

I don't think NPCs are supposed to connect with ipv6 as your logs show
Also can you try using a cmd instead of spawning on connect? just to see if they work?

@AmyrAhmady
Copy link
Member Author

image not bad not bad.)) 500 npc slots, 50 player slots)) Server crashed when i try to spawn npc in OnNPCConnect.

Also, update your launcher!

@eakwarp
Copy link

eakwarp commented Apr 17, 2024

I don't think NPCs are supposed to connect with ipv6 as your logs show Also can you try using a cmd instead of spawning on connect? just to see if they work?

I removed the spawn, the server is working, the npcs have connected, but are physically absent)

logs looks like good.

....
[2024-04-17T13:43:01+0300] [Info] [connection] incoming connection: 127.0.0.1:60194 id: 354
[2024-04-17T13:43:01+0300] [Info] [npc:join] FortCarson15 has joined the server (354:127.0.0.1)
[2024-04-17T13:43:01+0300] [Info] WalkNPC 355 Load, skin 191 node 4180
[2024-04-17T13:43:02+0300] [Info] [connection] incoming connection: 127.0.0.1:55540 id: 355
[2024-04-17T13:43:02+0300] [Info] [npc:join] FortCarson16 has joined the server (355:127.0.0.1)
[2024-04-17T13:43:02+0300] [Info] WalkNPC 356 Load, skin 226 node 4178
[2024-04-17T13:43:02+0300] [Info] [connection] incoming connection: 127.0.0.1:54902 id: 356
[2024-04-17T13:43:02+0300] [Info] [npc:join] FortCarson17 has joined the server (356:127.0.0.1)
[2024-04-17T13:43:02+0300] [Info] WalkNPC 357 Load, skin 248 node 4192
[2024-04-17T13:43:02+0300] [Info] [connection] incoming connection: 127.0.0.1:53290 id: 357
[2024-04-17T13:43:02+0300] [Info] [npc:join] FortCarson18 has joined the server (357:127.0.0.1)
[2024-04-17T13:43:02+0300] [Info] WalkNPC 358 Load, skin 261 node 4190
[2024-04-17T13:43:03+0300] [Info] [connection] incoming connection: 127.0.0.1:62594 id: 358
[2024-04-17T13:43:03+0300] [Info] [npc:join] FortCarson19 has joined the server (358:127.0.0.1)
[2024-04-17T13:43:03+0300] [Info] WalkNPC 359 Load, skin 151 node 4166
[2024-04-17T13:43:03+0300] [Info] [connection] incoming connection: 127.0.0.1:49694 id: 359
[2024-04-17T13:43:03+0300] [Info] [npc:join] Civilian has joined the server (359:127.0.0.1)
[2024-04-17T13:43:03+0300] [Info] WalkNPC 362 Load, skin 35 node 4218
....

Also, update your launcher!

later )

ipv6

ipv6 turns into a localhost after the first player connects, hm..)

[2024-04-17T13:41:29+0300] [Info] [connection] incoming connection: 7f00:1:fcdb:afff:7ce0:afff:9db:afff:58068 id: 55
[2024-04-17T13:41:29+0300] [Info] [npc:join] WillowField4 has joined the server (55:7f00:1:fcdb:afff:7ce0:afff:9db:afff)
[2024-04-17T13:41:29+0300] [Info] WalkNPC 55 Load, skin 48 node 510
[2024-04-17T13:41:29+0300] [Info] [connection] incoming connection: **7f00:1:fcdb:afff:7ce0:afff:9db:afff:56960 id: 56**
[2024-04-17T13:41:29+0300] [Info] [npc:join] SanPedro5 has joined the server (56:7f00:1:fcdb:afff:7ce0:afff:9db:afff)
[2024-04-17T13:41:29+0300] [Info] WalkNPC 56 Load, skin 236 node 520
[2024-04-17T13:41:29+0300] [Info] [connection] incoming connection: [censored]:14169 id: 57
**[2024-04-17T13:41:29+0300] [Info] [join] Richard_Castle has joined the server (57:[censored])**
[2024-04-17T13:41:29+0300] [Info] [connection] incoming connection: **127.0.0.1:61243 id: 58**
[2024-04-17T13:41:29+0300] [Info] [npc:join] SanPedro6 has joined the server (58:127.0.0.1)
[2024-04-17T13:41:29+0300] [Info] WalkNPC 57 Load, skin 192 node 530
[2024-04-17T13:41:30+0300] [Info] [connection] incoming connection: 127.0.0.1:62777 id: 59
[2024-04-17T13:41:30+0300] [Info] [npc:join] SanPedro7 has joined the server (59:127.0.0.1)
[2024-04-17T13:41:30+0300] [Info] WalkNPC 58 Load, skin 190 node 540
[2024-04-17T13:41:30+0300] [Info] [connection] incoming connection: 127.0.0.1:54810 id: 60
[2024-04-17T13:41:30+0300] [Info] [npc:join] SanPedro8 has joined the server (60:127.0.0.1)

@eakwarp
Copy link

eakwarp commented Apr 17, 2024

[2024-04-17T14:04:29+0300] [Info] npc 0 spawned via timer
[2024-04-17T14:04:29+0300] [Info] npc 0 walk start timer
[2024-04-17T14:04:29+0300] [Info] [npc:part] FortCarson has left the server (0:2)
[2024-04-17T14:04:29+0300] [Info] [debug] Server crashed due to an unknown error

I tried to spawn NPCs 10 seconds after connecting - the server also crashed

@eakwarp
Copy link

eakwarp commented Apr 17, 2024

One more bug, in OnNPCConnect(npcid)
npcid always 0

@AmyrAhmady
Copy link
Member Author

As we talked in discord, regarding the crash issue, it should be fixed now. @eakwarp was kicking them and kicking an NPC wasn't implemented since it was on network level. Also removing/destroying NPCs on connect callbacks would result into crashes as well, which is now fixed too.

Also callback names are updated

@eakwarp
Copy link

eakwarp commented Aug 8, 2024

what about new builds?)

@AmyrAhmady AmyrAhmady force-pushed the amir/NPCs branch 2 times, most recently from 7d97857 to 5ad4db9 Compare October 18, 2024 05:23
@AmyrAhmady
Copy link
Member Author

AmyrAhmady commented Oct 20, 2024

EDIT

Every thing from below are done and tested

Some natives from FCNPC for Mysy

  • FCNPC_Create
  • FCNPC_Spawn
  • FCNPC_Respawn
  • FCNPC_IsDead
  • FCNPC_IsStreamedInForAnyone
  • FCNPC_GetPosition
  • FCNPC_SetPosition
  • FCNPC_GetHealth
  • FCNPC_SetHealth
  • FCNPC_SetVirtualWorld
  • FCNPC_SetWeapon
  • FCNPC_SetAmmo
  • FCNPC_GiveAmmo
  • FCNPC_SetWeaponAccuracy
  • FCNPC_UseReloading
  • FCNPC_UseInfiniteAmmo
  • FCNPC_AimAtPlayer
  • FCNPC_Stop
  • FCNPC_StopAim
  • FCNPC_GoTo
  • FCNPC_GoToPlayer
  • FCNPC_TriggerWeaponShot
  • FCNPC_SetAngleToPlayer
  • FCNPC_MeleeAttack
  • FCNPC_ApplyAnimation
  • FCNPC_SetSkin

@douq
Copy link

douq commented Sep 30, 2025

If you start making an NPC shoot with NPC_AimAtPlayer() and then call NPC_StopAim() inside OnNPCWeaponShot(), the NPC will still appear to shoot, but it won’t deal any damage. In this case, NPC_StopAim() has no effect for that NPC.

@AmyrAhmady
Copy link
Member Author

If you start making an NPC shoot with NPC_AimAtPlayer() and then call NPC_StopAim() inside OnNPCWeaponShot(), the NPC will still appear to shoot, but it won’t deal any damage. In this case, NPC_StopAim() has no effect for that NPC.

@douq Fixed in latest commit

@dockfries
Copy link

dockfries commented Oct 10, 2025

  1. PutInVehicle in the OnNPCSpawn callback will cause an infinite loop, state = SPAWNED not ONFOOT ?

Not sure if there are other similar loop call issues.

  1. another is that when executing gmx on the console, NPC will not automatically disconnect or destroy if we not manually call NPC_Destroy ?

I don't know much about it. Is this a feature ?
max_bots: 1, so log the error;

  1. event dispatch should be stopped and clear when npc already disconnect
[2025-10-10T19:34:54+0800] [Info] [connection] incoming connection: 127.0.0.1:50497 id: 49
[2025-10-10T19:34:54+0800] [Info] [npc:join] Driver has joined the server (49:127.0.0.1)
[2025-10-10T19:34:54+0800] [Info] NPC 49 spawned
[2025-10-10T19:34:54+0800] [Info] Legacy Network started on port 7777
gmx
[2025-10-10T19:35:06+0800] [Warning] Couldn't announce legacy network to open.mp list.
[2025-10-10T19:35:06+0800] [Warning]     Status: 406
[2025-10-10T19:35:06+0800] [Warning]     Message: {"error":"failed to query server: socket read timed out"}
[2025-10-10T19:35:06+0800] [Warning] This won't affect the server's behaviour.
[2025-10-10T19:35:08+0800] [Error] [NPC] NPC creation failed. Server is either full or max_bots in config is not enough!

bool NPC::putInVehicle(IVehicle& vehicle, uint8_t seat)

npcComponent_->getEventDispatcher_internal().dispatch(&NPCEventHandler::onNPCSpawn, *this);

#include <open.mp>
#include <omp_npcs>

main(){}

new vehicleid;
new npcid;

public OnGameModeInit()
{
	npcid = NPC_Create("Driver");	
    NPC_Spawn(npcid);

	vehicleid = CreateVehicle(411, 1958.33, 1343.12, 15.36, 0.0, -1, -1, -1);
	NPC_PutInVehicle(npcid, vehicleid, 0); // ok
	return 1;
}

public OnGameModeExit()
{
    NPC_Destroy(npcid);
	return 1;
}

public OnNPCSpawn(npcid)
{
    printf("NPC %d spawned", npcid); // infinite loop
//	NPC_PutInVehicle(npcid, vehicleid, 0);
    return 1;
}

public OnNPCDestroy(npcid)
{
    printf("NPC %d destroy", npcid);
    return 1;
}


public OnPlayerDisconnect(playerid)
{
    printf("player %d disconnect", playerid);
    return 1;
}

public OnPlayerStateChange(playerid, PLAYER_STATE:newstate, PLAYER_STATE:oldstate)
{
	// gmx -> disconnect -> still trigger this callback, maybe others same
    printf("player %d %d %d", playerid, newstate, oldstate);
    return 1;
}

@AmyrAhmady
Copy link
Member Author

@dockfries thanks for your reports. They're all should be fixed now

@dockfries
Copy link

dockfries commented Oct 12, 2025

trigger twice OnPlayerDisconnect, maybe should be destroy -> disconnect?

#include <open.mp>
#include <omp_npcs>

main(){}

new npcid_;

public OnGameModeInit()
{
	npcid_ = NPC_Create("Driver");	
    NPC_Spawn(npcid_);
	return 1;
}

public OnGameModeExit()
{
    NPC_Destroy(npcid_);
	return 1;
}

public OnNPCDestroy(npcid)
{
    printf("NPC %d destroy", npcid);
    return 1;
}


public OnPlayerDisconnect(playerid)
{
    printf("player %d disconnect", playerid);
    return 1;
}
[2025-10-12T13:49:57+0800] [Info] [npc:join] Driver has joined the server (49:127.0.0.1)
[2025-10-12T13:49:57+0800] [Info] Legacy Network started on port 7777
gmx
[2025-10-12T13:50:00+0800] [Info] player 49 disconnect       <<<<<<<<<
[2025-10-12T13:50:00+0800] [Info] NPC 49 destroy
[2025-10-12T13:50:00+0800] [Info] player 49 disconnect     <<<<<<< again
[2025-10-12T13:50:00+0800] [Info] [npc:part] Driver has left the server (49:1)

2. NPC component may break samp-node or sampgdk plugin index... idk.

This is a very special case, and there is no need to waste time to fix it, I just want to give feedback.

may be triggered by the following callback chain:
OnGameModeInit-> NPC_Create-> OnNPCCreate
This sequence could potentially break the sampgdk index.

samp.on("OnGameModeInit", () => {
  /**
   * [2025-10-12T13:56:34+0800] [Info] [connection] incoming connection: 127.0.0.1:61258 id: 59
    [2025-10-12T13:56:34+0800] [Info] [npc:join] test has joined the server (59:127.0.0.1)
    [2025-10-12T13:56:34+0800] [Info] [sampgdk:w] Index mismatch for OnScriptLoadPlayer (-10049 != -10050)
    [2025-10-12T13:56:34+0800] [Info] Legacy Network started on port 7777
    [2025-10-12T13:56:34+0800] [Info] [sampgdk:w] Index mismatch for OnNPCWeaponStateChange (-10010 != -10011)
   */
  samp.callNative("NPC_Create", "s", 'test'); // not ok...
  // setTimeout(() => { // it's ok... but why?
  //   samp.callNative("NPC_Create", "s", 'test'); 
  // });
})

@AmyrAhmady
Copy link
Member Author

The issue above was fixed in last commit

@douq
Copy link

douq commented Oct 16, 2025

I'm not sure whether it's a bug or not. NPCs don't trigger the OnPlayerEnterDynamicArea() or OnPlayerEnterGangZone() callbacks. I'm using UseGangZoneCheck() and have shown the zone to the NPC.

@dockfries
Copy link

dockfries commented Oct 19, 2025

I'm not sure whether it's a bug or not. NPCs don't trigger the OnPlayerEnterDynamicArea() or OnPlayerEnterGangZone() callbacks. I'm using UseGangZoneCheck() and have shown the zone to the NPC.

I think you need to manually enable Streamer_ToggleItemUpdate(npcid, STREAMER_TYPE_AREA, true) for npc.
but gangzone should be ok, I didn't do anything extra, so I don't think this is a bug.

By default, every item type is turned on, except for NPCs.

https://github.com/samp-incognito/samp-streamer-plugin/blob/e96a220a81513ca7ea772aab34256fc2b5c90bdd/src/player.cpp#L38-L40

https://github.com/samp-incognito/samp-streamer-plugin/wiki/Natives-(Updates)#streamer_toggleitemupdateplayerid-type-toggle

I tested it in my environment, but anyway it would be better if any guys could show code to recurrence it.

It seems that we cannot directly use NPC_Create during OnGameModeInit, Streamer_ToggleItemUpdate for npcid returns 0, failed.

#include <open.mp>
#include <omp_npcs>
#include <streamer>

main(){}

new npcid_;
new gangzone_;
new gangzone2_;
new area_;

public OnGameModeInit()
{	
	// DelayInit(); // Streamer_ToggleItemUpdate for npcid failed
	SetTimerEx("DelayInit", 0, false, ""); // ok
	SetTimerEx("SetNpcPosOne", 1000, false, "");
	SetTimerEx("SetNpcPosTwo", 1500, false, "");
	return 1;
}

forward DelayInit();
public DelayInit()
{	
	npcid_ = NPC_Create("Driver");	
    NPC_Spawn(npcid_);
	
	// return 0, then the npc Enter/LeaveDynamicArea will not be received
	printf("Streamer_ToggleItemUpdate %d", Streamer_ToggleItemUpdate(npcid_, STREAMER_TYPE_AREA, 1));
	printf("Streamer_IsToggleItemUpdate %d", Streamer_IsToggleItemUpdate(npcid_, STREAMER_TYPE_AREA));
	
	gangzone_ = CreatePlayerGangZone(npcid_, 0, 0, 100, 100);
	gangzone2_ =  GangZoneCreate(0, 0, 100, 100);
	area_ = CreateDynamicCircle(0, 3, 1000);

	
	UsePlayerGangZoneCheck(npcid_, gangzone_, true);
	UseGangZoneCheck(gangzone2_, true);
	
	PlayerGangZoneShow(npcid_, gangzone_, 0xFFFFFFFF);
	GangZoneShowForAll(gangzone2_, 0xFFFFFFFF);
    return 1;
}

forward SetNpcPosOne();
public SetNpcPosOne()
{	
	NPC_SetPos(npcid_, 1000, 100, 100);

	new Float:x, Float:y, Float:z;
	NPC_GetPos(npcid_, x, y, z);
	printf("pos one %f %f %f", x, y, z);
	
	printf("is in area? %d", IsPlayerInAnyDynamicArea(npcid_));
	printf("is in gangzone? %d %d", IsPlayerInGangZone(npcid_, gangzone2_), IsPlayerInGangZone(npcid_, gangzone2_));
    return 1;
}

forward SetNpcPosTwo();
public SetNpcPosTwo()
{
	NPC_SetPos(npcid_, 0, 3, 3);
		
	new Float:x, Float:y, Float:z;
	NPC_GetPos(npcid_, x, y, z);
	printf("pos two %f %f %f", x, y, z);
	
	printf("is in area? %d", IsPlayerInAnyDynamicArea(npcid_));
	printf("is in gangzone? %d %d", IsPlayerInGangZone(npcid_, gangzone2_), IsPlayerInGangZone(npcid_, gangzone2_));
    return 1;
}


public OnPlayerEnterDynamicArea(playerid, STREAMER_TAG_AREA:areaid)
{
    printf("npc is entering area %i", area_);
    return 1;
}

public OnPlayerLeaveDynamicArea(playerid, STREAMER_TAG_AREA:areaid)
{
    printf("npc is leaving area %i", area_);
    return 1;
}

public OnPlayerEnterPlayerGangZone(playerid, zoneid)
{
    printf("npc is entering player gangzone %i", zoneid);
    return 1;
}

public OnPlayerLeavePlayerGangZone(playerid, zoneid)
{
    printf("npc is leaving player gangzone %i", zoneid);
    return 1;
}

public OnPlayerEnterGangZone(playerid, zoneid)
{
    printf("npc is entering gangzone %i", zoneid);
    return 1;
}

public OnPlayerLeaveGangZone(playerid, zoneid)
{
    printf("npc is leaving gangzone %i", zoneid);
    return 1;
}

@NoPressF
Copy link
Contributor

Streamer_ToggleItemUpdate

It doesn't work

@dockfries
Copy link

dockfries commented Oct 21, 2025

If we create NPCs after the OnGameModeInit event, it seems to work properly, particularly for the streamer dynamic area.

This bug currently exists in the legacy_plugin of any version of the streamer. If you prefer not to delay the creation of NPCs after OnGameModeInit, you can use the open.mp component version branch.

@AmyrAhmady
Copy link
Member Author

@douq @dockfries this is my code and it's running fine and I get the print log:

native UseGangZoneCheck(gangzoneid, bool:check);
public OnGameModeInit()
{
	new npcid = NPC_Create("AmitBot1");
	NPC_Spawn(npcid);
	NPC_SetPos(npcid, 32.7, 77.3, 0.0);

	new gzid = GangZoneCreate(-18.0, 58.5, 80.0, 119.5);
	GangZoneShowForPlayer(npcid, gzid, 0xFF0000FF);
	UseGangZoneCheck(gzid, true);
	return 1;
}

forward OnPlayerEnterGangZone(playerid, gangzoneid);
public OnPlayerEnterGangZone(playerid, gangzoneid)
{
	printf("Player %d has entered GangZone %d", playerid, gangzoneid);
	return 1;
}

@AmyrAhmady AmyrAhmady merged commit 12df449 into master Oct 22, 2025
13 checks passed
@AmyrAhmady
Copy link
Member Author

Merged to master, it's finally done bros.

@AmyrAhmady AmyrAhmady deleted the amir/NPCs branch October 23, 2025 00:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.