forked from Wirlaburla/P3NG0
pengo time
This commit is contained in:
commit
c7faeb0441
7
CMakeLists.txt
Normal file
7
CMakeLists.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(pengobot)
|
||||
SET(CMAKE_CXX_STANDARD 17)
|
||||
SET(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
SET(CMAKE_CXX_FLAGS "-O3")
|
||||
add_subdirectory(src)
|
||||
install(TARGETS pengobot RUNTIME DESTINATION bin)
|
7
conf.examples/attentions.messages
Normal file
7
conf.examples/attentions.messages
Normal file
|
@ -0,0 +1,7 @@
|
|||
hey pengo
|
||||
hey p3ng0
|
||||
p3ng0
|
||||
yo pengo
|
||||
yo p3ng0
|
||||
hello p3ng0
|
||||
aloha p3ng0
|
1
conf.examples/goodbyes.messages
Normal file
1
conf.examples/goodbyes.messages
Normal file
|
@ -0,0 +1 @@
|
|||
Goodbye!
|
3
conf.examples/greets.messages
Normal file
3
conf.examples/greets.messages
Normal file
|
@ -0,0 +1,3 @@
|
|||
Hi, I'm P3NG0, your friendly Worlds bot.
|
||||
My initialization is complete.
|
||||
Beep boop!
|
44
conf.examples/pengobot.conf
Normal file
44
conf.examples/pengobot.conf
Normal file
|
@ -0,0 +1,44 @@
|
|||
# This is the configuration file for PengoBot.
|
||||
|
||||
# The username you log in as. Account must be registered on worlds servers.
|
||||
username=Clem
|
||||
|
||||
# The password to the username above.
|
||||
password=hackme
|
||||
|
||||
# The username who owns the bot. This is for administrative actions.
|
||||
owner=Thom
|
||||
|
||||
# The URL to whisper users when asking for bot help.
|
||||
help_url=
|
||||
|
||||
# Bot avatar. Must be VIP for articulated to show up.
|
||||
avatar=http://files.worlio.com/users/wirlaburla/avatars/pengobot.mov
|
||||
|
||||
# The position in the world that the bot will sit.
|
||||
xpos=0
|
||||
ypos=0
|
||||
zpos=0
|
||||
direction=0
|
||||
|
||||
# Every 'keep alive', will turn x degrees.
|
||||
spin=0
|
||||
|
||||
# Keep alive interval. Setting this too long will make worlds disconnect you.
|
||||
katime=5
|
||||
|
||||
# The time between random messages. The wait period is between minRandomMsgTime and maxRandomMsgTime. Setting these to 0 will disable.
|
||||
msg_random=conf/randoms.messages
|
||||
minRandomMsgTime=300
|
||||
maxRandomMsgTime=900
|
||||
|
||||
# Local database of worlds and their names.
|
||||
msg_whereis=conf/whereis.messages
|
||||
worldfile=conf/worlds.conf
|
||||
|
||||
# Other responses.
|
||||
msg_attention=conf/attentions.messages
|
||||
msg_greet=conf/greets.messages
|
||||
msg_goodbye=conf/goodbyes.messages
|
||||
msg_unknowncmd=conf/unknowncmd.messages
|
||||
msg_whoami=conf/whoami.messages
|
2
conf.examples/randoms.messages
Normal file
2
conf.examples/randoms.messages
Normal file
|
@ -0,0 +1,2 @@
|
|||
kiwi
|
||||
mongolia
|
4
conf.examples/unknowncmd.messages
Normal file
4
conf.examples/unknowncmd.messages
Normal file
|
@ -0,0 +1,4 @@
|
|||
Sorry, I don't know what you're asking.
|
||||
I am unsure of your request.
|
||||
ERROR: DIVISION BY ZERO
|
||||
Need something?
|
4
conf.examples/whereis.messages
Normal file
4
conf.examples/whereis.messages
Normal file
|
@ -0,0 +1,4 @@
|
|||
It's right here: %s
|
||||
%s
|
||||
Here is your mark: %s
|
||||
Found it! %s
|
2
conf.examples/whoami.messages
Normal file
2
conf.examples/whoami.messages
Normal file
|
@ -0,0 +1,2 @@
|
|||
Hi, I'm P3NG0. I'm a friendly bot.
|
||||
I am here to annihilate the human race.
|
8
conf.examples/worlds.conf
Normal file
8
conf.examples/worlds.conf
Normal file
|
@ -0,0 +1,8 @@
|
|||
beach=http://ittraining.net/jimbly/groundzero.world
|
||||
mugshots=http://ittraining.net/jimbly/mugshots.world
|
||||
tyler=http://worlio.com/users/dsparil/Tyler%20World/tyler.world
|
||||
party cave=http://www.ittraining.net/waterworld/waterworld.world
|
||||
texas=http://ittraining.net/jimbly/texas01.world
|
||||
cybergz=http://files.worlio.com/users/dosfox/sybergz/cybergz_cur.world
|
||||
alien mystery=http://files.worlio.com/users/bilbo99/AlienMystery/alien.world
|
||||
decennary=http://files.worlio.com/users/sl0nderman/worlds/decennary.world
|
4
src/CMakeLists.txt
Normal file
4
src/CMakeLists.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
add_executable(pengobot
|
||||
main.cpp
|
||||
)
|
||||
target_link_libraries(pengobot)
|
78
src/client.h
Normal file
78
src/client.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
#ifndef H_CLIENT
|
||||
#define H_CLIENT
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include "drone.h"
|
||||
#include "config.h"
|
||||
PengoConfig conf;
|
||||
bool debug = false;
|
||||
|
||||
#define BUFFERSIZE 65535
|
||||
|
||||
bool autoOnline = false;
|
||||
bool roomOnline = false;
|
||||
|
||||
unsigned char bufout[BUFFERSIZE] = {0};
|
||||
int randWait;
|
||||
|
||||
int autosock;
|
||||
int roomsock;
|
||||
|
||||
std::thread aRecv_t;
|
||||
std::thread rRecv_t;
|
||||
std::thread rKeepAlive_t;
|
||||
std::thread rAutoMsg_t;
|
||||
|
||||
uint8_t autoserver[4] = { 209, 240, 84, 122 };
|
||||
uint16_t autoport = 6650;
|
||||
uint8_t roomserver[4] = { 209, 240, 84, 122 };
|
||||
uint16_t roomport = 5672;
|
||||
|
||||
std::string login_username;
|
||||
std::string login_password;
|
||||
std::string avatar = "avatar:pengo.mov";
|
||||
|
||||
// Needs to include dimension too
|
||||
std::string room;
|
||||
uint16_t roomID = 1;
|
||||
|
||||
int protocol = 24;
|
||||
char* version = "1000000000";
|
||||
int avatars = 253;
|
||||
int keepAliveTime;
|
||||
|
||||
uint16_t xPos = 0;
|
||||
uint16_t yPos = 0;
|
||||
uint16_t zPos = 0;
|
||||
uint16_t direction = 0;
|
||||
uint16_t spin = 0;
|
||||
|
||||
std::map<char, char*> properties;
|
||||
std::map<char, Drone> objects;
|
||||
|
||||
int deinit(int response);
|
||||
static char* trim(char *str);
|
||||
char* zero(int size);
|
||||
unsigned char* uzero(int size);
|
||||
void autoInit();
|
||||
void roomInit();
|
||||
void roomKeepAlive();
|
||||
void autoRandMessage();
|
||||
void reciever(int *sock, uint16_t port);
|
||||
void sessInit(int *sock, std::string username, std::string password);
|
||||
void sessExit(int *sock);
|
||||
void readPropertyList(unsigned char* in);
|
||||
std::map<char, char*> readOldPropertyList(unsigned char* in);
|
||||
void setAvatar(int *sock, std::string avatar);
|
||||
void roomIDReq(int *sock, std::string room);
|
||||
void teleport(int *sock, int x, int y, int z, int rot);
|
||||
char* dimAdd(std::string room);
|
||||
bool strcontains(std::string needle, std::string haystack);
|
||||
bool vstrcontains(std::string needle, std::vector<std::string> haystack);
|
||||
void processText(int *sock, std::string username, std::string message);
|
||||
void processWhisper(int *sock, std::string username, std::string message);
|
||||
void sendChatMessage(int *sock, std::string msg);
|
||||
void sendWhisperMessage(int *sock, std::string to, std::string msg);
|
||||
int wsend(int *sock, unsigned char str[], int flags);
|
||||
|
||||
#endif
|
34
src/cmds.h
Normal file
34
src/cmds.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef H_CMDS
|
||||
#define H_CMDS
|
||||
|
||||
#define CMD_LONGLOC 1
|
||||
#define CMD_STATE 2
|
||||
#define CMD_PROP 3
|
||||
#define CMD_SHORTLOC 4
|
||||
#define CMD_ROOMCHANGE 5
|
||||
#define CMD_SESSINIT 6
|
||||
#define CMD_SESSEXIT 7
|
||||
#define CMD_APPINIT 9
|
||||
#define CMD_PROPREQ 10
|
||||
#define CMD_ACTOR_DISAPPR 11
|
||||
#define CMD_ACTOR_APPR 12
|
||||
#define CMD_REGOBJID 13
|
||||
#define CMD_CHATMSG 14
|
||||
#define CMD_PROPSET 15
|
||||
#define CMD_PROPUPD 16
|
||||
#define CMD_WHISPER 17
|
||||
#define CMD_TELEPORT 18
|
||||
#define CMD_ROOMIDREQ 20
|
||||
#define CMD_ROOMID 21
|
||||
#define CMD_SUBSCRIBE 22
|
||||
#define CMD_UNSUBSCRIBE 23
|
||||
#define CMD_SUBDIST 24
|
||||
#define CMD_REDIRECT 25
|
||||
#define CMD_REDIRID 26
|
||||
#define CMD_FINGREQ 27
|
||||
#define CMD_FINGREP 28
|
||||
#define CMD_BUDDYUPD 29
|
||||
#define CMD_BUDDYNTF 30
|
||||
#define CMD_CHANNEL 31
|
||||
|
||||
#endif
|
96
src/config.h
Normal file
96
src/config.h
Normal file
|
@ -0,0 +1,96 @@
|
|||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <stdlib.h>
|
||||
|
||||
class PengoConfig {
|
||||
public:
|
||||
PengoConfig() {
|
||||
std::ifstream mconf("conf/pengobot.conf");
|
||||
|
||||
std::string line;
|
||||
while (std::getline(mconf, line)) {
|
||||
// Check if line is a comment line.
|
||||
if (line.rfind("#", 0) != 0) {
|
||||
std::string name = line.substr(0, line.find("="));
|
||||
std::string value = line.substr(line.find("=")+1, line.length());
|
||||
std::cout << name << ": \"" << value << "\"" << std::endl;
|
||||
conf[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& mc : conf) {
|
||||
std::string msgName;
|
||||
if ((mc.first.substr(0, mc.first.find("_"))) == "msg") {
|
||||
msgName = mc.first.substr(mc.first.find("_")+1, mc.first.length());
|
||||
std::ifstream msglines(mc.second);
|
||||
std::string line;
|
||||
std::vector<std::string> lines;
|
||||
while (std::getline(msglines, line)) {
|
||||
if (line.rfind("#", 0) != 0) {
|
||||
lines.push_back(line);
|
||||
std::cout << msgName << "=" << line << std::endl;
|
||||
}
|
||||
}
|
||||
messages[msgName] = lines;
|
||||
}
|
||||
}
|
||||
|
||||
if ((conf["worldfile"]).length() > 0) {
|
||||
std::ifstream wrlds(conf["worldfile"]);
|
||||
std::string wline;
|
||||
while (std::getline(wrlds, wline)) {
|
||||
if (wline.rfind("#", 0) != 0) {
|
||||
std::string name = wline.substr(0, wline.find("="));
|
||||
std::string value = wline.substr(wline.find("=")+1, wline.length());
|
||||
std::cout << name << ": \"" << value << "\"" << std::endl;
|
||||
worlds[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PengoConfig operator = (PengoConfig *pc) { return *pc; };
|
||||
|
||||
std::string getValue(std::string name, std::string def) {
|
||||
if (((std::string)conf[name]).length() > 0) return conf[name];
|
||||
else return def;
|
||||
}
|
||||
|
||||
int getInt(std::string name, int def) {
|
||||
if (((std::string)conf[name]).length() > 0) return std::stoi(conf[name]);
|
||||
else return def;
|
||||
}
|
||||
|
||||
void setValue(std::string name, std::string value) {
|
||||
conf[name] = value;
|
||||
}
|
||||
|
||||
void setInt(std::string name, int value) {
|
||||
conf[name] = std::to_string(value);
|
||||
}
|
||||
|
||||
std::string getMessage(std::string type) {
|
||||
return (messages[type])[(int)(rand() % ((messages[type]).size()))];
|
||||
}
|
||||
|
||||
std::vector<std::string> getMessages(std::string type) {
|
||||
return messages[type];
|
||||
}
|
||||
|
||||
std::string getWorld(std::string name) {
|
||||
return worlds[name];
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> getWorlds() {
|
||||
return worlds;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> conf;
|
||||
std::map<std::string, std::string> worlds;
|
||||
std::map<std::string, std::vector<std::string>> messages;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
15
src/drone.h
Normal file
15
src/drone.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef H_DRONE
|
||||
#define H_DRONE
|
||||
|
||||
class Drone {
|
||||
public:
|
||||
bool droneActive = false;
|
||||
char* name = new char[24];
|
||||
|
||||
Drone() { };
|
||||
Drone(char* &_name) : name{ _name } { };
|
||||
bool operator != (Drone &d) { return strcmp(this->name, d.name) != 0; };
|
||||
Drone operator = (Drone *d) { return *d; };
|
||||
};
|
||||
|
||||
#endif
|
623
src/main.cpp
Normal file
623
src/main.cpp
Normal file
|
@ -0,0 +1,623 @@
|
|||
#include <map>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <ctime>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <iomanip>
|
||||
|
||||
#include "strutils.h"
|
||||
#include "client.h"
|
||||
#include "verrors.h.h"
|
||||
#include "cmds.h"
|
||||
#include "props.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
static char* toLower(char* str) {
|
||||
for(int i = 0; str[i]; i++){
|
||||
str[i] = std::tolower(str[i]);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static std::string toLower(std::string str) {
|
||||
std::transform(str.begin(), str.end(), str.begin(),
|
||||
[](unsigned char c){ return std::tolower(c); });
|
||||
return str;
|
||||
}
|
||||
|
||||
static char* trim(char *str) {
|
||||
char *end;
|
||||
while(isspace(*str))
|
||||
str++;
|
||||
if(*str == 0)
|
||||
return str;
|
||||
end = str + strnlen(str, 128) - 1;
|
||||
while(end > str && isspace(*end))
|
||||
end--;
|
||||
*(end+1) = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
int main(int argc, char const* argv[]) {
|
||||
srand (time(NULL));
|
||||
// Setting config values.
|
||||
login_username = (conf.getValue("username", ""));
|
||||
login_password = (conf.getValue("password", ""));
|
||||
room = (conf.getValue("room", "GroundZero#Reception<dimension-1>"));
|
||||
avatar = (conf.getValue("avatar", "avatar:pengo.mov"));
|
||||
xPos = conf.getInt("xpos", 0);
|
||||
yPos = conf.getInt("ypos", 0);
|
||||
zPos = conf.getInt("zpos", 0);
|
||||
direction = conf.getInt("direction", 0);
|
||||
spin = conf.getInt("spin", 45);
|
||||
keepAliveTime = conf.getInt("katime", 15);
|
||||
debug = conf.getInt("debug", 0) == 1;
|
||||
autoInit();
|
||||
while (autoOnline) {
|
||||
while (!roomOnline) {}
|
||||
sleep(1);
|
||||
}
|
||||
return deinit(0);
|
||||
}
|
||||
|
||||
int deinit(int response) {
|
||||
sendChatMessage(&roomsock, conf.getMessage("goodbye"));
|
||||
if (roomOnline) sessExit(&roomsock);
|
||||
roomOnline = false;
|
||||
if (autoOnline) sessExit(&autosock);
|
||||
autoOnline = false;
|
||||
if (aRecv_t.joinable()) aRecv_t.detach();
|
||||
if (rRecv_t.joinable()) rRecv_t.detach();
|
||||
if (rKeepAlive_t.joinable()) rKeepAlive_t.detach();
|
||||
close(autosock);
|
||||
close(roomsock);
|
||||
return response;
|
||||
}
|
||||
|
||||
void autoInit() {
|
||||
sockaddr_in auto_addr;
|
||||
auto_addr.sin_family = AF_INET;
|
||||
memcpy((void*)&auto_addr.sin_addr.s_addr, (void*)&autoserver, sizeof(roomserver));
|
||||
auto_addr.sin_port = htons(autoport);
|
||||
|
||||
if ((autosock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
perror("AutoSock creation error");
|
||||
|
||||
if (connect(autosock, (struct sockaddr*)&auto_addr, sizeof(auto_addr)) < 0)
|
||||
perror("AutoServ connection failed");
|
||||
|
||||
aRecv_t = std::thread(reciever, &autosock, autoport);
|
||||
wsend(&autosock, new unsigned char[] {0x03, 0xff, CMD_PROPREQ}, 0);
|
||||
printf("info: Connected to AutoServer: %i.%i.%i.%i:%i\n", autoserver[1], autoserver[1], autoserver[2], autoserver[3], autoport);
|
||||
sessInit(&autosock, login_username, login_password);
|
||||
autoOnline = true;
|
||||
}
|
||||
|
||||
void roomInit() {
|
||||
sockaddr_in room_addr;
|
||||
room_addr.sin_family = AF_INET;
|
||||
memcpy((void*)&room_addr.sin_addr.s_addr, (void*)&roomserver, sizeof(roomserver));
|
||||
room_addr.sin_port = htons(roomport);
|
||||
|
||||
if ((roomsock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
|
||||
perror("AutoSock creation error");
|
||||
|
||||
if ((connect(roomsock, (struct sockaddr*)&room_addr, sizeof(room_addr))) < 0)
|
||||
perror("RoomServ connection failed");
|
||||
|
||||
wsend(&autosock, new unsigned char[] {0x03, 0xff, CMD_PROPREQ}, 0);
|
||||
printf("info: Connected to RoomServer: %i.%i.%i.%i:%i\n", roomserver[1], roomserver[1], roomserver[2], roomserver[3], roomport);
|
||||
roomOnline = true;
|
||||
rRecv_t = std::thread(reciever, &roomsock, roomport);
|
||||
sessInit(&roomsock, login_username, login_password);
|
||||
sleep(1);
|
||||
rKeepAlive_t = std::thread(roomKeepAlive);
|
||||
rAutoMsg_t = std::thread(autoRandMessage);
|
||||
}
|
||||
|
||||
void roomKeepAlive() {
|
||||
while (roomOnline) {
|
||||
if (direction >= 360) direction = 0;
|
||||
else direction+=spin;
|
||||
teleport(&roomsock, xPos, yPos, zPos, direction);
|
||||
sleep(keepAliveTime); // So we don't auto-disconnect.
|
||||
}
|
||||
printf("warning: room keep alive disconnected!\n");
|
||||
}
|
||||
|
||||
void autoRandMessage() {
|
||||
int minTime = conf.getInt("minRandomMsgTime", 0);
|
||||
int maxTime = conf.getInt("maxRandomMsgTime", 0);
|
||||
int wait = 0;
|
||||
sleep(2);
|
||||
sendChatMessage(&roomsock, conf.getMessage("greet"));
|
||||
if (minTime != 0) {
|
||||
while (roomOnline) {
|
||||
if (wait != 0) {
|
||||
std::string newMsg = conf.getMessage("random");
|
||||
if (debug) printf("debug: automsg: \"%s\"\n", newMsg.c_str());
|
||||
sendChatMessage(&roomsock, newMsg);
|
||||
}
|
||||
wait = rand() % minTime + maxTime;
|
||||
if (debug) printf("debug: waiting %i seconds for next message.\n", wait);
|
||||
sleep(wait);
|
||||
}
|
||||
}
|
||||
printf("warning: room auto-messenger disconnected! Ignore if minRandomMsgTime is 0.\n");
|
||||
}
|
||||
|
||||
void reciever(int *sock, uint16_t port) {
|
||||
unsigned char bufin[BUFFERSIZE] = {};
|
||||
while (read(*sock, bufin, sizeof(bufin)) > 0) {
|
||||
int p = 0;
|
||||
more_in_buffer:
|
||||
int buflen = bufin[p];
|
||||
if (buflen == 0x00) continue;
|
||||
memset(&(bufout[0]), 0, sizeof(bufout));
|
||||
if (bufin[p+2] == CMD_PROPUPD && bufin[p+1] == 0xff) {
|
||||
readPropertyList(bufin);
|
||||
} else if (bufin[p+2] == CMD_CHATMSG && bufin[p+1] == 0x01) {
|
||||
char *username = new char[32];
|
||||
char *message = new char[250];
|
||||
int offs = p+3;
|
||||
offs++; // Ignore empty byte
|
||||
int username_len = bufin[offs++];
|
||||
memcpy(username, &bufin[offs], username_len);
|
||||
username[username_len+1] = 0;
|
||||
offs+=username_len;
|
||||
int message_len = bufin[offs++];
|
||||
memcpy(message, &bufin[offs++], message_len);
|
||||
message[message_len+1] = 0;
|
||||
printf("info: received message from %s: \"%s\"\n", username, message);
|
||||
processText(sock, username, message);
|
||||
} else if (bufin[p+2] == CMD_WHISPER && bufin[p+1] == 0x01) {
|
||||
char *username = new char[32];
|
||||
char *message;
|
||||
int offs = p+3;
|
||||
offs++; // Ignore empty byte
|
||||
int username_len = bufin[offs++];
|
||||
memcpy(username, &bufin[offs], username_len);
|
||||
username[username_len] = 0;
|
||||
offs+=username_len;
|
||||
message = new char[250-username_len];
|
||||
int message_len = bufin[offs++];
|
||||
memcpy(message, &bufin[offs++], message_len);
|
||||
message[message_len] = 0;
|
||||
printf("info: received whisper from %s: \"%s\"\n", username, message);
|
||||
processWhisper(sock, username, message);
|
||||
} else if (bufin[p+2] == CMD_REGOBJID && bufin[p+1] == 0xff) {
|
||||
char *longID = new char[32];
|
||||
int shortID;
|
||||
int offs = p+3;
|
||||
int long_len = bufin[offs++];
|
||||
memcpy(longID, &bufin[offs], long_len);
|
||||
longID[long_len] = 0;
|
||||
offs+=long_len;
|
||||
shortID = bufin[offs++];
|
||||
if (longID != NULL || strlen(longID) > 0) {
|
||||
Drone newDrone = *(new Drone(longID));
|
||||
objects[shortID] = newDrone;
|
||||
}
|
||||
} else if (bufin[p+2] == CMD_SESSEXIT && bufin[p+1] == 0x01) {
|
||||
autoOnline = roomOnline = false;
|
||||
deinit(0);
|
||||
} else if (bufin[p+2] == CMD_SESSINIT && bufin[p+1] == 0x01) {
|
||||
std::map<char, char*> props = readOldPropertyList(&bufin[p]);
|
||||
int errNo = VAR_OK;
|
||||
for (auto const& p : props)
|
||||
switch (p.first) {
|
||||
case PROP_ERROR:
|
||||
errNo = atoi(p.second);
|
||||
break;
|
||||
}
|
||||
if (errNo != VAR_OK) {
|
||||
char* errMsg = "UNKNOWN";
|
||||
switch(errNo) {
|
||||
case VAR_BAD_PASSWORD:
|
||||
errMsg = "Invalid Password."; break;
|
||||
case VAR_BAD_ACCOUNT:
|
||||
errMsg = "Account is no longer valid."; break;
|
||||
case VAR_BAD_IPADDRESS:
|
||||
errMsg = "Invalid client IP address!"; break;
|
||||
case VAR_NO_SUCH_USER:
|
||||
errMsg = "User does not exist."; break;
|
||||
}
|
||||
printf("error: code %i received: %s\n", errNo, errMsg);
|
||||
|
||||
if (port == autoport) {
|
||||
autoOnline = false;
|
||||
} else {
|
||||
roomOnline = false;
|
||||
}
|
||||
} else {
|
||||
if (port != autoport) {
|
||||
setAvatar(sock, avatar);
|
||||
} else {
|
||||
roomIDReq(sock, room);
|
||||
}
|
||||
}
|
||||
} else if ((bufin[p+2] == CMD_ROOMID || bufin[p+2] == 0x1A) && bufin[p+1] == 0x01) {
|
||||
char *longID = new char[255];
|
||||
int shortID;
|
||||
int offs = p+3;
|
||||
int long_len = bufin[offs++];
|
||||
memcpy(longID, &bufin[offs], long_len);
|
||||
longID[long_len+1] = 0;
|
||||
offs+=long_len;
|
||||
shortID = ((uint16_t)bufin[offs++] << 8) | bufin[offs++];
|
||||
roomID = shortID;
|
||||
memcpy(&roomserver, new uint8_t[4]{ bufin[offs++], bufin[offs++], bufin[offs++], bufin[offs++] }, 4);
|
||||
roomport = (bufin[offs++] << 8) | bufin[offs++];
|
||||
if (port != autoport) sessExit(sock);
|
||||
printf("info: Joining room %s\n", longID);
|
||||
objects.erase(objects.begin(), objects.end());
|
||||
roomInit();
|
||||
teleport(sock, xPos, yPos, zPos, direction);
|
||||
} else if (bufin[p+2] == CMD_ACTOR_DISAPPR && bufin[p+1] == 0xfe) {
|
||||
for (int t = 3; t < buflen; t++) {
|
||||
userExit(bufin[p+t]);
|
||||
}
|
||||
} else if (bufin[p+2] == CMD_ACTOR_APPR && bufin[p+1] == 0xfe) {
|
||||
for (int t = 3; t < buflen; t+=11) {
|
||||
userEnter(bufin[p+t]);
|
||||
}
|
||||
} else if (bufin[p+2] == CMD_TELEPORT && bufin[p+1] == 0xfe) {
|
||||
int offs = p+3;
|
||||
int objID = bufin[offs++];
|
||||
int exitType = bufin[offs++];
|
||||
int entryType = bufin[offs++];
|
||||
int roomid = ((uint16_t)bufin[offs++] << 8) | bufin[offs++];
|
||||
if (exitType != 0) {
|
||||
// De-register ObjID and say user left.
|
||||
userExit(objID);
|
||||
} else {
|
||||
if (entryType == 0) {
|
||||
userExit(objID);
|
||||
} else {
|
||||
userEnter(objID);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//printf("*LEN[%i] OID[%i] TYPE[%02X] OFF[%i]\n", bufin[p], bufin[p+1], bufin[p+2], p);
|
||||
}
|
||||
if (buflen < sizeof(bufin) && bufin[bufin[p]] != 0x00) {
|
||||
p += bufin[p];
|
||||
goto more_in_buffer;
|
||||
}
|
||||
memset(&(bufin[0]), 0, sizeof(bufin));
|
||||
}
|
||||
}
|
||||
|
||||
void sessInit(int *sock, std::string username, std::string password) {
|
||||
bufout[1] = 0x01;
|
||||
bufout[2] = CMD_SESSINIT;
|
||||
int l = 3;
|
||||
|
||||
// Username
|
||||
bufout[l++] = 2;
|
||||
bufout[l++] = username.length();
|
||||
for (int c = 0; c < username.length(); c++)
|
||||
bufout[l++] = username[c];
|
||||
|
||||
// Password
|
||||
bufout[l++] = 6;
|
||||
bufout[l++] = password.length();
|
||||
for (int c = 0; c < password.length(); c++)
|
||||
bufout[l++] = password[c];
|
||||
|
||||
// Protocol
|
||||
char* pstr = new char[4];
|
||||
sprintf(pstr, "%d", protocol);
|
||||
bufout[l++] = 3;
|
||||
bufout[l++] = strlen(pstr);
|
||||
for (int c = 0; c < strlen(pstr); c++)
|
||||
bufout[l++] = pstr[c];
|
||||
|
||||
// Avatars
|
||||
char* avstr = new char[4];
|
||||
sprintf(avstr, "%d", avatars);
|
||||
bufout[l++] = 7;
|
||||
bufout[l++] = strlen(avstr);
|
||||
for (int c = 0; c < strlen(avstr); c++)
|
||||
bufout[l++] = avstr[c];
|
||||
|
||||
// Version
|
||||
bufout[l++] = 9;
|
||||
bufout[l++] = strlen(version);
|
||||
for (int c = 0; c < strlen(version); c++)
|
||||
bufout[l++] = version[c];
|
||||
|
||||
// Version
|
||||
bufout[l++] = 12;
|
||||
bufout[l++] = 1;
|
||||
bufout[l++] = '1';
|
||||
|
||||
bufout[0] = l;
|
||||
bufout[l+1] = 0;
|
||||
wsend(sock, bufout, 0);
|
||||
}
|
||||
|
||||
void sessExit(int *sock) {
|
||||
bufout[0] = 0x03;
|
||||
bufout[1] = 0x01;
|
||||
bufout[2] = CMD_SESSEXIT;
|
||||
wsend(sock, bufout, 0);
|
||||
}
|
||||
|
||||
void constructPropertyList(int type, std::map<int, char*> props, unsigned char* snd) {
|
||||
snd[1] = 0x01;
|
||||
snd[2] = type;
|
||||
int l = 3;
|
||||
for (auto const& p : props) {
|
||||
snd[l++] = p.first;
|
||||
snd[l++] = strlen(p.second);
|
||||
for (int c = 0; c < strlen(p.second); c++)
|
||||
snd[l++] = p.second[c];
|
||||
}
|
||||
snd[0] = l;
|
||||
snd[l+1] = 0;
|
||||
}
|
||||
|
||||
void readPropertyList(unsigned char* in) {
|
||||
int l {3};
|
||||
while (l < in[0]) {
|
||||
char property[128] = {0};
|
||||
int type = in[l++];
|
||||
l++; l++;
|
||||
int len = in[l++];
|
||||
memcpy(property, &in[l], len);
|
||||
property[len]='\0';
|
||||
properties[type] = (char*)property;
|
||||
l+=len;
|
||||
}
|
||||
}
|
||||
|
||||
std::map<char, char*> readOldPropertyList(unsigned char* in) {
|
||||
std::map<char, char*> oldprops = {};
|
||||
int l {3};
|
||||
while (l < in[0]) {
|
||||
char* value = new char[255];
|
||||
char type = in[l++];
|
||||
int len = in[l++];
|
||||
memcpy(value, &in[l], len);
|
||||
l+=len;
|
||||
value[len]=0;
|
||||
oldprops[type] = value;
|
||||
}
|
||||
return oldprops;
|
||||
}
|
||||
|
||||
void setAvatar(int *sock, std::string avstr) {
|
||||
unsigned char bufav[255] = {0};
|
||||
int l = 1;
|
||||
bufav[l++] = 0x01;
|
||||
bufav[l++] = CMD_PROPSET;
|
||||
bufav[l++] = 0x00;
|
||||
bufav[l++] = 0x05;
|
||||
bufav[l++] = 0x40;
|
||||
bufav[l++] = 0x01;
|
||||
|
||||
bufav[l++] = avstr.length();
|
||||
for (int c = 0; c < avstr.length(); c++)
|
||||
bufav[l++] = avstr[c];
|
||||
|
||||
bufav[0] = l;
|
||||
bufav[l+1] = 0;
|
||||
wsend(sock, bufav, 0);
|
||||
}
|
||||
|
||||
void roomIDReq(int *sock, std::string room) {
|
||||
unsigned char bufrm[255] = {0};
|
||||
bufrm[1] = 1;
|
||||
bufrm[2] = CMD_ROOMIDREQ;
|
||||
bufrm[3] = room.length();
|
||||
int x = 4;
|
||||
for (int z = 0; z < room.length(); z++)
|
||||
bufrm[x++] = room[z];
|
||||
bufrm[x++] = 0;
|
||||
bufrm[0] = x;
|
||||
wsend(sock, bufrm, 0);
|
||||
}
|
||||
|
||||
void teleport(int *sock, int x, int y, int z, int rot) {
|
||||
unsigned char buftp[16] = {0};
|
||||
uint8_t _roomID[2];
|
||||
uint8_t _x[2];
|
||||
uint8_t _y[2];
|
||||
uint8_t _z[2];
|
||||
uint8_t _rot[2];
|
||||
memcpy(_roomID, &roomID, sizeof(_roomID));
|
||||
memcpy(_x, &x, sizeof(_x));
|
||||
memcpy(_y, &y, sizeof(_y));
|
||||
memcpy(_z, &z, sizeof(_z));
|
||||
memcpy(_rot, &rot, sizeof(_rot));
|
||||
|
||||
buftp[0] = 0x0f;
|
||||
buftp[1] = 0x01;
|
||||
buftp[2] = CMD_TELEPORT;
|
||||
buftp[4] = _roomID[0]; buftp[3] = _roomID[1];
|
||||
buftp[5] = 0x00; buftp[6] = 0x01;
|
||||
buftp[8] = _x[0]; buftp[7] = _x[1];
|
||||
buftp[10] = _y[0]; buftp[9] = _y[1];
|
||||
buftp[12] = _z[0]; buftp[11] = _z[1];
|
||||
buftp[14] = _rot[0]; buftp[13] = _rot[1];
|
||||
|
||||
wsend(sock, buftp, 0);
|
||||
}
|
||||
|
||||
void userEnter(char id) {
|
||||
if (!((Drone)objects[id]).droneActive) {
|
||||
objects[id].droneActive = true;
|
||||
}
|
||||
}
|
||||
|
||||
void userExit(char id) {
|
||||
if (((Drone)objects[id]).droneActive) {
|
||||
objects.erase((char)id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool strcontains(std::string needle, std::string haystack) {
|
||||
bool found = haystack.find(needle) != std::string::npos;
|
||||
if (debug) printf("debug: %s =?= %s == %i\n", needle.c_str(), haystack.c_str(), found?1:0);
|
||||
return found;
|
||||
}
|
||||
|
||||
bool vstrcontains(std::string needle, std::vector<std::string> haystack) {
|
||||
for (std::string str : haystack) {
|
||||
if (needle.rfind(str, 0) == 0) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getContainedWorld(std::map<std::string, std::string> worldlist, std::string input) {
|
||||
for (auto world : worldlist) {
|
||||
if (strcontains(world.first, input)) return world.second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
char* handleCommand(std::string from, std::string message) {
|
||||
char *msgout = new char[255];
|
||||
if (strcontains("flip a coin", message)) {
|
||||
|
||||
bool heads = rand() % 10 > 5;
|
||||
snprintf(msgout, 255, "%s", heads?"Heads":"Tails");
|
||||
|
||||
} else if (strcontains("time", message)) {
|
||||
|
||||
time_t currentTime;
|
||||
struct tm *localTime;
|
||||
time( ¤tTime );
|
||||
localTime = localtime( ¤tTime );
|
||||
snprintf(msgout, 255, "The time is %02i:%02i.", localTime->tm_hour, localTime->tm_min, localTime->tm_sec);
|
||||
|
||||
} else if (strcontains("dice", message) || strcontains("roll", message)) {
|
||||
|
||||
int dice = 6;
|
||||
|
||||
if (strcontains("d10", message)) dice = 10;
|
||||
else if (strcontains("d12", message)) dice = 12;
|
||||
else if (strcontains("d20", message)) dice = 20;
|
||||
else if (strcontains("d100", message)) dice = 100;
|
||||
|
||||
int roll = (rand() % (dice-1)) + 1;
|
||||
snprintf(msgout, 255, "%s rolled a %i.", from.c_str(), dice);
|
||||
|
||||
} else if (strcontains("where is", message) || strcontains("where", message) || strcontains("mark to", message) || strcontains("show me", message)) {
|
||||
|
||||
std::string mark = getContainedWorld(conf.getWorlds(), message);
|
||||
if (mark.length() > 0) {
|
||||
snprintf(msgout, 255, conf.getMessage("whereis").c_str(), mark.c_str());
|
||||
} else {
|
||||
snprintf(msgout, 255, "Sorry! Not a clue.");
|
||||
}
|
||||
|
||||
} else if (strcontains("many users", message) || strcontains("whos online", message) || strcontains("who is online", message) || strcontains("many online", message)) {
|
||||
|
||||
snprintf(msgout, 255, "There are %i users in this room.", objects.size());
|
||||
|
||||
} else if ((strcontains("what", message) || strcontains("who", message)) && strcontains("are you", message)) {
|
||||
|
||||
snprintf(msgout, 255, "%s", conf.getMessage("whoami").c_str());
|
||||
|
||||
} else if (strcontains("shutdown", message) && from == conf.getValue("owner", "")) {
|
||||
|
||||
exit(deinit(0));
|
||||
|
||||
}
|
||||
return msgout;
|
||||
}
|
||||
|
||||
void processText(int *sock, std::string username, std::string message) {
|
||||
char *msgout = new char[255];
|
||||
message = toLower(message); // Make it a lowercase string so we can work with it.
|
||||
// Someone has requested P3NG0s attention.
|
||||
// We'll accept some variations.
|
||||
if (username != login_username) {
|
||||
if (vstrcontains(message, conf.getMessages("attention"))) {
|
||||
msgout = handleCommand(username, message);
|
||||
if (strlen(msgout) > 0) sendChatMessage(sock, msgout);
|
||||
else if (strcontains("your commands", message) || strcontains("can you do", message)) {
|
||||
|
||||
char *whisout = new char[255];
|
||||
snprintf(whisout, 255, "Check this out: %s", conf.getValue("help_url", "").c_str());
|
||||
sendWhisperMessage(&roomsock, username, whisout);
|
||||
snprintf(msgout, 255, "You have been whispered with a link that will help you.");
|
||||
sendChatMessage(sock, msgout);
|
||||
|
||||
}
|
||||
} else if (message == "ping") { // We'll accept a simple ping to pong.
|
||||
sendChatMessage(sock, "Pong!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processWhisper(int *sock, std::string username, std::string message) {
|
||||
char *msgout = new char[255];
|
||||
message = toLower(message);
|
||||
|
||||
if (message == "ping") {
|
||||
sendWhisperMessage(sock, username, "Pong");
|
||||
} else {
|
||||
msgout = handleCommand(username, message);
|
||||
if (strlen(msgout) > 0) sendWhisperMessage(sock, username, msgout);
|
||||
}
|
||||
}
|
||||
|
||||
void sendChatMessage(int *sock, std::string msg) {
|
||||
unsigned char bufout[BUFFERSIZE] = {0};
|
||||
int msglen = msg.length();
|
||||
int k = 1;
|
||||
bufout[k++] = 1;
|
||||
bufout[k++] = CMD_CHATMSG;
|
||||
bufout[k++] = 0; bufout[k++] = 0;
|
||||
bufout[k++] = msglen;
|
||||
for(int l = 0; l < msglen; l++)
|
||||
bufout[k++] = msg[l];
|
||||
bufout[k] = 0;
|
||||
bufout[0] = k;
|
||||
wsend(&roomsock, bufout, 0);
|
||||
}
|
||||
|
||||
void sendWhisperMessage(int *sock, std::string to, std::string msg) {
|
||||
whisper_repeat:
|
||||
unsigned char bufout[BUFFERSIZE] = {0};
|
||||
int k = 1;
|
||||
bufout[k++] = 0;
|
||||
bufout[k++] = to.length();
|
||||
for(int l = 0; l < to.length(); l++)
|
||||
bufout[k++] = to[l];
|
||||
bufout[k++] = CMD_WHISPER;
|
||||
bufout[k++] = 0; bufout[k++] = 0;
|
||||
int msglen = std::min((int)msg.length(), 226);
|
||||
bufout[k++] = msglen;
|
||||
for(int l = 0; l < msglen; l++)
|
||||
bufout[k++] = msg[l];
|
||||
bufout[k] = 0;
|
||||
bufout[0] = k;
|
||||
wsend(&roomsock, bufout, 0);
|
||||
// Check if the length is higher.
|
||||
if (msg.length() > 226) {
|
||||
msg = msg.substr(226, -1);
|
||||
goto whisper_repeat;
|
||||
}
|
||||
}
|
||||
|
||||
int wsend(int *sock, unsigned char str[], int flags) {
|
||||
if (debug) printf("debug: sending new packet of type %i and length %i.\n", str[2], str[0]);
|
||||
return send(*sock, str, str[0], flags);
|
||||
}
|
32
src/props.h
Normal file
32
src/props.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef PROPS_H
|
||||
#define PROPS_H
|
||||
|
||||
#define PROP_APPNAME 1
|
||||
#define PROP_USERNAME 2
|
||||
#define PROP_PROTOCOL 3
|
||||
#define PROP_ERROR 4
|
||||
#define PROP_CHANNEL 5
|
||||
#define PROP_PASSWORD 6
|
||||
#define PROP_AVATARS 7
|
||||
#define PROP_UPDATETIME 8
|
||||
#define PROP_CLIENT 9
|
||||
#define PROP_SERIAL 10
|
||||
#define PROP_EMAIL 11
|
||||
#define PROP_LOGONOFF 12
|
||||
#define PROP_DURATION 13
|
||||
#define PROP_GUEST 14
|
||||
#define PROP_SERVERTYPE 15
|
||||
#define PROP_BIZCARD 16
|
||||
#define PROP_NEW_PASSWORD 20
|
||||
#define PROP_PRIV 22
|
||||
#define PROP_ASLEEP 23
|
||||
#define PROP_EX_HTTP_SERVER 24
|
||||
#define PROP_SCRIPT_SERVER 25
|
||||
#define PROP_SMTP_SERVER 26
|
||||
#define PROP_MAIL_DOMAIN 27
|
||||
#define PROP_NEW_USERNAME 28
|
||||
#define PROP_IN_HTTP_SERVER 29
|
||||
#define PROP_INVENTORY 30
|
||||
|
||||
#endif
|
||||
|
25
src/strutils.h
Normal file
25
src/strutils.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef STRUTILS_H
|
||||
#define STRUTILS_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <iterator>
|
||||
|
||||
template <typename Out>
|
||||
void split(const std::string &s, char delim, Out result) {
|
||||
std::istringstream iss(s);
|
||||
std::string item;
|
||||
while (std::getline(iss, item, delim)) {
|
||||
*result++ = item;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
split(s, delim, std::back_inserter(elems));
|
||||
return elems;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
29
src/verrors.h.h
Normal file
29
src/verrors.h.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifndef H_VAR_ERROR
|
||||
#define H_VAR_ERROR
|
||||
|
||||
#define VAR_OK 0
|
||||
#define VAR_BAD_USER 1
|
||||
#define VAR_MAX_ORDINARY 2
|
||||
#define VAR_MAX_PRIORITY 3
|
||||
#define VAR_FATAL 5
|
||||
#define VAR_BAD_PROTOCOL 6
|
||||
#define VAR_BAD_CLIENTSW 7
|
||||
#define VAR_BAD_SERIAL 9
|
||||
#define VAR_TAKEN_SERIAL 10
|
||||
#define VAR_TAKEN_USER 11
|
||||
#define VAR_NO_SUCH_USER 12
|
||||
#define VAR_BAD_PASSWORD 13
|
||||
#define VAR_BAD_ACCOUNT 14
|
||||
#define VAR_NOT_LOGGEDON 15
|
||||
#define VAR_BAD_IPADDRESS 16
|
||||
#define VAR_LOGGEDON 17
|
||||
#define VAR_ROOM_FULL 21
|
||||
#define VAR_UNEXPECTED 100 | 101 | 102 | 103
|
||||
#define VAR_UNREACHABLE 104 | 105 | 106 | 107
|
||||
#define VAR_SHUTTING_DOWN 201
|
||||
#define VAR_RECONNECTING 202
|
||||
#define VAR_DISCONNECTED 203
|
||||
#define VAR_LOST_CONNECTION 204
|
||||
#define VAR_SINGLE_USER 205
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user