Merge branch 'master' of https://git.worlio.com/bonkmaykr/Tourbot
This commit is contained in:
commit
ac5b9a7f7f
35
src/client.h
35
src/client.h
|
@ -9,7 +9,7 @@
|
||||||
#include "acfile.h"
|
#include "acfile.h"
|
||||||
#define BUFFERSIZE 4096
|
#define BUFFERSIZE 4096
|
||||||
|
|
||||||
bool debug = false;
|
bool debug = true;
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 rng(rd());
|
std::mt19937 rng(rd());
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ const std::string user_agent = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.
|
||||||
std::string confFile = "conf/bot.conf";
|
std::string confFile = "conf/bot.conf";
|
||||||
ACFile* mainConf;
|
ACFile* mainConf;
|
||||||
ACFile* worldlist;
|
ACFile* worldlist;
|
||||||
|
ACFile* marksLUT;
|
||||||
ACFile* replylist;
|
ACFile* replylist;
|
||||||
AMFile* messages;
|
AMFile* messages;
|
||||||
ALFile* filth;
|
ALFile* filth;
|
||||||
|
@ -49,7 +50,7 @@ uint16_t roomport = 5672;
|
||||||
|
|
||||||
std::string login_username;
|
std::string login_username;
|
||||||
std::string login_password;
|
std::string login_password;
|
||||||
std::string avatar = "avatar:pengo.mov";
|
std::string avatar = "http://files.worlio.com/users/bonkmaykr/avatarsforme/gabu1s*4h*4v*.mov";
|
||||||
|
|
||||||
// Needs to include dimension too
|
// Needs to include dimension too
|
||||||
std::string room;
|
std::string room;
|
||||||
|
@ -57,7 +58,7 @@ uint16_t roomID = 1;
|
||||||
|
|
||||||
int protocol = 24;
|
int protocol = 24;
|
||||||
char* version = "1000000000";
|
char* version = "1000000000";
|
||||||
int avatars = 253;
|
int avatars = 253; // avoid culling users if possible... what could go wrong?
|
||||||
int keepAliveTime;
|
int keepAliveTime;
|
||||||
|
|
||||||
uint16_t xPos = 0;
|
uint16_t xPos = 0;
|
||||||
|
@ -70,6 +71,30 @@ std::map<char, char*> properties;
|
||||||
std::map<char, Drone*> objects;
|
std::map<char, Drone*> objects;
|
||||||
std::vector<Group> groups;
|
std::vector<Group> groups;
|
||||||
|
|
||||||
|
namespace internalTypes {
|
||||||
|
struct dronePositionI {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int z;
|
||||||
|
int yaw;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dronePositionF {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float z;
|
||||||
|
float yaw;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct markEntry {
|
||||||
|
std::string name;
|
||||||
|
std::string url;
|
||||||
|
std::string room;
|
||||||
|
dronePositionI position;
|
||||||
|
bool blacklist;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
void loadConfig();
|
void loadConfig();
|
||||||
int deinit(int response);
|
int deinit(int response);
|
||||||
void autoInit();
|
void autoInit();
|
||||||
|
@ -101,6 +126,10 @@ void sendGroupMessage(Group* g, int *sock, std::string message);
|
||||||
void safeDeleteGroupMember(Group* g, std::string member);
|
void safeDeleteGroupMember(Group* g, std::string member);
|
||||||
void qsend(int *sock, unsigned char str[], bool queue);
|
void qsend(int *sock, unsigned char str[], bool queue);
|
||||||
|
|
||||||
|
void handleTeleportRequest(internalTypes::markEntry details);
|
||||||
|
void handleTour(std::string destination[4]);
|
||||||
|
void lookUpWorldName(std::string alias, char* buffer);
|
||||||
|
|
||||||
Drone* getDrone(std::string name) {
|
Drone* getDrone(std::string name) {
|
||||||
for (auto o : objects)
|
for (auto o : objects)
|
||||||
if (o.second->name == name) return o.second;
|
if (o.second->name == name) return o.second;
|
||||||
|
|
122
src/main.cpp
122
src/main.cpp
|
@ -11,6 +11,7 @@
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
//#include <vector>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
#define CURL_STATICLIB
|
#define CURL_STATICLIB
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
@ -32,6 +34,13 @@
|
||||||
#include "props.h"
|
#include "props.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
|
// Global variables used to prevent things from derailing
|
||||||
|
bool onTour = false;
|
||||||
|
std::string tourQueue[4];
|
||||||
|
std::string realLocation;
|
||||||
|
json worldsmarks;
|
||||||
|
|
||||||
|
|
||||||
class QueuedPacket {
|
class QueuedPacket {
|
||||||
public:
|
public:
|
||||||
QueuedPacket() {};
|
QueuedPacket() {};
|
||||||
|
@ -61,9 +70,10 @@ int main(int argc, char const* argv[]) {
|
||||||
printf("info: primary conf file set to \"%s\"\n", confFile.c_str());
|
printf("info: primary conf file set to \"%s\"\n", confFile.c_str());
|
||||||
}
|
}
|
||||||
loadConfig();
|
loadConfig();
|
||||||
/*for (auto const& c : mainConf->get()) {
|
|
||||||
printf("info: (%s),(%s)\n", c.first.c_str(), c.second.c_str());
|
// initialize teleportation ability
|
||||||
}*/
|
realLocation = mainConf->getValue("world", "http://jett.dacii.net/jett/Recreated%20Worlds/SummersGZ/groundzero%20summers.world");
|
||||||
|
|
||||||
autoInit();
|
autoInit();
|
||||||
while (autoOnline || roomOnline) {
|
while (autoOnline || roomOnline) {
|
||||||
while (!roomOnline) {} // We require the room but get disconnected from auto after awhile
|
while (!roomOnline) {} // We require the room but get disconnected from auto after awhile
|
||||||
|
@ -84,6 +94,7 @@ int main(int argc, char const* argv[]) {
|
||||||
void loadConfig() {
|
void loadConfig() {
|
||||||
mainConf = new ACFile(confFile.c_str());
|
mainConf = new ACFile(confFile.c_str());
|
||||||
worldlist = new ACFile(mainConf->getValue("worldfile", "conf/worldlist.conf").c_str());
|
worldlist = new ACFile(mainConf->getValue("worldfile", "conf/worldlist.conf").c_str());
|
||||||
|
marksLUT = new ACFile(mainConf->getValue("lutfile", "conf/lut.conf").c_str());
|
||||||
replylist = new ACFile(mainConf->getValue("replyfile", "conf/replies.conf").c_str());
|
replylist = new ACFile(mainConf->getValue("replyfile", "conf/replies.conf").c_str());
|
||||||
messages = new AMFile(mainConf->getValue("messages", "conf/messages.list").c_str());
|
messages = new AMFile(mainConf->getValue("messages", "conf/messages.list").c_str());
|
||||||
filth = new ALFile(mainConf->getValue("filthlist", "conf/filth.list").c_str());
|
filth = new ALFile(mainConf->getValue("filthlist", "conf/filth.list").c_str());
|
||||||
|
@ -99,6 +110,23 @@ void loadConfig() {
|
||||||
spin = mainConf->getInt("spin", 0);
|
spin = mainConf->getInt("spin", 0);
|
||||||
keepAliveTime = mainConf->getInt("katime", 15);
|
keepAliveTime = mainConf->getInt("katime", 15);
|
||||||
debug = mainConf->getInt("debug", 0) == 1;
|
debug = mainConf->getInt("debug", 0) == 1;
|
||||||
|
|
||||||
|
// parse json routine
|
||||||
|
//
|
||||||
|
// data structure per entry is as follows:
|
||||||
|
// name (friendly name used during tours)
|
||||||
|
// url (the file location)
|
||||||
|
// room (the chatroom ID for the roomserver)
|
||||||
|
// position (an array containing the bot's resting position for that world while on tour)
|
||||||
|
// position is an array with a length of 4, containing X, Y, Z, and yaw in that order.
|
||||||
|
// blacklist (bool which skips the world during diceroll tours)
|
||||||
|
// useful for preventing GZ reskins from appearing, exceptions made where appropriate
|
||||||
|
// blacklisted worlds still need a specified idle position!
|
||||||
|
//
|
||||||
|
// feature idea: commentary/notes keyvalue pair which the bot will speak when entering a certain world, used to give tips ??
|
||||||
|
|
||||||
|
std::ifstream dictionaryStream("conf/marks.json"); // look for worldsmarks database in the configuration folder and open it
|
||||||
|
worldsmarks = json::parse(dictionaryStream); // parse and remember data globally
|
||||||
}
|
}
|
||||||
|
|
||||||
int deinit(int response) {
|
int deinit(int response) {
|
||||||
|
@ -172,8 +200,8 @@ void roomKeepAlive() {
|
||||||
void autoRandMessage() {
|
void autoRandMessage() {
|
||||||
int minTime = mainConf->getInt("minRandomMsgTime", 0);
|
int minTime = mainConf->getInt("minRandomMsgTime", 0);
|
||||||
int maxTime = mainConf->getInt("maxRandomMsgTime", 0);
|
int maxTime = mainConf->getInt("maxRandomMsgTime", 0);
|
||||||
int wait = 0;
|
int wait = 600;
|
||||||
sendChatMessage(&roomsock, messages->getMessage("startup"));
|
//sendChatMessage(&roomsock, messages->getMessage("startup"));
|
||||||
if (minTime != 0) {
|
if (minTime != 0) {
|
||||||
while (roomOnline) {
|
while (roomOnline) {
|
||||||
if (wait != 0) {
|
if (wait != 0) {
|
||||||
|
@ -349,10 +377,14 @@ void reciever(int *sock, uint16_t port, bool* status) {
|
||||||
*status = false;
|
*status = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this only works correctly if using POSIX-compliant line endings in the bot.conf file
|
||||||
|
// CR+LF breaks everything, should probably fix this if this becomes widely used at any point!
|
||||||
void sessInit(int *sock, std::string username, std::string password) {
|
void sessInit(int *sock, std::string username, std::string password) {
|
||||||
bufout[1] = 0x01;
|
bufout[1] = 0x01;
|
||||||
bufout[2] = CMD_SESSINIT;
|
bufout[2] = CMD_SESSINIT;
|
||||||
int l = 3;
|
int l = 3; // packet construction buffer
|
||||||
|
|
||||||
|
std::cout << "Logging in with screenname " + username + "\n"; //debug
|
||||||
|
|
||||||
// Username
|
// Username
|
||||||
bufout[l++] = 2;
|
bufout[l++] = 2;
|
||||||
|
@ -395,6 +427,7 @@ void sessInit(int *sock, std::string username, std::string password) {
|
||||||
|
|
||||||
bufout[0] = l;
|
bufout[0] = l;
|
||||||
bufout[l+1] = 0;
|
bufout[l+1] = 0;
|
||||||
|
|
||||||
qsend(sock, bufout, false);
|
qsend(sock, bufout, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -755,6 +788,39 @@ bool handleGroups(char* buffer, std::string from, std::string message) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unimplemented
|
||||||
|
void handleTeleportRequest(internalTypes::markEntry details) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// unimplemented
|
||||||
|
void handleTour(std::string destination[4]) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid redundant CTRL + V code in handlePhrase()
|
||||||
|
void lookUpWorldName(std::string alias, char* buffer/*replies*/) {
|
||||||
|
auto key = worldsmarks.find(alias);
|
||||||
|
if (key != worldsmarks.end()) {
|
||||||
|
std::cout << "info: found world \"" + alias + "\", teleporting.";
|
||||||
|
internalTypes::markEntry details;
|
||||||
|
details.name = (*key)["name"].get<std::string>();
|
||||||
|
details.url = (*key)["url"].get<std::string>();
|
||||||
|
details.room = (*key)["room"].get<std::string>();
|
||||||
|
|
||||||
|
details.position.x = (*key)["position"][0];
|
||||||
|
details.position.y = (*key)["position"][1];
|
||||||
|
details.position.z = (*key)["position"][2];
|
||||||
|
details.position.yaw = (*key)["position"][3];
|
||||||
|
|
||||||
|
handleTeleportRequest(details);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::cout << "ERROR: no world with the name \"" + alias + "\" exists! aborting teleport request\n";
|
||||||
|
sprintf(buffer, mainConf->getValue("world_not_found_msg", "Sorry, I don't know that one.").c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool handlePhrase(char* buffer, std::string from, std::string message) {
|
bool handlePhrase(char* buffer, std::string from, std::string message) {
|
||||||
std::vector<std::string> args = split(message, ' ');
|
std::vector<std::string> args = split(message, ' ');
|
||||||
if (strcontains("flip a coin", message)) {
|
if (strcontains("flip a coin", message)) {
|
||||||
|
@ -780,6 +846,31 @@ bool handlePhrase(char* buffer, std::string from, std::string message) {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// in the interest of making things easier programmatically
|
||||||
|
// i want to generate LUTs to map phrases to the JSON
|
||||||
|
// which will allow aliases for each entry in the db
|
||||||
|
//
|
||||||
|
// having an admin command like "makelut" to instantly generate these
|
||||||
|
// by recursively scanning the marks file would be nice
|
||||||
|
else if (strcontains("take me to", message)) {
|
||||||
|
std::cout << "info: remote user requested teleportation!\n";
|
||||||
|
// lookup LUT first for aliases and then check JSON for key
|
||||||
|
// using worldsmarks.find(message) if no alias present
|
||||||
|
// spit back error if both are blank
|
||||||
|
|
||||||
|
std::string alias = getValueOfIncludedName(marksLUT->get(), message);
|
||||||
|
if (alias.length() > 0) {
|
||||||
|
std::cout << "info: found world with alias \"" + message + "\" in lookup table.\n";
|
||||||
|
lookUpWorldName(alias, buffer);
|
||||||
|
}
|
||||||
|
else { // we didn't find an alias, search the DB directly
|
||||||
|
std::cout << "info: no world with the alias \"" + message + "\" is in the lookup table.\n";
|
||||||
|
lookUpWorldName(message, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,6 +902,7 @@ void processText(int *sock, std::string username, std::string message) {
|
||||||
} else if (lowermsg == "ping") {
|
} else if (lowermsg == "ping") {
|
||||||
sprintf(msgout, mainConf->getValue("pong_msg", "Pong!").c_str());
|
sprintf(msgout, mainConf->getValue("pong_msg", "Pong!").c_str());
|
||||||
sendChatMessage(sock, std::string(msgout));
|
sendChatMessage(sock, std::string(msgout));
|
||||||
|
} else if (lowermsg.find("http") != std::string::npos) {
|
||||||
} else if (lowermsg.find("http") != std::string::npos) {
|
} else if (lowermsg.find("http") != std::string::npos) {
|
||||||
int pos;
|
int pos;
|
||||||
if ((pos = lowermsg.find("http://")) != std::string::npos || (pos = lowermsg.find("https://")) != std::string::npos) {
|
if ((pos = lowermsg.find("http://")) != std::string::npos || (pos = lowermsg.find("https://")) != std::string::npos) {
|
||||||
|
@ -866,6 +958,24 @@ void processWhisper(int *sock, std::string username, std::string message) {
|
||||||
}
|
}
|
||||||
sendWhisperMessage(sock, username, msgout);
|
sendWhisperMessage(sock, username, msgout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// needs to process geolocation requests and respond with a file path for valid teleporting
|
||||||
|
if (lowermsg == "&|+where?") {
|
||||||
|
// intentionally omit bot location if we're touring so players always start at world start
|
||||||
|
// the bot should ideally be placed in the same starting room, within the player's view as soon as they spawn
|
||||||
|
//
|
||||||
|
// doing it this way requires that we handle bookmark room IDs separately from the destination URL
|
||||||
|
if (onTour == true) {
|
||||||
|
std::cout << "info: touring, sending truncated location\n";
|
||||||
|
sendWhisperMessage(sock, username, "&|+where>" + realLocation + "#" + room);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// are all these concats really fucking neccessary?
|
||||||
|
std::cout << "info: not touring, sending full location\n";
|
||||||
|
sendWhisperMessage(sock, username, "&|+where>" + realLocation + "#" + room
|
||||||
|
+ "@" + std::to_string(xPos) + "," + std::to_string(yPos) + "," + std::to_string(zPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendChatMessage(int *sock, std::string msg) {
|
void sendChatMessage(int *sock, std::string msg) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user