PDA

View Full Version : [Include] Communicating between NPCs and the server


Y_Less
02/09/2009, 06:17 PM
botsync

Introduction

Now hopefully I've not missed something here and there is a dead easy way of doing this - but as far as I can see you can't send messages between NPCs and regular scripts (if there is an existing way please tell me). Some callbacks aren't available in NPC scripts, but what if you want the bot to do something which can only be done from an NPC script when those callbacks, or other events, occur? This seemed like a slight shortcoming to me so I decided to write a cross-process communication script - "botsync".

Setup

Botsync, for simplicity reasons, consists of two parts - a filterscript you need to have running all the time and an include you need to include into any gamemode, filterscript or npcscript which you want to include cross-process communication in. Note that botsync requires the latest version of foreach.

Gamemodes


#include <a_samp>
#include <botsync>

main () {}

public
OnBotSyncData(bot, const name[], const msg[])
{
return 1;
}


The "OnBotSyncData" callback is not required, it is just the callback which is called when data is recieved, you only need it in any given script if that script is going to recieve data.

Filterscripts


#define FILTERSCRIPT

#include <a_samp>
#include <botsync>

public
OnBotSyncData(bot, const name[], const msg[])
{
return 1;
}


NPCScripts


#define BOT_SYNC_CALLBACK OnBotSyncData

#include <a_npc>
#include <botsync>

main () {}

public
OnBotSyncData(bot, const name[], const msg[])
{
return 1;
}

public
OnNPCConnect(myplayerid)
{
SetTimer("RemoteCall", 1000, 1);
}

public
OnClientMessage(color, text[])
{
return 0;
}


Note that, as NPCScripts don't currently have CallLocalFunction, you MUST include OnNPCConnect and OnClientMessage. You must also include the "BOT_SYNC_CALLBACK" define above the includes if you want to use "OnBotSyncData".

Use

There are two main functions in this include:

BotSync_Send(bot, name[], msg[]);

This function sends a message to a specified bot or, if called from a bot, the main server. If you use this function in an NPCScript the "bot" parameter is always "-1" (there may be a future expansion where you can send messages from bot to bot, but for now it's only "-1" for the server).


BotSync_SendFast(bot, name[], msg[]);

This function can ONLY be used in GameModes and FilterScripts, you can not use it to send messages from NPCScripts to the server. If you are doing one way communication this function is far better. Bots do not know from which function the data was sent, they both call OnBotSyncData. You can still reply to fast messages in bots, but only using the slower BotSync_Send function.

Examples

Random 2-way comms

GM:


public
OnBotSyncData(bot, const name[], const msg[])
{
BotSync_Send(bot, "thanks", "got your message");
return 1;
}


NPC:


forward
RemoteCall();

public
RemoteCall()
{
BotSync_Send(-1, "hello", "hi from a bot");
}

public
OnBotSyncData(bot, const name[], const msg[])
{
new
File:f = fopen("debugout.txt", io_append);
if (f)
{
fwrite(f, "input from server\n");
fwrite(f, name);
fwrite(f, "\n");
fwrite(f, msg);
fwrite(f, "\n");
fclose(f);
}
return 1;
}

public
OnNPCConnect(myplayerid)
{
SetTimer("RemoteCall", 1000, 1);
}


Additional Callbacks

FS:


public
OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
new
msg[16];
format(msg, sizeof (msg), "%d %d %d", playerid, vehicleid, ispassenger);
BotSync_SendFast(bot, "OnPlayerEnterVehicle", msg);
return 1;
}


NPC:


public
OnBotSyncData(bot, const name[], const msg[])
{
if (!strcmp(name, "OnPlayerEnterVehicle"))
{
new
playerid,
vehicleid,
ispassenger;
if (!sscanf(msg, "iii", playerid, vehicleid, ispassenger))
{
OnPlayerEnterVehicle(playerid, vehicleid, ispassenger);
}
}
}


Download

Links now back on line thanks to some wonderful investigations by Meta!

Filterscript (http://pastebin.com/idqjrn70)
Include (http://pastebin.com/pWhPXKg5)
foreach (http://pastebin.com/UMJVpe2L)

This appears to use an older version of foreach, I'll have to update it at some point.

Technical

I just throught I'd add a quick bit of technical information regarding the sync.

Firstly BotSync_SendFast works by utilising "SendClientMessage" and "OnClientMessage", this is the most direct method of generic communication I could find. To identify messages sent via BotSync, rather than any normal method, the color is 0 (i.e. completely see-through black, most people use 0x000000AA for black). If this proves to cause problems I could always change it to 1, as I don't think that's used anywhere at all.

The main chunk of the code relates to the standard communication method (BotSync_Send). This method uses files to write and read messages between the multiple processes - however it's not quite as simple as that as they may try read and write at the same time, so I've added locks.

Basically when either side of the communication wants to write data (note that every bot has two files, one for input, one for output, so, although a file may be locked to one side, both sides can still be writing), they attempt to lock their output file. To lock the output file, first the lock file must not exist, they they must write to the file and read it back again. The reason it is written to and read from is because of what would happen if the server tried to lock a file at the same time as a bot. In this rare case they would both see that the lock file was missing (because there are multiple files, the server would have to be trying to perform a data read while the npc was trying to perform a data write, or vice-versa), and they would BOTH attempt to create it (the chances of this occuring are very slim, but do exist). To avoid this, both sides create the file and write a single character ('0' in NPCS, '1' in the server) and then they both read the first character. Because one of them must have got there first, that one wins and the other side backs off to try again later.

The filterscript is used to buffer, read and write all communications from all server side scripts. Because a lock is required to read and write data to the files, data must be buffered somewhere while the lock is unavailable - this happens in the filterscript (NPCs have their own buffers because they only go one to one). Fast writes go from individual scripts directly, normal writes go to the filterscript, which will write data to various bots as and when it can.

The reason for this complexity is that an NPC can only talk to one server (as there is only one), so that is nice and simple. However a server can talk to many different bots, so it needs code to write to each one when a lock for that single one becomes available.

I know this likely isn't very clear but tough - read the code (it's not commented anyway - oops, forgot).

Correlli
02/09/2009, 06:20 PM
This is great, thanks Alex.

Burridge
02/09/2009, 07:03 PM
Thanks Y_Less, this is great, i understood it well. I shall be looking into this more when i get back on the 9th. (Holiday to scottland :D)

sebihunter
03/09/2009, 09:15 PM
This is fucking great Alex ;)

Donny_k
03/09/2009, 09:23 PM
Very nice dude but lets hope a remote function is added soon as I really don't like having to use my HDD (read/write) to just tell a bot what to do. Not that I'm complaining or anything, cheers for this and cheers to Kye for giving us bots, maybe some dudes will shut up now hehe.

I really want AI, did you get anywhere with the native functions (pos/animations) ? I have not had a play yet, just looked at the includes etc.

Zeex
03/09/2009, 10:09 PM
What is "bot" parameter? Bot's playerid?

Y_Less
04/09/2009, 10:01 AM
What is "bot" parameter? Bot's playerid?


Yes.


Very nice dude but lets hope a remote function is added soon as I really don't like having to use my HDD (read/write) to just tell a bot what to do. Not that I'm complaining or anything, cheers for this and cheers to Kye for giving us bots, maybe some dudes will shut up now hehe.


If you're only telling bots what to do, i.e. only sending data TO bots, not sending anything FROM bots you can use BotSync_SendFast which doesn't use the hard disk and is much faster than using files.


I really want AI, did you get anywhere with the native functions (pos/animations) ? I have not had a play yet, just looked at the includes etc.


Not really yet, I've been very busy recently.

Y_Less
18/03/2011, 02:51 PM
Quite an epic bump. I recently released this topic:

http://forum.sa-mp.com/showthread.php?t=241446

The techniques used in there can actually be used to write a PAWN version of CallLocalFunction, which itself can be used to provide callback hooking in bot scripts, something previously not possible because there was no CallLocalFunction in their API.

Donya
21/05/2011, 12:31 AM
hmm C:\Documents and Settings\Karim\My Documents\Grand Theft Auto San Andreas\SA-MP SERVER(CNR)\pawno\include\botsync.inc(219) : error 017: undefined symbol "YSI_gBotSyncS"
C:\Documents and Settings\Karim\My Documents\Grand Theft Auto San Andreas\SA-MP SERVER(CNR)\pawno\include\botsync.inc(224) : error 017: undefined symbol "YSI_gBotSyncA"
C:\Documents and Settings\Karim\My Documents\Grand Theft Auto San Andreas\SA-MP SERVER(CNR)\pawno\include\botsync.inc(224) : warning 215: expression has no effect
C:\Documents and Settings\Karim\My Documents\Grand Theft Auto San Andreas\SA-MP SERVER(CNR)\pawno\include\botsync.inc(224) : error 001: expected token: ";", but found "]"
C:\Documents and Settings\Karim\My Documents\Grand Theft Auto San Andreas\SA-MP SERVER(CNR)\pawno\include\botsync.inc(224) : error 029: invalid expression, assumed zero
C:\Documents and Settings\Karim\My Documents\Grand Theft Auto San Andreas\SA-MP SERVER(CNR)\pawno\include\botsync.inc(224) : fatal error 107: too many error messages on one line

Compilation aborted.Pawn compiler 3.2.3664 Copyright (c) 1997-2006, ITB CompuPhase


5 Errors.


why does that happen when i compile in an npcmode script?

Looking forward to see the call functions in npcmodes for the next samp version...

Meta
10/07/2011, 02:53 AM
Pastebin Links are down :( (I only get a gray page on pastebin.ca)

EDIT: Thank god we have Google and its cache!
I found the pastes in Google's Caches and reupped 'em!

botsync.inc (http://pastebin.com/pWhPXKg5)
botsync.pwn (http://pastebin.com/idqjrn70)
foreach.inc (http://pastebin.com/UMJVpe2L)

Y_Less
14/07/2011, 11:19 AM
Thank you very much for finding those links - I've added them to the first post.

lolumadd_
18/07/2011, 01:34 AM
Do you have to run the filterscript? I don't feel too safe running a 10 millisecond looping timer.

EDIT: Also, the new updated foreach does not seem to like Incognito's streamer


C:\Users\stephen\Desktop\samp\pawno\include\foreac h.inc(335) : warning 201: redefinition of constant/macro (symbol "OnPlayerConnect")
C:\Users\stephen\Desktop\samp\pawno\include\foreac h.inc(371) : warning 201: redefinition of constant/macro (symbol "OnGameModeInit")
C:\Users\stephen\Desktop\samp\pawno\include\foreac h.inc(407) : warning 201: redefinition of constant/macro (symbol "OnPlayerDisconnect")


Any solution to that?

Y_Less
18/07/2011, 09:44 AM
Do you have to run the filterscript? I don't feel too safe running a 10 millisecond looping timer.

Why?

EDIT: Also, the new updated foreach does not seem to like Incognito's streamer


C:\Users\stephen\Desktop\samp\pawno\include\foreac h.inc(335) : warning 201: redefinition of constant/macro (symbol "OnPlayerConnect")
C:\Users\stephen\Desktop\samp\pawno\include\foreac h.inc(371) : warning 201: redefinition of constant/macro (symbol "OnGameModeInit")
C:\Users\stephen\Desktop\samp\pawno\include\foreac h.inc(407) : warning 201: redefinition of constant/macro (symbol "OnPlayerDisconnect")


Any solution to that?

That's not a new updated one, that's an old outdated one.

lolumadd_
18/07/2011, 02:52 PM
Why?



That's not a new updated one, that's an old outdated one.

Nevertheless, where is the new one then, how can I fix it?

Y_Less
18/07/2011, 03:30 PM
The new one is in the "foreach" topic, but I don't actually know if this library works with the new version - I've not touched this code in years.

clavador
19/07/2011, 09:23 PM
Is this outdated?

I was using it but i've found that it took sometimes various seconds for the bot to react so I switched to "SendClientMessage" and "OnClientMessage" to communicate and it's pretty fast now.

Y_Less
19/07/2011, 09:53 PM
No, in fact that is exactly how this system works if you are using the fast functions.

Edit: There is no fast return function as it could cause problems if a single script wasn't properly configured, but I think that's less of an issue now so I may update the code.

kriszrap
08/07/2014, 07:37 PM
#define BOT_SYNC_CALLBACK OnBotSyncData

#include <a_npc>
#include <botsync>


#define RECORDING "npcbuszoslv"
#define RECORDING_TYPE 1

#include <a_npc> // Az NPC függvénykönyvtár beágyazása

public OnRecordingPlaybackEnd ( )
{
StartRecordingPlayback ( RECORDING_TYPE, RECORDING );
return 0;
}

#if RECORDING_TYPE == 1 // Ha az NPC típusa járműves vezető
public OnNPCEnterVehicle ( vehicleid, seatid )
{
StartRecordingPlayback ( RECORDING_TYPE, RECORDING );
return 0;
}
public OnNPCExitVehicle ( )
{
StopRecordingPlayback ( );
return 0;
}
#else // Viszont ha gyalogos
public OnNPCSpawn ( )
{
StartRecordingPlayback ( RECORDING_TYPE, RECORDING );
return 0;
}
#endif
Error:
C:\Users\krisz\Desktop\samp z\pawno\include\botsync.inc(216) : error 017: undefined symbol "YSI_gBotSyncS"
C:\Users\krisz\Desktop\samp z\pawno\include\botsync.inc(221) : error 017: undefined symbol "YSI_gBotSyncA"
C:\Users\krisz\Desktop\samp z\pawno\include\botsync.inc(221) : warning 215: expression has no effect
C:\Users\krisz\Desktop\samp z\pawno\include\botsync.inc(221) : error 001: expected token: ";", but found "]"
C:\Users\krisz\Desktop\samp z\pawno\include\botsync.inc(221) : error 029: invalid expression, assumed zero
C:\Users\krisz\Desktop\samp z\pawno\include\botsync.inc(221) : fatal error 107: too many error messages on one line

why?

Y_Less
10/07/2014, 09:51 AM
Possibly because you don't use the data callback "OnBotSyncData".