Created
April 12, 2015 15:44
-
-
Save Y-Less/f2569a165a10deef9fed to your computer and use it in GitHub Desktop.
Botsync updated for new foreach versions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*----------------------------------------------------------------------------*- | |
========================== | |
NPC script communication | |
========================== | |
Description: | |
This code provides a system to communicate with bots via files. It uses | |
locks to ensure only one script may communicate at once - bots and the main | |
server run in separate processes so it is possible to read and write from | |
the files at the same time if locks are not used. | |
Because the communication is asynchronous replies are not instant, you send | |
a message to the bot (or vice versa) then use a callback to process the | |
response later. | |
Fast communication with bots is done via OnClientMessage, but there is no | |
way of returning data using this method, any responses from the bot will | |
have to go via the regular file system. | |
This file defines functions useable from scripts, both server and bot end, | |
to communicate with each other. At the server end this file posts the | |
messages off to the communication filterscript, except fast messages which, | |
as the name implies, are done specially and instantly. At the bot end this | |
file handles all its own file reading and writing as only one script can | |
access the files it relates to. | |
Legal: | |
Copyright (C) 2009 Alex "Y_Less" Cole | |
The contents of this file are subject to the Mozilla Public License | |
Version 1.1 (the "License"); you may not use this file except in | |
compliance with the License. You may obtain a copy of the License at | |
http://www.mozilla.org/MPL/ | |
Software distributed under the License is distributed on an "AS IS" | |
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the | |
License for the specific language governing rights and limitations | |
under the License. | |
The Original Code is the NPC synchronisation code include. | |
The Initial Developer of the Original Code is Alex "Y_Less" Cole. All | |
Rights Reserved. | |
Version: | |
0.1 | |
Changelog: | |
02/09/09: | |
First version | |
Functions: | |
Public: | |
- | |
Core: | |
- | |
Stock: | |
- | |
Static: | |
- | |
Inline: | |
- | |
API: | |
- | |
Callbacks: | |
- | |
Hooks: | |
- | |
Definitions: | |
BOTSYNC_IS_BOT - Detects where this is included, in a bot or server script. | |
MAX_FAST_MESSAGE - Max length of a fast bot message. | |
Enums: | |
- | |
Macros: | |
- | |
Tags: | |
- | |
Variables: | |
Global: | |
- | |
Static: | |
- | |
Commands: | |
- | |
Compile options: | |
- | |
Operators: | |
- | |
Iterators: | |
BotSync - Array of unsent messages. | |
-*----------------------------------------------------------------------------*/ | |
#if !defined _samp_included | |
#error "Please include a_samp or a_npc before botsync" | |
#endif | |
#include <foreach> | |
#if defined SendChat | |
#define BOTSYNC_IS_BOT (true) | |
#endif | |
#if defined BOTSYNC_IS_BOT | |
#define BOTSYNC_LOCK_STRING "0" | |
#define BOTSYNC_LOCK_CHAR '0' | |
#define BOTSYNC_IN_STR "t" | |
#define BOTSYNC_OUT_STR "f" | |
#define BOTSYNC_MESSAGE_BUFFER (20) | |
#else | |
#define BOTSYNC_LOCK_STRING "1" | |
#define BOTSYNC_LOCK_CHAR '1' | |
#define BOTSYNC_IN_STR "f" | |
#define BOTSYNC_OUT_STR "t" | |
#define BOTSYNC_MESSAGE_BUFFER (128) | |
#endif | |
#define BOTSYNC_MESSAGE_LENGTH (124) | |
#define BOTSYNC_FOLDER "BotSync." | |
#define BOTSYNC_FILE_LENGTH (20) | |
#define BOTSYNC_FILE (BOTSYNC_FOLDER "%03d.%s.l"), (bot), (read ? (BOTSYNC_IN_STR) : (BOTSYNC_OUT_STR)) | |
#if !defined isnull | |
#define isnull(%0) \ | |
(((%0)[0] == '\0') || (((%0)[0] == '\1') && ((%0)[1] == '\0'))) | |
#endif | |
forward | |
OnBotSyncData(bot, const name[], const msg[]); | |
#if defined BOTSYNC_SYNC_FS || defined BOTSYNC_IS_BOT | |
new | |
Iterator:BotSync<BOTSYNC_MESSAGE_BUFFER>; | |
forward | |
BotSync_Tick(); | |
static | |
bool: | |
BotSync_GetLock(bot, bool:read) | |
{ | |
new | |
name[BOTSYNC_FILE_LENGTH]; | |
format(name, sizeof (name), BOTSYNC_FILE); | |
if (fexist(name)) | |
{ | |
return false; | |
} | |
new | |
File:fhnd = fopen(name, io_write); | |
if (fhnd) | |
{ | |
fwrite(fhnd, BOTSYNC_LOCK_STRING); | |
fclose(fhnd); | |
fhnd = fopen(name, io_read); | |
if (fhnd) | |
{ | |
if (fgetchar(fhnd, 0, false) == BOTSYNC_LOCK_CHAR) | |
{ | |
fclose(fhnd); | |
return true; | |
} | |
fclose(fhnd); | |
} | |
else | |
{ | |
printf("BotSync error: Lock fail"); | |
} | |
} | |
return false; | |
} | |
static | |
BotSync_ReleaseLock(bot, bool:read) | |
{ | |
new | |
name[BOTSYNC_FILE_LENGTH]; | |
format(name, sizeof (name), BOTSYNC_FILE); | |
fremove(name); | |
} | |
static | |
BSF: | |
BotSync_Open(bot) | |
{ | |
new | |
name[BOTSYNC_FILE_LENGTH]; | |
format(name, sizeof (name), BOTSYNC_FOLDER "%03d." BOTSYNC_OUT_STR ".d", bot); | |
return BSF:fopen(name, io_append); | |
} | |
#define BotSync_Write(%0,%1) \ | |
fwrite(File:%0, %1) | |
#define BotSync_Close(%0) \ | |
fclose(File:%0) | |
#endif | |
#if defined BOTSYNC_IS_BOT | |
static | |
BS_g_MessageBuffer[BOTSYNC_MESSAGE_BUFFER][BOTSYNC_MESSAGE_LENGTH], | |
BS_g_me; | |
public | |
BotSync_Tick() | |
{ | |
if (Iter_Count(BotSync)) | |
{ | |
if (BotSync_GetLock(BS_g_me, false)) | |
{ | |
new | |
BSF:fhnd = BotSync_Open(BS_g_me); | |
if (fhnd) | |
{ | |
new | |
msg = YSI_gBotSyncS, | |
nxt; | |
while (msg != -1) | |
{ | |
BotSync_Write(fhnd, BS_g_MessageBuffer[msg]); | |
nxt = YSI_gBotSyncA[msg]; | |
YSI_gBotSyncA[msg] = -1; | |
msg = nxt; | |
} | |
YSI_gBotSyncC = 0; | |
YSI_gBotSyncS = -1; | |
BotSync_Close(fhnd); | |
} | |
BotSync_ReleaseLock(BS_g_me, false); | |
} | |
} | |
#if defined BOT_SYNC_CALLBACK | |
new | |
name[BOTSYNC_FILE_LENGTH]; | |
format(name, sizeof (name), BOTSYNC_FOLDER "%03d." BOTSYNC_IN_STR ".d", BS_g_me); | |
if (fexist(name)) | |
{ | |
if (BotSync_GetLock(BS_g_me, true)) | |
{ | |
new | |
File:fhnd = fopen(name, io_read); | |
if (fhnd) | |
{ | |
new | |
str[BOTSYNC_MESSAGE_LENGTH]; | |
while (fread(fhnd, str)) | |
{ | |
new | |
pos0 = -1; | |
while (str[++pos0] > '\1') {} | |
if (str[pos0] == '\1') | |
{ | |
new | |
pos1 = pos0; | |
while (str[++pos1] >= ' ') {} | |
str[pos0] = '\0'; | |
str[pos1] = '\0'; | |
BOT_SYNC_CALLBACK(-1, str, str[pos0 + 1]); | |
} | |
} | |
fclose(fhnd); | |
fremove(name); | |
} | |
BotSync_ReleaseLock(BS_g_me, true); | |
} | |
} | |
#endif | |
} | |
public | |
OnNPCConnect(myplayerid) | |
{ | |
SetTimer("BotSync_Tick", 10, true); | |
BS_g_me = myplayerid; | |
BotSync_OnNPCConnect(myplayerid); | |
} | |
#define OnNPCConnect BotSync_OnNPCConnect | |
forward | |
BotSync_OnNPCConnect(myplayerid); | |
public | |
OnClientMessage(color, text[]) | |
{ | |
if (color) | |
{ | |
return BotSync_OnClientMessage(color, text); | |
} | |
new | |
pos0 = -1; | |
while (text[++pos0] > '\1') {} | |
if (text[pos0] == '\1') | |
{ | |
text[pos0] = '\0'; | |
BOT_SYNC_CALLBACK(-1, text, text[pos0 + 1]); | |
} | |
return 0; | |
} | |
#define OnClientMessage BotSync_OnClientMessage | |
forward | |
BotSync_OnClientMessage(color, text[]); | |
stock | |
BotSync_Send(bot, type[], message[]) | |
{ | |
new | |
slot = Iter_Free(BotSync); | |
if (slot != -1) | |
{ | |
if (strlen(type) + strlen(message) < BOTSYNC_MESSAGE_LENGTH - 3) | |
{ | |
format(BS_g_MessageBuffer[slot], BOTSYNC_MESSAGE_LENGTH, "%s\1%s\n", type, message); | |
Iter_Add(BotSync, slot); | |
return 1; | |
} | |
} | |
return 0; | |
#pragma unused bot | |
} | |
#else | |
#if defined BOTSYNC_SYNC_FS | |
enum E_BOTSYNC_BUFFER | |
{ | |
E_BOTSYNC_BOT, | |
E_BOTSYNC_MESSAGE[BOTSYNC_MESSAGE_LENGTH] | |
} | |
static | |
BS_g_MessageBuffer[BOTSYNC_MESSAGE_BUFFER][E_BOTSYNC_BUFFER]; | |
forward | |
BotSync_Buffer(bot, type[], message[]); | |
public | |
BotSync_Tick() | |
{ | |
new | |
dun = -1, | |
msg, | |
last; | |
do | |
{ | |
last = -1; | |
foreach (msg : BotSync) | |
{ | |
if (msg > dun) | |
{ | |
new | |
bot = BS_g_MessageBuffer[msg][E_BOTSYNC_BOT]; | |
if (BotSync_GetLock(bot, false)) | |
{ | |
new | |
BSF:fhnd = BotSync_Open(bot); | |
if (fhnd) | |
{ | |
BotSync_Write(fhnd, BS_g_MessageBuffer[msg][E_BOTSYNC_MESSAGE]); | |
new | |
cur = YSI_gBotSyncA[msg], | |
lst = msg; | |
while (cur != -1) | |
{ | |
if (BS_g_MessageBuffer[cur][E_BOTSYNC_BOT] == bot) | |
{ | |
BotSync_Write(fhnd, BS_g_MessageBuffer[cur][E_BOTSYNC_MESSAGE]); | |
YSI_gBotSyncA[lst] = YSI_gBotSyncA[cur]; | |
YSI_gBotSyncA[cur] = -1; | |
cur = YSI_gBotSyncA[lst]; | |
--YSI_gBotSyncC; | |
} | |
else | |
{ | |
lst = cur; | |
cur = YSI_gBotSyncA[cur]; | |
} | |
} | |
BotSync_Close(fhnd); | |
BotSync_ReleaseLock(bot, false); | |
dun = msg; | |
if (last == -1) | |
{ | |
YSI_gBotSyncS = YSI_gBotSyncA[msg]; | |
} | |
else | |
{ | |
YSI_gBotSyncA[last] = YSI_gBotSyncA[msg]; | |
} | |
YSI_gBotSyncA[msg] = -1; | |
--YSI_gBotSyncC; | |
break; | |
} | |
BotSync_ReleaseLock(bot, false); | |
} | |
} | |
last = msg; | |
} | |
} | |
while (msg != -1); | |
foreach (new bot : Bot) | |
{ | |
new | |
name[BOTSYNC_FILE_LENGTH]; | |
format(name, sizeof (name), BOTSYNC_FOLDER "%03d." BOTSYNC_IN_STR ".d", bot); | |
if (fexist(name)) | |
{ | |
if (BotSync_GetLock(bot, true)) | |
{ | |
new | |
File:fhnd = fopen(name, io_read); | |
if (fhnd) | |
{ | |
new | |
str[BOTSYNC_MESSAGE_LENGTH]; | |
while (fread(fhnd, str)) | |
{ | |
new | |
pos0 = -1; | |
while (str[++pos0] > '\1') {} | |
if (str[pos0] == '\1') | |
{ | |
new | |
pos1 = pos0; | |
while (str[++pos1] >= ' ') {} | |
str[pos0] = '\0'; | |
str[pos1] = '\0'; | |
CallRemoteFunction("OnBotSyncData", "iss", bot, str, str[pos0 + 1]); | |
} | |
} | |
fclose(fhnd); | |
fremove(name); | |
} | |
BotSync_ReleaseLock(bot, true); | |
} | |
} | |
} | |
} | |
public | |
BotSync_Buffer(bot, type[], message[]) | |
{ | |
// Buffer the message and send it later. | |
if (isnull(type) || isnull(message)) | |
{ | |
return 0; | |
} | |
if (IsPlayerNPC(bot)) | |
{ | |
new | |
slot = Iter_Free(BotSync); | |
if (slot != -1) | |
{ | |
if (strlen(type) + strlen(message) < BOTSYNC_MESSAGE_LENGTH - 3) | |
{ | |
format(BS_g_MessageBuffer[slot][E_BOTSYNC_MESSAGE], BOTSYNC_MESSAGE_LENGTH, "%s\1%s\n", type, message); | |
BS_g_MessageBuffer[slot][E_BOTSYNC_BOT] = bot; | |
Iter_Add(BotSync, slot); | |
return 1; | |
} | |
} | |
} | |
return 0; | |
} | |
#else | |
stock | |
BotSync_SendFast(bot, type[], message[]) | |
{ | |
if (IsPlayerNPC(bot)) | |
{ | |
if (strlen(type) + strlen(message) < BOTSYNC_MESSAGE_LENGTH - 3) | |
{ | |
new | |
str[BOTSYNC_MESSAGE_LENGTH]; | |
format(str, sizeof (str), "%s\1%s", type, message); | |
SendClientMessage(bot, 0, str); | |
return 1; | |
} | |
} | |
return 0; | |
} | |
stock | |
BotSync_Send(bot, type[], message[]) | |
{ | |
CallRemoteFunction("BotSync_Buffer", "iss", bot, type, message); | |
} | |
#endif | |
#endif | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment