[Bots] Add Bot scripting capabilities to the source. (#1378)

- This will allow server operators to interact with bots within a script in Perl or Lua.
This commit is contained in:
Alex 2021-06-11 14:46:30 -04:00 committed by GitHub
parent d54cd08560
commit d9d6a64941
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 338 additions and 0 deletions

View File

@ -977,6 +977,14 @@ void PerlembParser::MapFunctions()
"package Expedition;"
"&boot_Expedition;"
#ifdef BOTS
"package Bot;"
"our @ISA = qw(NPC);" // Bot inherits NPC
"&boot_Mob;" // load our Mob XS
"&boot_NPC;" // load our NPC XS
"&boot_Bot;" // load our Bot XS
#endif
#endif
"package main;"
"}"

View File

@ -39,6 +39,9 @@ EXTERN_C XS(boot_Object);
EXTERN_C XS(boot_Doors);
EXTERN_C XS(boot_PerlPacket);
EXTERN_C XS(boot_Expedition);
#ifdef BOTS
EXTERN_C XS(boot_Bot);
#endif
#endif
#endif
@ -91,6 +94,11 @@ EXTERN_C void xs_init(pTHX)
newXS(strcpy(buf, "Object::boot_Object"), boot_Object, file);
newXS(strcpy(buf, "Doors::boot_Doors"), boot_Doors, file);
newXS(strcpy(buf, "Expedition::boot_Expedition"), boot_Expedition, file);
#ifdef BOTS
newXS(strcpy(buf, "Bot::boot_Mob"), boot_Mob, file);
newXS(strcpy(buf, "Bot::boot_NPC"), boot_NPC, file);
newXS(strcpy(buf, "Bot::boot_Bot"), boot_Bot, file);
#endif
;
#endif
#endif

View File

@ -4769,6 +4769,16 @@ void EntityList::GetClientList(std::list<Client *> &c_list)
}
}
#ifdef BOTS
void EntityList::GetBotList(std::list<Bot *> &b_list)
{
b_list.clear();
for (auto bot_iterator : bot_list) {
b_list.push_back(bot_iterator);
}
}
#endif
void EntityList::GetCorpseList(std::list<Corpse *> &c_list)
{
c_list.clear();

View File

@ -514,6 +514,9 @@ public:
inline const std::unordered_map<uint16, NPC *> &GetNPCList() { return npc_list; }
inline const std::unordered_map<uint16, Merc *> &GetMercList() { return merc_list; }
inline const std::unordered_map<uint16, Client *> &GetClientList() { return client_list; }
#ifdef BOTS
inline const std::list<Bot *> &GetBotList() { return bot_list; }
#endif
inline const std::unordered_map<uint16, Corpse *> &GetCorpseList() { return corpse_list; }
inline const std::unordered_map<uint16, Object *> &GetObjectList() { return object_list; }
inline const std::unordered_map<uint16, Doors *> &GetDoorsList() { return door_list; }
@ -593,6 +596,8 @@ private:
void ShowSpawnWindow(Client* client, int Distance, bool NamedOnly); // TODO: Implement ShowSpawnWindow in the bot class but it needs entity list stuff
void ScanCloseClientMobs(std::unordered_map<uint16, Mob*>& close_mobs, Mob* scanning_mob);
void GetBotList(std::list<Bot*> &b_list);
private:
std::list<Bot*> bot_list;
#endif

13
zone/lua_bot.cpp Normal file
View File

@ -0,0 +1,13 @@
#ifdef LUA_EQEMU
#include "lua.hpp"
#include <luabind/luabind.hpp>
#include "bot.h"
#include "lua_bot.h"
luabind::scope lua_register_bot() {
return luabind::class_<Lua_Bot, Lua_Mob>("Bot").def(luabind::constructor<>());
}
#endif

30
zone/lua_bot.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef EQEMU_LUA_BOT_H
#define EQEMU_LUA_BOT_H
#ifdef LUA_EQEMU
#include "lua_mob.h"
class Bot;
class Lua_Bot;
namespace luabind {
struct scope;
}
luabind::scope lua_register_bot();
class Lua_Bot : public Lua_Mob
{
typedef Bot NativeType;
public:
Lua_Bot() { SetLuaPtrData(nullptr); }
Lua_Bot(Bot *d) { SetLuaPtrData(reinterpret_cast<Entity*>(d)); }
virtual ~Lua_Bot() { }
operator Bot*() {
return reinterpret_cast<Bot*>(GetLuaPtrData());
}
};
#endif
#endif

View File

@ -12,6 +12,10 @@
#include "lua_object.h"
#include "lua_door.h"
#ifdef BOTS
#include "lua_bot.h"
#endif
bool Lua_Entity::IsClient() {
Lua_Safe_Call_Bool();
return self->IsClient();
@ -118,6 +122,14 @@ Lua_Door Lua_Entity::CastToDoor() {
return Lua_Door(m);
}
#ifdef BOTS
Lua_Bot Lua_Entity::CastToBot() {
void *d = GetLuaPtrData();
Bot *b = reinterpret_cast<Bot*>(d);
return Lua_Bot(b);
}
#endif
luabind::scope lua_register_entity() {
return luabind::class_<Lua_Entity>("Entity")
.def(luabind::constructor<>())
@ -138,6 +150,9 @@ luabind::scope lua_register_entity() {
.def("IsBot", &Lua_Entity::IsBot)
.def("GetID", &Lua_Entity::GetID)
.def("CastToClient", &Lua_Entity::CastToClient)
#ifdef BOTS
.def("CastToBot", &Lua_Entity::CastToBot)
#endif
.def("CastToNPC", &Lua_Entity::CastToNPC)
.def("CastToMob", &Lua_Entity::CastToMob)
.def("CastToCorpse", &Lua_Entity::CastToCorpse)

View File

@ -6,6 +6,9 @@
class Entity;
class Lua_Client;
#ifdef BOTS
class Lua_Bot;
#endif
class Lua_NPC;
class Lua_Mob;
struct Lua_HateList;
@ -54,6 +57,9 @@ public:
Lua_Corpse CastToCorpse();
Lua_Object CastToObject();
Lua_Door CastToDoor();
#ifdef BOTS
Lua_Bot CastToBot();
#endif
};
#endif

View File

@ -17,6 +17,10 @@
#include "lua_raid.h"
#include "lua_spawn.h"
#ifdef BOTS
#include "lua_bot.h"
#endif
struct Lua_Mob_List {
std::vector<Lua_Mob> entries;
};
@ -29,6 +33,12 @@ struct Lua_Client_List {
std::vector<Lua_Client> entries;
};
#ifdef BOTS
struct Lua_Bot_List {
std::vector<Lua_Bot> entries;
};
#endif
struct Lua_Corpse_List {
std::vector<Lua_Corpse> entries;
};
@ -345,6 +355,29 @@ Lua_Client_List Lua_EntityList::GetClientList() {
return ret;
}
#ifdef BOTS
Lua_Bot Lua_EntityList::GetBotByID(uint32 bot_id) {
Lua_Safe_Call_Class(Lua_Bot);
return Lua_Bot(self->GetBotByBotID(bot_id));
}
Lua_Bot Lua_EntityList::GetBotByName(std::string bot_name) {
Lua_Safe_Call_Class(Lua_Bot);
return Lua_Bot(self->GetBotByBotName(bot_name));
}
Lua_Bot_List Lua_EntityList::GetBotList() {
Lua_Safe_Call_Class(Lua_Bot_List);
Lua_Bot_List ret;
auto &bot_list = self->GetBotList();
for (auto bot_iterator : bot_list) {
ret.entries.push_back(Lua_Bot(bot_iterator));
}
return ret;
}
#endif
Lua_Client_List Lua_EntityList::GetShuffledClientList() {
Lua_Safe_Call_Class(Lua_Client_List);
Lua_Client_List ret;
@ -502,6 +535,11 @@ luabind::scope lua_register_entity_list() {
.def("GetRandomClient", (Lua_Client(Lua_EntityList::*)(float, float, float, float, Lua_Client))&Lua_EntityList::GetRandomClient)
.def("GetMobList", (Lua_Mob_List(Lua_EntityList::*)(void))&Lua_EntityList::GetMobList)
.def("GetClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetClientList)
#ifdef BOTS
.def("GetBotByID", (Lua_Bot(Lua_EntityList::*)(uint32))&Lua_EntityList::GetBotByID)
.def("GetBotByName", (Lua_Bot(Lua_EntityList::*)(std::string))&Lua_EntityList::GetBotByName)
.def("GetBotList", (Lua_Bot_List(Lua_EntityList::*)(void))&Lua_EntityList::GetBotList)
#endif
.def("GetShuffledClientList", (Lua_Client_List(Lua_EntityList::*)(void))&Lua_EntityList::GetShuffledClientList)
.def("GetNPCList", (Lua_NPC_List(Lua_EntityList::*)(void))&Lua_EntityList::GetNPCList)
.def("GetCorpseList", (Lua_Corpse_List(Lua_EntityList::*)(void))&Lua_EntityList::GetCorpseList)
@ -522,6 +560,13 @@ luabind::scope lua_register_client_list() {
.def_readwrite("entries", &Lua_Client_List::entries, luabind::return_stl_iterator);
}
#ifdef BOTS
luabind::scope lua_register_bot_list() {
return luabind::class_<Lua_Bot_List>("BotList")
.def_readwrite("entries", &Lua_Bot_List::entries, luabind::return_stl_iterator);
}
#endif
luabind::scope lua_register_npc_list() {
return luabind::class_<Lua_NPC_List>("NPCList")
.def_readwrite("entries", &Lua_NPC_List::entries, luabind::return_stl_iterator);

View File

@ -7,6 +7,9 @@
class EntityList;
class Lua_Mob;
class Lua_Client;
#ifdef BOTS
class Lua_Bot;
#endif
class Lua_NPC;
class Lua_Door;
class Lua_Corpse;
@ -16,6 +19,9 @@ class Lua_Raid;
class Lua_Spawn;
struct Lua_Mob_List;
struct Lua_Client_List;
#ifdef BOTS
struct Lua_Bot_List;
#endif
struct Lua_NPC_List;
struct Lua_Corpse_List;
struct Lua_Object_List;
@ -35,6 +41,10 @@ luabind::scope lua_register_object_list();
luabind::scope lua_register_door_list();
luabind::scope lua_register_spawn_list();
#ifdef BOTS
luabind::scope lua_register_bot_list();
#endif
class Lua_EntityList : public Lua_Ptr<EntityList>
{
typedef EntityList NativeType;
@ -110,6 +120,11 @@ public:
Lua_Spawn_List GetSpawnList();
void SignalAllClients(int signal);
void ChannelMessage(Lua_Mob from, int channel_num, int language, const char *message);
#ifdef BOTS
Lua_Bot GetBotByID(uint32 bot_id);
Lua_Bot GetBotByName(std::string bot_name);
Lua_Bot_List GetBotList();
#endif
};
#endif

View File

@ -40,6 +40,10 @@
#include "lua_encounter.h"
#include "lua_stat_bonuses.h"
#ifdef BOTS
#include "lua_bot.h"
#endif
const char *LuaEvents[_LargestEventID] = {
"event_say",
"event_trade",
@ -1090,6 +1094,9 @@ void LuaParser::MapFunctions(lua_State *L) {
lua_register_special_abilities(),
lua_register_npc(),
lua_register_client(),
#ifdef BOTS
lua_register_bot(),
#endif
lua_register_inventory(),
lua_register_inventory_where(),
lua_register_iteminst(),
@ -1101,6 +1108,9 @@ void LuaParser::MapFunctions(lua_State *L) {
lua_register_entity_list(),
lua_register_mob_list(),
lua_register_client_list(),
#ifdef BOTS
lua_register_bot_list(),
#endif
lua_register_npc_list(),
lua_register_corpse_list(),
lua_register_object_list(),

84
zone/perl_bot.cpp Normal file
View File

@ -0,0 +1,84 @@
/* EQEMu: Everquest Server Emulator
Copyright (C) 2001-2004 EQEMu Development Team (http://eqemulator.net)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY except by those people which sell it, which
are required to give you total support for your newly bought product;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../common/features.h"
#ifdef EMBPERL_XS_CLASSES
#include "../common/global_define.h"
#include "embperl.h"
#ifdef seed
#undef seed
#endif
#include "bot.h"
#ifdef THIS
#undef THIS
#endif
#define VALIDATE_THIS_IS_BOT \
do { \
if (sv_derived_from(ST(0), "Bot")) { \
IV tmp = SvIV((SV*)SvRV(ST(0))); \
THIS = INT2PTR(Bot*, tmp); \
} else { \
Perl_croak(aTHX_ "THIS is not of type Bot"); \
} \
if (THIS == nullptr) { \
Perl_croak(aTHX_ "THIS is nullptr, avoiding crash."); \
} \
} while (0);
XS(XS_Bot_GetOwner);
XS(XS_Bot_GetOwner)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Bot::GetOwner(THIS)"); // @categories Script Utility, Bot
{
Bot* THIS;
Mob* bot_owner;
VALIDATE_THIS_IS_BOT;
bot_owner = THIS->GetBotOwner();
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Mob", (void*)bot_owner);
}
XSRETURN(1);
}
#ifdef __cplusplus
extern "C"
#endif
XS(boot_Bot);
XS(boot_Bot)
{
dXSARGS;
char file[256];
strncpy(file, __FILE__, 256);
file[255] = 0;
if (items != 1)
fprintf(stderr, "boot_Bot does not take any arguments.");
char buf[128];
XS_VERSION_BOOTCHECK;
newXSproto(strcpy(buf, "GetOwner"), XS_Bot_GetOwner, file, "$");
XSRETURN_YES;
}
#endif //EMBPERL_XS_CLASSES

View File

@ -1310,6 +1310,64 @@ XS(XS_EntityList_GetClientList) {
XSRETURN(num_clients);
}
#ifdef BOTS
XS(XS_EntityList_GetBotByID);
XS(XS_EntityList_GetBotByID) {
dXSARGS;
int bot_count = 0;
if (items != 2)
Perl_croak(aTHX_ "Usage: EntityList::GetBotByID(THIS, uint32 bot_id)"); // @categories Script Utility, Bot
{
EntityList* THIS;
Bot* RETVAL;
uint32 bot_id = (uint32) SvUV(ST(1));
VALIDATE_THIS_IS_ENTITY;
RETVAL = THIS->GetBotByBotID(bot_id);
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Bot", (void *) RETVAL);
}
XSRETURN(1);
}
XS(XS_EntityList_GetBotByName);
XS(XS_EntityList_GetBotByName) {
dXSARGS;
int bot_count = 0;
if (items != 2)
Perl_croak(aTHX_ "Usage: EntityList::GetBotByName(THIS, string bot_name)"); // @categories Script Utility, Bot
{
EntityList* THIS;
Bot* RETVAL;
std::string bot_name = (std::string) SvPV_nolen(ST(1));
VALIDATE_THIS_IS_ENTITY;
RETVAL = THIS->GetBotByBotName(bot_name);
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Bot", (void *) RETVAL);
}
XSRETURN(1);
}
XS(XS_EntityList_GetBotList);
XS(XS_EntityList_GetBotList) {
dXSARGS;
int bot_count = 0;
if (items != 1)
Perl_croak(aTHX_ "Usage: EntityList::GetBotList(THIS)"); // @categories Script Utility, Bot
{
EntityList *THIS;
VALIDATE_THIS_IS_ENTITY;
auto current_bot_list = THIS->GetBotList();
for (auto bot_iterator : current_bot_list) {
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Bot", (void *)bot_iterator);
XPUSHs(ST(0));
bot_count++;
}
}
XSRETURN(bot_count);
}
#endif
XS(XS_EntityList_GetNPCList); /* prototype to pass -Wmissing-prototypes */
XS(XS_EntityList_GetNPCList) {
dXSARGS;
@ -1517,6 +1575,11 @@ XS(boot_EntityList) {
newXSproto(strcpy(buf, "GetObjectList"), XS_EntityList_GetObjectList, file, "$");
newXSproto(strcpy(buf, "GetDoorsList"), XS_EntityList_GetDoorsList, file, "$");
newXSproto(strcpy(buf, "SignalAllClients"), XS_EntityList_SignalAllClients, file, "$$");
#ifdef BOTS
newXSproto(strcpy(buf, "GetBotByID"), XS_EntityList_GetBotByID, file, "$$");
newXSproto(strcpy(buf, "GetBotByName"), XS_EntityList_GetBotByName, file, "$$");
newXSproto(strcpy(buf, "GetBotList"), XS_EntityList_GetBotList, file, "$");
#endif
XSRETURN_YES;
}

View File

@ -42,6 +42,10 @@ typedef const char Const_char;
#include "client.h"
#include "../common/spdat.h"
#ifdef BOTS
#include "bot.h"
#endif
#ifdef THIS /* this macro seems to leak out on some systems */
#undef THIS
#endif
@ -6253,6 +6257,25 @@ XS(XS_Mob_GetLastName) {
XSRETURN(1);
}
#ifdef BOTS
XS(XS_Mob_CastToBot); /* prototype to pass -Wmissing-prototypes */
XS(XS_Mob_CastToBot)
{
dXSARGS;
if (items != 1)
Perl_croak(aTHX_ "Usage: Mob::CastToBot(THIS)");
{
Mob* THIS;
Bot* RETVAL;
VALIDATE_THIS_IS_MOB;
RETVAL = THIS->CastToBot();
ST(0) = sv_newmortal();
sv_setref_pv(ST(0), "Bot", (void*)RETVAL);
}
XSRETURN(1);
}
#endif
#ifdef __cplusplus
extern "C"
#endif
@ -6602,6 +6625,9 @@ XS(boot_Mob) {
newXSproto(strcpy(buf, "GetHateClosest"), XS_Mob_GetHateClosest, file, "$");
newXSproto(strcpy(buf, "GetHateListByDistance"), XS_Mob_GetHateListByDistance, file, "$;$");
newXSproto(strcpy(buf, "GetLastName"), XS_Mob_GetLastName, file, "$");
#ifdef BOTS
newXSproto(strcpy(buf, "CastToBot"), XS_Mob_CastToBot, file, "$");
#endif
XSRETURN_YES;
}