diff options
author | Hello=) <hello@themanaworld.org> | 2024-03-28 03:58:45 +0300 |
---|---|---|
committer | Hello=) <hello@themanaworld.org> | 2024-03-28 03:58:45 +0300 |
commit | db0b1da0060f5eb4b2af040c22ea9373d36970af (patch) | |
tree | dc2bdc0478c341bf4368fee4993c20e52f2d41c1 | |
download | guildbot-db0b1da0060f5eb4b2af040c22ea9373d36970af.tar.gz guildbot-db0b1da0060f5eb4b2af040c22ea9373d36970af.tar.bz2 guildbot-db0b1da0060f5eb4b2af040c22ea9373d36970af.tar.xz guildbot-db0b1da0060f5eb4b2af040c22ea9373d36970af.zip |
Initial commit of Guild Bot, as seen in:
$ sha256sum guildsrc.zip
ef61469ab59ce3f5dd3289505e89bd5b84e3a82b89cda90d25ae3c41f7464beb guildsrc.zip
Verification shown its source 100% match to currently running version on TMWA.
The following changes were made VS version found in guildsrc.zip:
1) src/build and src/dist content completely removed.
Rationale: build-time artifacts; binaries contained login/password.
2) Executable flag (+x) removed from src/automation.cpp and src/main.cpp.
Rationale: executable CPP sources are weird thing. No change to file content.
3) src/main.cpp changes: 3 lines:
std::string main_username = "test";
std::string main_pw = "test";
std::string main_host = "127.0.0.1";
Rationale: avoid leaking real production credentials and ensure experimenters
dont hammer real TMW prod server by experiments.
Effort been made to preserve original file timestamps, etc. However toplevel src/
dir date adjusted to date of mentioned changes.
58 files changed, 6454 insertions, 0 deletions
diff --git a/src/.dep.inc b/src/.dep.inc new file mode 100644 index 0000000..4560e55 --- /dev/null +++ b/src/.dep.inc @@ -0,0 +1,5 @@ +# This code depends on make tool being used +DEPFILES=$(wildcard $(addsuffix .d, ${OBJECTFILES})) +ifneq (${DEPFILES},) +include ${DEPFILES} +endif diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..e2cae22 --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,2 @@ +/build/ +/dist/ diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..e137db5 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,109 @@ +# +# There exist several targets which are by default empty and which can be +# used for execution of your targets. These targets are usually executed +# before and after some main targets. They are: +# +# .build-pre: called before 'build' target +# .build-post: called after 'build' target +# .clean-pre: called before 'clean' target +# .clean-post: called after 'clean' target +# .clobber-pre: called before 'clobber' target +# .clobber-post: called after 'clobber' target +# .all-pre: called before 'all' target +# .all-post: called after 'all' target +# .help-pre: called before 'help' target +# .help-post: called after 'help' target +# +# Targets beginning with '.' are not intended to be called on their own. +# +# Main targets can be executed directly, and they are: +# +# build build a specific configuration +# clean remove built files from a configuration +# clobber remove all built files +# all build all configurations +# help print help mesage +# +# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and +# .help-impl are implemented in nbproject/makefile-impl.mk. +# +# Available make variables: +# +# CND_BASEDIR base directory for relative paths +# CND_DISTDIR default top distribution directory (build artifacts) +# CND_BUILDDIR default top build directory (object files, ...) +# CONF name of current configuration +# CND_PLATFORM_${CONF} platform name (current configuration) +# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration) +# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration) +# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration) +# CND_PACKAGE_DIR_${CONF} directory of package (current configuration) +# CND_PACKAGE_NAME_${CONF} name of package (current configuration) +# CND_PACKAGE_PATH_${CONF} path to package (current configuration) +# +# NOCDDL + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib + + +# build +build: .build-post + +.build-pre: +# Add your pre 'build' code here... + +.build-post: .build-impl +# Add your post 'build' code here... + + +# clean +clean: .clean-post + +.clean-pre: +# Add your pre 'clean' code here... + +.clean-post: .clean-impl +# Add your post 'clean' code here... + + +# clobber +clobber: .clobber-post + +.clobber-pre: +# Add your pre 'clobber' code here... + +.clobber-post: .clobber-impl +# Add your post 'clobber' code here... + + +# all +all: .all-post + +.all-pre: +# Add your pre 'all' code here... + +.all-post: .all-impl +# Add your post 'all' code here... + + +# help +help: .help-post + +.help-pre: +# Add your pre 'help' code here... + +.help-post: .help-impl +# Add your post 'help' code here... + + + +# include project implementation makefile +include nbproject/Makefile-impl.mk + +# include project make variables +include nbproject/Makefile-variables.mk diff --git a/src/automation.cpp b/src/automation.cpp new file mode 100644 index 0000000..48babd7 --- /dev/null +++ b/src/automation.cpp @@ -0,0 +1,855 @@ +/* + * + * Automation.cpp: The Ruined Place Chat Bot. + * + */ + +#include <iostream> +#include <string> +#include <set> +#include <deque> +#include <sstream> +#include <fstream> +#include <map> +#include <cstdlib> + +#include "automation.h" +#include "game.h" +#include "main.h" +#include "utils/stringutils.h" +#include "utils/specialfolder.h" +#include "net/nethandler.h" + +static Automation *automationHandler = NULL; + +std::set<member> guildMembers; +std::deque<whispermsg> whispers; +std::deque<whispermsg> information; +std::set<std::string> onlineList; +std::set<memberinvite> inviteList; +std::map<std::string, std::string> guildMOTD; + +bool automation = true; +bool repeatfix = false; +bool load = true; +bool hideOnLoad = true; // Hide all online/offline notifications on startup - creates a lot of spam! + +int message_timer = 0; + +Automation::Automation() +{ + automationHandler = this; +} + +Automation::~Automation() +{ + delete automationHandler; +} + +Automation *Automation::getAutomationHandler() +{ + return automationHandler; +} + +/* Commands/chat recieved through whisper. */ +void Automation::commandHandler(std::string message, std::string nick) +{ + + std::string::size_type pos = message.find(' '); + std::string type(message, 0, pos); + std::string args(message, pos == std::string::npos ? message.size() : pos + 1); + + /*start of code that deals with invitations - could do with a rewrite*/ + std::set<memberinvite>::iterator it3; + bool invited = false; + memberinvite invitedMember; + + for (it3=inviteList.begin(); it3 != inviteList.end(); it3++) + { + if (it3->name == nick) + { + invited = true; + invitedMember = *it3; + } + } + + if (invited) + { + if (removeColors(type) == "yes") + { + inviteList.erase(invitedMember); + addMember(nick, invitedMember.guildName, 0); + addMessage(nick+ " has joined the Guild.", + invitedMember.guildName, "Info", 1); + return; + } + else if (removeColors(type) == "no") + { + inviteList.erase(invitedMember); + return; + } + } + + /* end */ + + if (!automation || !inGuild(nick)) + { + whisper(nick, colorText("You are currently not in a guild." + " For more information or to discuss the possibility" + " of adding you own guild please contact Jero."), 1); + return; + } + + if (type[0] == '!') + { + debugMsg("("+findByName(nick).guildName+") Command: "+ + nick+": "+type +" "+args); + //note incorrect commands will be logged twice. + } + + if (accessLevel(args) != -1) + { + member tmp = findByName(nick); + if (tmp.status == 0) + { + guildMembers.erase(tmp); + tmp.status = 1; + addMessage(tmp.name+ " is now Online.", tmp.guildName, "Info", 1); + guildMembers.insert(tmp); + whisper(tmp.name, colorText("Welcome to the "+tmp.guildName+"! ("+ + toString(countOnline(tmp.guildName)) +" Members are Online)"), 1); + } + } + + if (type == "!invite" && accessLevel(nick) >= 5) /* This command is only available to admin*/ + { + if (!args.empty() && accessLevel(args) != -1) + { + if (inGuild(args)) + { + whisper(nick, colorText("The user is in another guild."), 1); + } + else + { + if (onlineList.find(args) != onlineList.end()) + { + memberinvite tmp= {args, findByName(nick).guildName}; + inviteList.insert(tmp); + whisper(args, colorText("You have been invited to the "+ + findByName(nick).guildName+ " guild chat. If you " + "would like to accept this invitation" + " please reply \"yes\" and if not then \"no\" ." ), 1); + } + else + { + whisper(nick, colorText("The user is offline or hidden."), 1); + } + + } + } + } + else if (type == "!test" && accessLevel(nick) == 20) /* This command is only available to admin*/ + { + addMessage("A test will be running shortly.", + findByName(nick).guildName, "Info", 0); + testMsg(); + } + else if (type == "!disband" && accessLevel(nick) >= 10) /* This command is only available to guild masters*/ + { + std::string guild = findByName(nick).guildName; + debugMsg(guild + " disbanded."); + addMessage("The "+guild +" guild has been disbanded.","global", "Info", 1); + + std::set<member>::iterator it2; + for (it2=guildMembers.begin(); it2 != guildMembers.end(); it2++) + { + if (it2->guildName == guild) + guildMembers.erase(it2); + } + + saveMembers(); + } + else if (type == "!removeguild" && accessLevel(nick) == 20) /* This command is only available to admin*/ + { + + if (!args.empty()) + { + debugMsg(args + "removed."); + std::set<member>::iterator it2; + for (it2=guildMembers.begin(); it2 != guildMembers.end(); it2++) + { + if (it2->guildName == args) + guildMembers.erase(it2); + } + + addMessage("The "+args +" guild has been removed.","global", "Info", 1); + saveMembers(); + } + + } + else if (type == "!addguild" && accessLevel(nick) == 20) + { + if (!args.empty()) + { + std::string::size_type pos2 = args.find(','); + std::string name = args.substr(0, pos2); + std::string guildName = args.substr(pos2+1, args.size()); + + addMember(name, guildName, 10); + addMessage("The "+guildName+" guild has been created.","global", "Info", 1); + } + } + else if (type == "!info") + { + std::stringstream message; + message << "Player name: "+nick+", Access Level: "<< accessLevel(nick) + << ", Guild:" << findByName(nick).guildName + << ", No. Of Online Players: " << + countOnline(findByName(nick).guildName); + + whisper(nick, colorText(message.str()), 1); + + std::string MOTD = getMOTD(findByName(nick).guildName); + if (MOTD != "") + whisper(nick, colorText("Guild MOTD: "+MOTD), 1); + + } + else if (type == "!ping") /* A simple response to check if the bot is active. */ + { + whisper(nick, colorText("Pong."), 0); + } + else if (type == "!remove") + { + if (!args.empty()) + { + if (hasPermission(nick, args, 0) && inGuild(args)) + { + removeMember(args); + whisper(args, "You have been removed from the Guild", 0); + addMessage(args+ " has been removed from the Guild.", + findByName(nick).guildName, "Info", 1); + saveMembers(); + } + } + } + else if (type == "!setmotd" && accessLevel(nick) >= 5) + { + std::map<std::string, std::string>::iterator it; + it=guildMOTD.find(findByName(nick).guildName); + + if (it != guildMOTD.end()) + { + guildMOTD.erase(it); + guildMOTD.insert(std::pair<std::string, std::string>(findByName(nick).guildName, args)); + } + else + { + guildMOTD.insert(std::pair<std::string, std::string>(findByName(nick).guildName, args)); + } + + whisper(nick, colorText("MOTD Set:" + args), 1); + } + else if (type == "!removemotd" && accessLevel(nick) >= 5) + { + std::map<std::string, std::string>::iterator it; + it=guildMOTD.find(findByName(nick).guildName); + + if (it != guildMOTD.end()) + { + guildMOTD.erase(it); + whisper(nick, colorText("The MOTD has been Removed."), 1); + } + else + { + whisper(nick, colorText("No MOTD set."), 1); + } + + } + else if (type == "!setaccess") /* This command is only available to admin*/ + { + if (!args.empty()) + { + std::string::size_type pos = args.find(' '); + std::string level(args, 0, pos); + std::string name(args, pos == std::string::npos ? args.size() : pos + 1); + int access = toInt(level); + + if (hasPermission(nick, name, access) && inGuild(name) + && !name.empty() && !level.empty()) + { + member update = findByName(name); + guildMembers.erase(update); + update.accesslevel = access; + guildMembers.insert(update); + whisper(nick, colorText("Player name:" + name + + ", Access Level: "+level), 1); + } + saveMembers(); + } + } + else if (type == "!leave") + { + std::string guild = findByName(nick).guildName; + whisper(nick, "You have left the Guild", 0); + removeMember(nick); + addMessage(nick+ " has left the Guild.", guild, "Info", 1); + saveMembers(); + } + else if (type == "!help") + { + whisper(nick, colorText("Guild ChatBot. The " + "commands are: !invite <name>, !leave, !listonline, !listmembers, !info. " + "If you would like to hide information messages use !hideinfo, " + "and to make them visible again use !showinfo."), 1); + + if (accessLevel(nick) >= 5) + { + whisper(nick, colorText( + "You are also able to add a guild MOTD using !setmotd, this can be removed using !removemotd."), 1); + } + + if (accessLevel(nick) >= 10) + { + whisper(nick, colorText( + "You also have access to the guild master commands these are" + " !remove <name>, !disband, !setaccess <access level> <name>" + "(the access level must be less than or equal to your own)."), 1); + } + else if (accessLevel(nick) <= 10 && accessLevel(nick) > 0) + { + whisper(nick, colorText( + "You also have access to the guild moderator commands these are" + " !remove <name>, !setaccess <access level> <name>" + "(the access level must be less than or equal to your own)."), 1); + } + + if (accessLevel(nick) == 20) + { + whisper(nick, colorText( + "You also have access to the admin commands these are !test," + " !addguild <name>,<guild name> (the comma is important)" + " and !removeguild <name>."), 1); + whisper(nick, colorText( + " To send a message to all guilds use !global <message>, " + "!listallonline, !joinguild <guild name> (lets you join another guilds chat)"), 1); + } + } + else if (type == "!hideinfo") + { + whisper(nick, colorText("Information messages hidden."), 1); + member tmp = findByName(nick); + guildMembers.erase(tmp); + tmp.info = 0; + guildMembers.insert(tmp); + } + else if (type == "!online") + { + whisper(nick, colorText("You are online."), 1); + member tmp = findByName(nick); + guildMembers.erase(tmp); + tmp.status = 1; + guildMembers.insert(tmp); + } + else if (type == "!offline") + { + whisper(nick, colorText("You have gone offline."), 1); + member tmp = findByName(nick); + guildMembers.erase(tmp); + tmp.status = 0; + guildMembers.insert(tmp); + } + else if (type == "!joinguild" && accessLevel(nick) == 20) + { + whisper(nick, colorText("You've joined "+args+"."), 1); + member tmp = findByName(nick); + guildMembers.erase(tmp); + tmp.guildName = args; + guildMembers.insert(tmp); + } + else if (type == "!showinfo") + { + whisper(nick, colorText("Information messages vissible."), 1); + member tmp = findByName(nick); + guildMembers.erase(tmp); + tmp.info = 1; + guildMembers.insert(tmp); + } + else if (type == "!global" && accessLevel(nick) == 20) /* This command is only available to admin*/ + { + if (!args.empty()) + { + addMessage(args, "global", "Info", 0); + } + } + else if (type == "!listonline") + { + std::set<member>::iterator it; + std::string message; + std::stringstream list; + list << "List of online Guild Members: "; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + { + + if (list.str().length() + it->name.length() > 250 && it->status == 1 + && it->guildName == findByName(nick).guildName) + { + message = list.str(); + message[message.length()-2] = '.'; + whisper(nick,colorText(message), 1); + list.str(""); + list << it->name + ", "; + } + else if (it->status == 1 && it->guildName == findByName(nick).guildName) + { + list << it->name + ", "; + } + + } + message = list.str(); + message[message.length()-2] = '.'; + whisper(nick,colorText(message), 1); + } + else if (type == "!getonlineinfo") + { + std::set<member>::iterator it; + std::string message; + std::stringstream list; + list << "OL"; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + { + int status = it->status; + if (it->accesslevel >= 10) + status += 2; + + if (list.str().length() + it->name.length()+2 > 400 + && it->guildName == findByName(nick).guildName) + { + list << "#"; + message = list.str(); + whisper(nick,colorText(message), 1); + list.str(""); + list << "oL#"; + list << it->name; + list << status; + } + else if (it->guildName == findByName(nick).guildName) + { + list << "#"; + list << it->name; + list << status; + } + + } + message = list.str(); + whisper(nick,colorText(message), 1); + } + else if (type == "!listallonline" && accessLevel(nick) == 20) + { + std::set<member>::iterator it; + std::string message; + std::stringstream list; + list << "List of online Players: "; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + { + + if (list.str().length() + it->name.length() > 250 && it->status == 1) + { + message = list.str(); + message[message.length()-2] = '.'; + whisper(nick,colorText(message), 1); + list.str(""); + list << it->name + ", "; + } + else if (it->status == 1) + { + list << it->name + ", "; + } + + } + message = list.str(); + message[message.length()-2] = '.'; + whisper(nick,colorText(message), 1); + } + else if (type == "!listmembers") + { + std::set<member>::iterator it; + std::string message; + std::stringstream list; + list << "List of Guild Members: "; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + { + + if (list.str().length() + it->name.length() > 250 + && it->guildName == findByName(nick).guildName) + { + message = list.str(); + message[message.length()-2] = '.'; + whisper(nick,colorText(message), 1); + list.str(""); + list << it->name + ", "; + } + else if (it->guildName == findByName(nick).guildName) + { + list << it->name + ", "; + } + + } + message = list.str(); + message[message.length()-2] = '.'; + whisper(nick,colorText(message), 1); + } + else + { + std::size_t found; + found=message.find("*AFK*"); + + if (found == std::string::npos) + addMessage(removeColors(message), findByName(nick).guildName, nick, 0); + } +} + +/* hooks directly into the main game logic. */ +void Automation::logic() +{ + if (message_timer == 0) + message_timer = cur_time; + + if (get_elapsed_time(message_timer) > 10 && hideOnLoad) + { + hideOnLoad = false; + debugMsg("Online/Offline messages unhidden."); + } + + if (!whispers.empty())// with SDL_Delay(10) this should send around 100 messages per second. + { + NetHandler::getNetInstance()->privateMessage(whispers.front().name, + whispers.front().message); + whispers.pop_front(); + } + else if (!information.empty()) + { + NetHandler::getNetInstance()->privateMessage(information.front().name, + information.front().message); + information.pop_front(); + } +} + +void Automation::addMember(std::string name, std::string guildName, int access) +{ + member addme = {name, guildName, 0, access, 1}; + guildMembers.insert(addme); + + if (!load) + { + debugMsg("Member Added: "+ name+", Access Level: "+ + toString(access) + " Guild Name: " + guildName); + saveMembers(); + } +} + +void Automation::removeMember(std::string name) +{ + debugMsg("Member Removed: "+ name); + guildMembers.erase(findByName(name)); + saveMembers(); +} + +/*Checks to see whether a player is on the guildbot.*/ +bool Automation::inGuild(std::string name) +{ + std::set<member>::iterator it; + + for (it=guildMembers.begin() ; it != guildMembers.end(); it++) + if (it->name == name) + return true; + + return false; +} + +/* Updates member online status, this uses 4144's online list.*/ +void Automation::updateOnline(std::set<std::string> &onlinePlayers) +{ + debugMsg("Update Online List."); + onlineList = onlinePlayers; + std::set<member>::iterator it; + std::set<member>::iterator it2; + std::set<member> updateStatus; //used for applying changes + + //figure out status changes + for (it=guildMembers.begin(); it != guildMembers.end(); it++ ) + { + if (it->accesslevel < 0) + continue; + + member old = *it; + + if (onlinePlayers.find(it->name) != onlinePlayers.end() && it->status == 0) + { + old.status = 1; + updateStatus.insert(old); + } + else if (onlinePlayers.find(it->name) == onlinePlayers.end() && it->status == 1) + { + old.status = 0; + updateStatus.insert(old); + } + } + + //apply status changes + for (it2=updateStatus.begin(); it2 != updateStatus.end(); it2++) + { + member tmp = *it2; + if (it2->status == 1) + { + guildMembers.erase(findByName(it2->name)); + + /*if (hideOnLoad != true)*/ + addMessage(tmp.name+ " is now Online.", tmp.guildName, "Info", 1); + + guildMembers.insert(tmp); + whisper(tmp.name, colorText("Welcome to the "+tmp.guildName+"! ("+ + toString(countOnline(tmp.guildName)) +" Members are Online)"), 1); + + std::string MOTD = getMOTD(tmp.guildName); + if (MOTD != "") + whisper(tmp.name, colorText(MOTD), 1); + + } + else if (it2->status == 0) + { + guildMembers.erase(findByName(it2->name)); + guildMembers.insert(tmp); + addMessage(tmp.name+ " is now Offline.", tmp.guildName, "Info", 1); + } + + } +} + +/* Sends messages to all those in the specified guild. */ +void Automation::addMessage(std::string msg, std::string guildName, + std::string sender, int p) +{ + std::set<member>::iterator it; + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + { + if (sender == "Info" && it->info == 0) + continue; + + if (it->name != sender && it->status == 1 && (it->guildName == guildName + || guildName == "global")) + { + if (sender == "Info") + whisper(it->name,"##0"+msg, p); + else + whisper(it->name, colorText(sender) +": "+"##0"+msg, p); + } + } +} + +void Automation::debugMsg(std::string msg) +{ + std::string message = removeColors("GuildBot: "+msg); + //logger->log(message.c_str()); +} + +/* Adds the whispers to the required queue*/ +void Automation::whisper(std::string name, std::string msg, int priority) +{ + whispermsg newmsg = {name, msg}; + + if (priority == 0) + whispers.push_back(newmsg); + else + information.push_back(newmsg); +} + +void Automation::showOptions() +{ + debugMsg("List of Guild Members:"); + std::set<member>::iterator it; + + for ( it=guildMembers.begin() ; it != guildMembers.end(); it++ ) + { + std::stringstream status; + status << " Status: " << it->status; + status << " Access Level: " << it->accesslevel; + status << " Guild: " << it->guildName; + debugMsg("Character name: "+ it->name + status.str()); + } +} + +/* Saves the member file */ +void Automation::saveMembers() +{ + mLocalDataDir += "."; +#if defined WIN32 + mLocalDataDir = getSpecialFolderLocation(CSIDL_LOCAL_APPDATA); + mLocalDataDir += "/ManaGuild"; + std::string namelist = mLocalDataDir + "/guildmembers.txt"; +#else + std::string namelist = "guildmembers.txt"; +#endif + std::ofstream guildMemberFile(namelist.c_str()); + + if (guildMemberFile.is_open()) + { + debugMsg("Save Guild Member File."); + std::set<member>::iterator it; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + guildMemberFile << it->name.c_str() << "," + << it->accesslevel << "," + << it->guildName << std::endl; + + guildMemberFile.close(); + } + else + { + debugMsg("Guild Member File save failed."); + } +} + +/* Loads the member file */ +void Automation::loadMembers() +{ + mLocalDataDir += "."; +#if defined WIN32 + mLocalDataDir = getSpecialFolderLocation(CSIDL_LOCAL_APPDATA); + mLocalDataDir += "/ManaGuild"; + std::string namelist = mLocalDataDir + "/guildmembers.txt"; +#else + std::string namelist = "guildmembers.txt"; +#endif + std::string line; + std::ifstream guildMemberFile(namelist.c_str()); + + if (guildMemberFile.is_open()) + { + debugMsg("Load Guild Member File."); + while (!guildMemberFile.eof() ) + { + getline (guildMemberFile,line); + if (!line.empty()) + { + /* Messy pretend tokenizer*/ + std::string::size_type pos = line.find(','); + std::string::size_type pos2 = line.find(',', pos+1); + std::string guildName = line.substr(pos2+1, line.size()); + std::string name = line.substr(0, pos); + int access = toInt(line.substr(pos+1, pos2)); + addMember(name, guildName, access); + } + } + + guildMemberFile.close(); + } + else + { + debugMsg("Guild Member File open failed. If this is your " + "first time runing the chat bot please ignore this message."); + } + + load = false; +} + +/* Color parts of the text to avoid bans from chat spam, also looks pretty. */ +std::string Automation::colorText(std::string text) +{ + if (repeatfix) + text = "##3"+text; + else + text = "##2"+text; + + repeatfix = !repeatfix; + + return text; +} + +/* Returns the number of members online in a specified guild. */ +int Automation::countOnline(std::string guildName) +{ + int count = 0; + std::set<member>::iterator it; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + if (it->status == 1 && (it->guildName == guildName || guildName == "global")) + count++; + + return count; +} + +void Automation::clearMembers() +{ + debugMsg("Clear Members."); + guildMembers.clear(); +} + +int Automation::accessLevel(std::string name) +{ + int accesslevel = findByName(name).accesslevel; + + return accesslevel; +} + +/* Checks to see whether the user has the required permissions, + * for either changing the someones accesslevel or removing another player. */ +bool Automation::hasPermission(std::string user, + std::string player, int changeLevel) +{ + // level 5 players should not be able to remove others. + if (accessLevel(user) != 50 && accessLevel(player) < accessLevel(user) + && changeLevel <= accessLevel(user) && accessLevel(user) > 5 && + findByName(user).guildName == findByName(player).guildName) + { + return true; + } + else + { + whisper(user, colorText("You do not have the correct " + "access level, for this operation."), 1); + return false; + } + + return false; +} + +/* Finds and a member by name. */ +member Automation::findByName(std::string name) +{ + member findme; + std::set<member>::iterator it; + + for (it=guildMembers.begin(); it != guildMembers.end(); it++) + if (it->name == name) + findme = *it; + + return findme; +} + +/* Outputs a test message for testing purposes.*/ +void Automation::testMsg() +{ + for (int i=0;i < 20; i++){ + std::string message = "testing " + toString(i); + addMessage(message,"global", "Info", 0); + } +} + +std::string Automation::getMOTD(std::string guild) +{ + std::map<std::string, std::string>::iterator it; + it=guildMOTD.find(guild); + + if (it != guildMOTD.end()) + return it->second; + else + return ""; +} + + + + diff --git a/src/automation.h b/src/automation.h new file mode 100644 index 0000000..0f563fe --- /dev/null +++ b/src/automation.h @@ -0,0 +1,77 @@ +/* + * + * Automation.h: The Ruined Place Chat Bot. + * + */ + +#include <iostream> +#include <string> +#include <set> + + + +extern bool automation; + +struct member +{ + std::string name; + std::string guildName; /* Now suports more than one group */ + int status; // 0 = offline, 1 = online + int accesslevel; // -1 = blocked, 0 = normal member, 10 = guildmaster, 20 = admin. + /* Note: blocked users do not have there online status updated, so don't recieve any messages.*/ + int info; /* 0 = hide info messages, 1 = show info messages*/ + + bool operator<(const member &a) const + { return name < a.name; } +}; + +struct memberinvite +{ + std::string name; + std::string guildName; + + bool operator<(const memberinvite &a) const + { return name < a.name; } +}; + +struct whispermsg +{ + std::string name; + std::string message; +}; + +class Automation +{ + public: + + Automation(); + ~Automation(); + static Automation *getAutomationHandler(); + + void commandHandler(std::string message, std::string nick); + void logic(); + + void addMember(std::string name, std::string guildName, int access); + void removeMember(std::string name); + bool inGuild(std::string name); + void addMessage(std::string msg, std::string guildName, std::string sender, int p); + void updateOnline(std::set<std::string> &onlinePlayers); + int countOnline(std::string guildName); + int accessLevel(std::string name); + void saveMembers(); + void loadMembers(); + void whisper(std::string name, std::string msg, int priority); + void showOptions(); + std::string colorText(std::string text); + + + private: + std::string getMOTD(std::string guild); + void testMsg(); + void debugMsg(std::string msg); + member findByName(std::string name); + void clearMembers(); + bool hasPermission(std::string user, std::string player, int changeLevel); +}; + + diff --git a/src/game.cpp b/src/game.cpp new file mode 100644 index 0000000..d933c2f --- /dev/null +++ b/src/game.cpp @@ -0,0 +1,103 @@ +#include "game.h" + +#include <fstream> +#include <sstream> +#include <string> +#include <iostream> + +#include "automation.h" +#include "net/nethandler.h" +#include "net/network.h" +#include "onlinelist.h" + +std::string map_path; +volatile int tick_time; +volatile int cur_time; +const int MAX_TIME = 10000; +bool done = false; + +OnlineList *onlinelist; + +/** + * Advances game logic counter. + */ +Uint32 nextTick(Uint32 interval, void *param) +{ + tick_time++; + if (tick_time == MAX_TIME) tick_time = 0; + return interval; +} + +int get_elapsed_time(int start_time) +{ + if (start_time <= tick_time) { + return (tick_time - start_time) * 10; + } + else { + return (tick_time + (MAX_TIME - start_time)) * 10; + } +} + +Game::Game() +{ + // Initialize timers + tick_time = 0; + SDL_AddTimer(10, nextTick, NULL); // Logic counter + onlinelist = new OnlineList(); +} + +Game::~Game() +{ + delete onlinelist; +} + +int stay_awake(void *data) +{ + /* Eathena seems to kick the client after 10 mins of inactivity. + A teenky hack to keep it alive.*/ + while (!done) + { + NetHandler::getNetInstance()->sit(); + std::cout << "I'm still here." << std::endl; + SDL_Delay(5 * 60 * 1000); + } +} + +void Game::logic() +{ + done = false; + int gameTime = tick_time; + + SDL_Thread *wakeywakey; + + + Network *mNetwork = NetHandler::getNetInstance()->getNetwork(); + NetHandler::getNetInstance()->mapLoaded(); + NetHandler::getNetInstance()->ping(tick_time); + //NetHandler::getNetInstance()->sit(); + NetHandler::getNetInstance()->loadHandlers(); + wakeywakey = SDL_CreateThread(stay_awake, NULL); + + while (!done) + { + if (mNetwork->getState() == Network::ERROR_BROKE) //get out of this loop to allow a restart. + done = true; + + mNetwork->flush(); + mNetwork->dispatchMessages(); + + while (get_elapsed_time(gameTime) > 0) + { + cur_time = static_cast<int>(time(0)); + onlinelist->logic(); + Automation::getAutomationHandler()->logic(); + ++gameTime; + } + + gameTime = tick_time; + + SDL_Delay(10); // Don't steal all the cpu time. + } + + SDL_KillThread(wakeywakey); +} diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..e9cac14 --- /dev/null +++ b/src/game.h @@ -0,0 +1,37 @@ +/* + * File: game.h + * Author: dipesh + * + * Created on July 31, 2010, 6:27 PM + */ + +#ifndef _GAME_H +#define _GAME_H + +#include <iosfwd> +#include <deque> + + +//class MessageHandler; +class Network; + +extern volatile int cur_time; +extern std::string map_path; + +class Game +{ + public: + Game(); + ~Game(); + + void logic(); + protected: +}; + /** + * Returns elapsed time. (Warning: very unsafe function, it supposes the delay + * is always < 10 seconds) + */ +int get_elapsed_time(int start_time); + +#endif /* _GAME_H */ + diff --git a/src/logindata.h b/src/logindata.h new file mode 100644 index 0000000..62a04ff --- /dev/null +++ b/src/logindata.h @@ -0,0 +1,42 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: logindata.h 2184 2006-02-23 16:02:00Z der_doener $ + */ + +#ifndef _TMW_LOGINDATA_H +#define _TMW_LOGINDATA_H + +struct LoginData +{ + std::string username; + std::string password; + std::string hostname; + short port; + + int account_ID; + int session_ID1; + int session_ID2; + char sex; + + bool remember; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..56f7815 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,153 @@ +/* + * File: main.cpp + * Author: dipesh + * + * Created on July 31, 2010, 6:04 PM + */ + +#include <stdlib.h> +#include <iostream> +#include <string> +#include <SDL.h> + +#include "logindata.h" +#include "game.h" +#include "main.h" +#include "automation.h" + +#include "net/charserverhandler.h" +#include "net/loginhandler.h" +#include "net/maploginhandler.h" +#include "net/messagein.h" +#include "net/messageout.h" +#include "net/network.h" +#include "net/nethandler.h" +#include "serverinfo.h" + +#if defined WIN32 +#include "Windows.h" +#include "Winbase.h" +#include "utils/specialfolder.h" +#endif + +unsigned char state = LOGIN_STATE; +unsigned char oldstate; +std::string errorMessage; +char n_server, n_character; + +class SERVER_INFO; +SERVER_INFO **server_info; + +std::string main_username = "test"; +std::string main_pw = "test"; +std::string main_host = "127.0.0.1"; +int main_charno = 1; //character slot + +int main_port = 6901; + +int charID[3]; +int world; +std::string char_name; +std::string mLocalDataDir; + +LoginData loginData; + +void init_engine() +{ + + if (SDL_Init(SDL_INIT_TIMER) < 0) { + std::cerr << "Could not initialize SDL: " << + SDL_GetError() << std::endl; + exit(1); + } + + atexit(SDL_Quit); + mLocalDataDir = "."; + +#if defined WIN32 + mLocalDataDir = getSpecialFolderLocation(CSIDL_LOCAL_APPDATA); + mLocalDataDir += "/ManaGuild"; +#endif +} + +int main(int argc, char **argv) +{ + Automation::getAutomationHandler()->loadMembers(); + + init_engine(); + SDLNet_Init(); + Network *network = NetHandler::getNetInstance()->getNetwork(); + Game *game = new Game(); + + while (state != EXIT_STATE) + { + network->flush(); + network->dispatchMessages(); + + if (network->getState() == Network::ERROR_BROKE) + { + state = ERROR_STATE; + errorMessage = "Got disconnected from server!"; + } + + if (state != oldstate) + { + oldstate = state; + + switch (oldstate) + { + // Those states that don't cause a network disconnect + case ACCOUNT_STATE: + case CHAR_SELECT_STATE: + case GAME_STATE: + break; + + default: + network->disconnect(); + network->clearHandlers(); + break; + } + + switch (state) + { + case LOGIN_STATE: + state = ACCOUNT_STATE; + break; + case ACCOUNT_STATE: + loginData.hostname = main_host; + loginData.port = main_port; + loginData.password = main_pw; + loginData.username = main_username; + NetHandler::getNetInstance()->accountLogin(&loginData); + break; + case CHAR_SERVER_STATE: + { + SERVER_INFO *si = server_info[world]; + loginData.hostname = iptostring(si->address); + loginData.port = si->port; + NetHandler::getNetInstance()->charLogin(&loginData); + break; + } + case CHAR_SELECT_STATE: + NetHandler::getNetInstance()->attemptCharSelect(); + break; + case CONNECTING_STATE: + NetHandler::getNetInstance()->mapLogin(&loginData); + break; + case GAME_STATE: + game->logic(); + break; + case ERROR_STATE: + state = EXIT_STATE; //LOGIN_STATE + break; + default: + state = EXIT_STATE; + break; + } + } + } + + delete game; + return (EXIT_SUCCESS); +} + diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..1b66278 --- /dev/null +++ b/src/main.h @@ -0,0 +1,40 @@ +/* + * File: man.h + * Author: dipesh + * + * Created on July 31, 2010, 6:04 PM + */ + +#ifndef _MAIN_H +#define _MAIN_H + +#include <iostream> +#include <string> +#include "serverinfo.h" + +extern SERVER_INFO **server_info; + +extern int charID[3]; + +enum { + EXIT_STATE, + LOGIN_STATE, + ACCOUNT_STATE, + CHAR_SERVER_STATE, + CHAR_SELECT_STATE, + GAME_STATE, + ERROR_STATE, + CONNECTING_STATE +}; + +extern char n_server, n_character; +extern unsigned char state; +extern std::string errorMessage; +extern std::string main_host; +extern std::string char_name; +extern int main_charno; +extern int world; +extern std::string mLocalDataDir; + +#endif /* _MAIN_H */ + diff --git a/src/nbproject/Makefile-Debug.mk b/src/nbproject/Makefile-Debug.mk new file mode 100644 index 0000000..d5830e6 --- /dev/null +++ b/src/nbproject/Makefile-Debug.mk @@ -0,0 +1,175 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux-x86 +CND_CONF=Debug +CND_DISTDIR=dist + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=build/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/utils/stringutils.o \ + ${OBJECTDIR}/net/maploginhandler.o \ + ${OBJECTDIR}/game.o \ + ${OBJECTDIR}/net/messageout.o \ + ${OBJECTDIR}/onlinelist.o \ + ${OBJECTDIR}/net/nethandler.o \ + ${OBJECTDIR}/main.o \ + ${OBJECTDIR}/net/messagein.o \ + ${OBJECTDIR}/automation.o \ + ${OBJECTDIR}/net/packet.o \ + ${OBJECTDIR}/net/charserverhandler.o \ + ${OBJECTDIR}/net/loginhandler.o \ + ${OBJECTDIR}/utils/specialfolder.o \ + ${OBJECTDIR}/net/network.o \ + ${OBJECTDIR}/net/chathandler.o \ + ${OBJECTDIR}/net/protocol.o \ + ${OBJECTDIR}/net/messagehandler.o + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS=-pg +CXXFLAGS=-pg + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS=-L/usr/lib -lSDL -lSDL_net -lpthread -lcurl + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + ${MAKE} -f nbproject/Makefile-Debug.mk dist/Debug/GNU-Linux-x86/guild + +dist/Debug/GNU-Linux-x86/guild: ${OBJECTFILES} + ${MKDIR} -p dist/Debug/GNU-Linux-x86 + ${LINK.cc} -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/guild ${OBJECTFILES} ${LDLIBSOPTIONS} + +${OBJECTDIR}/utils/stringutils.o: nbproject/Makefile-${CND_CONF}.mk utils/stringutils.cpp + ${MKDIR} -p ${OBJECTDIR}/utils + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/utils/stringutils.o utils/stringutils.cpp + +${OBJECTDIR}/net/maploginhandler.o: nbproject/Makefile-${CND_CONF}.mk net/maploginhandler.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/maploginhandler.o net/maploginhandler.cpp + +${OBJECTDIR}/game.o: nbproject/Makefile-${CND_CONF}.mk game.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/game.o game.cpp + +${OBJECTDIR}/net/messageout.o: nbproject/Makefile-${CND_CONF}.mk net/messageout.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/messageout.o net/messageout.cpp + +${OBJECTDIR}/onlinelist.o: nbproject/Makefile-${CND_CONF}.mk onlinelist.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/onlinelist.o onlinelist.cpp + +${OBJECTDIR}/net/nethandler.o: nbproject/Makefile-${CND_CONF}.mk net/nethandler.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/nethandler.o net/nethandler.cpp + +${OBJECTDIR}/main.o: nbproject/Makefile-${CND_CONF}.mk main.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/main.o main.cpp + +${OBJECTDIR}/net/messagein.o: nbproject/Makefile-${CND_CONF}.mk net/messagein.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/messagein.o net/messagein.cpp + +${OBJECTDIR}/automation.o: nbproject/Makefile-${CND_CONF}.mk automation.cpp + ${MKDIR} -p ${OBJECTDIR} + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/automation.o automation.cpp + +${OBJECTDIR}/net/packet.o: nbproject/Makefile-${CND_CONF}.mk net/packet.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/packet.o net/packet.cpp + +${OBJECTDIR}/net/charserverhandler.o: nbproject/Makefile-${CND_CONF}.mk net/charserverhandler.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/charserverhandler.o net/charserverhandler.cpp + +${OBJECTDIR}/net/loginhandler.o: nbproject/Makefile-${CND_CONF}.mk net/loginhandler.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/loginhandler.o net/loginhandler.cpp + +${OBJECTDIR}/utils/specialfolder.o: nbproject/Makefile-${CND_CONF}.mk utils/specialfolder.cpp + ${MKDIR} -p ${OBJECTDIR}/utils + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/utils/specialfolder.o utils/specialfolder.cpp + +${OBJECTDIR}/net/network.o: nbproject/Makefile-${CND_CONF}.mk net/network.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/network.o net/network.cpp + +${OBJECTDIR}/net/chathandler.o: nbproject/Makefile-${CND_CONF}.mk net/chathandler.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/chathandler.o net/chathandler.cpp + +${OBJECTDIR}/net/protocol.o: nbproject/Makefile-${CND_CONF}.mk net/protocol.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/protocol.o net/protocol.cpp + +${OBJECTDIR}/net/messagehandler.o: nbproject/Makefile-${CND_CONF}.mk net/messagehandler.cpp + ${MKDIR} -p ${OBJECTDIR}/net + ${RM} $@.d + $(COMPILE.cc) -g -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/messagehandler.o net/messagehandler.cpp + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + ${RM} -r build/Debug + ${RM} dist/Debug/GNU-Linux-x86/guild + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git a/src/nbproject/Makefile-Release.mk b/src/nbproject/Makefile-Release.mk new file mode 100644 index 0000000..90d16af --- /dev/null +++ b/src/nbproject/Makefile-Release.mk @@ -0,0 +1,176 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a -pre and a -post target defined where you can add customized code. +# +# This makefile implements configuration specific macros and targets. + + +# Environment +MKDIR=mkdir +CP=cp +CCADMIN=CCadmin +RANLIB=ranlib +CC=gcc +CCC=g++ +CXX=g++ +FC=gfortran +AS=as + +# Macros +CND_PLATFORM=GNU-Linux-x86 +CND_CONF=Release +CND_DISTDIR=dist + +# Include project Makefile +include Makefile + +# Object Directory +OBJECTDIR=build/${CND_CONF}/${CND_PLATFORM} + +# Object Files +OBJECTFILES= \ + ${OBJECTDIR}/utils/stringutils.o \ + ${OBJECTDIR}/net/maploginhandler.o \ + ${OBJECTDIR}/game.o \ + ${OBJECTDIR}/net/messageout.o \ + ${OBJECTDIR}/onlinelist.o \ + ${OBJECTDIR}/net/nethandler.o \ + ${OBJECTDIR}/main.o \ + ${OBJECTDIR}/net/messagein.o \ + ${OBJECTDIR}/automation.o \ + ${OBJECTDIR}/net/packet.o \ + ${OBJECTDIR}/net/charserverhandler.o \ + ${OBJECTDIR}/net/loginhandler.o \ + ${OBJECTDIR}/utils/specialfolder.o \ + ${OBJECTDIR}/net/network.o \ + ${OBJECTDIR}/net/chathandler.o \ + ${OBJECTDIR}/net/protocol.o \ + ${OBJECTDIR}/net/messagehandler.o + +# C Compiler Flags +CFLAGS= + +# CC Compiler Flags +CCFLAGS=-march=i686 +CXXFLAGS=-march=i686 + +# Fortran Compiler Flags +FFLAGS= + +# Assembler Flags +ASFLAGS= + +# Link Libraries and Options +LDLIBSOPTIONS=-lSDL -lSDL_net -lcurl -lpthread + +# Build Targets +.build-conf: ${BUILD_SUBPROJECTS} + ${MAKE} -f nbproject/Makefile-Release.mk dist/Release/GNU-Linux-x86/guild + +${OBJECTDIR}/utils/stringutils.o: nbproject/Makefile-${CND_CONF}.mk utils/stringutils.cpp + mkdir -p ${OBJECTDIR}/utils + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/utils/stringutils.o utils/stringutils.cpp + + +${OBJECTDIR}/net/maploginhandler.o: nbproject/Makefile-${CND_CONF}.mk net/maploginhandler.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/maploginhandler.o net/maploginhandler.cpp + +${OBJECTDIR}/game.o: nbproject/Makefile-${CND_CONF}.mk game.cpp + mkdir -p ${OBJECTDIR} + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/game.o game.cpp + +${OBJECTDIR}/net/messageout.o: nbproject/Makefile-${CND_CONF}.mk net/messageout.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/messageout.o net/messageout.cpp + +${OBJECTDIR}/onlinelist.o: nbproject/Makefile-${CND_CONF}.mk onlinelist.cpp + mkdir -p ${OBJECTDIR} + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -I/usr/local/include -MMD -MP -MF $@.d -o ${OBJECTDIR}/onlinelist.o onlinelist.cpp + +${OBJECTDIR}/net/nethandler.o: nbproject/Makefile-${CND_CONF}.mk net/nethandler.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/nethandler.o net/nethandler.cpp + +${OBJECTDIR}/main.o: nbproject/Makefile-${CND_CONF}.mk main.cpp + mkdir -p ${OBJECTDIR} + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/main.o main.cpp + +${OBJECTDIR}/net/messagein.o: nbproject/Makefile-${CND_CONF}.mk net/messagein.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/messagein.o net/messagein.cpp + +${OBJECTDIR}/automation.o: nbproject/Makefile-${CND_CONF}.mk automation.cpp + mkdir -p ${OBJECTDIR} + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/automation.o automation.cpp + +${OBJECTDIR}/net/packet.o: nbproject/Makefile-${CND_CONF}.mk net/packet.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/packet.o net/packet.cpp + +${OBJECTDIR}/net/charserverhandler.o: nbproject/Makefile-${CND_CONF}.mk net/charserverhandler.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/charserverhandler.o net/charserverhandler.cpp + +${OBJECTDIR}/net/loginhandler.o: nbproject/Makefile-${CND_CONF}.mk net/loginhandler.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/loginhandler.o net/loginhandler.cpp + +${OBJECTDIR}/utils/specialfolder.o: nbproject/Makefile-${CND_CONF}.mk utils/specialfolder.cpp + mkdir -p ${OBJECTDIR}/utils + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/utils/specialfolder.o utils/specialfolder.cpp + +${OBJECTDIR}/net/network.o: nbproject/Makefile-${CND_CONF}.mk net/network.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/network.o net/network.cpp + +${OBJECTDIR}/net/chathandler.o: nbproject/Makefile-${CND_CONF}.mk net/chathandler.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/chathandler.o net/chathandler.cpp + +${OBJECTDIR}/net/protocol.o: nbproject/Makefile-${CND_CONF}.mk net/protocol.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/protocol.o net/protocol.cpp + +${OBJECTDIR}/net/messagehandler.o: nbproject/Makefile-${CND_CONF}.mk net/messagehandler.cpp + mkdir -p ${OBJECTDIR}/net + rm -f $@.d + g++ -c -O2 -s -I/usr/include/SDL -MMD -MP -MF $@.d -o ${OBJECTDIR}/net/messagehandler.o net/messagehandler.cpp + +dist/Release/GNU-Linux-x86/guild: ${OBJECTFILES} + mkdir -p dist/Release/GNU-Linux-x86 + ${LINK.cc} -L/usr/local/lib -o ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/guild ${OBJECTFILES} ${LDLIBSOPTIONS} + +# Subprojects +.build-subprojects: + +# Clean Targets +.clean-conf: ${CLEAN_SUBPROJECTS} + rm -f -r build/Release + rm -f dist/Release/GNU-Linux-x86/guild + +# Subprojects +.clean-subprojects: + +# Enable dependency checking +.dep.inc: .depcheck-impl + +include .dep.inc diff --git a/src/nbproject/Makefile-impl.mk b/src/nbproject/Makefile-impl.mk new file mode 100644 index 0000000..8ffd6a4 --- /dev/null +++ b/src/nbproject/Makefile-impl.mk @@ -0,0 +1,123 @@ +# +# Generated Makefile - do not edit! +# +# Edit the Makefile in the project folder instead (../Makefile). Each target +# has a pre- and a post- target defined where you can add customization code. +# +# This makefile implements macros and targets common to all configurations. +# +# NOCDDL + + +# Building and Cleaning subprojects are done by default, but can be controlled with the SUB +# macro. If SUB=no, subprojects will not be built or cleaned. The following macro +# statements set BUILD_SUB-CONF and CLEAN_SUB-CONF to .build-reqprojects-conf +# and .clean-reqprojects-conf unless SUB has the value 'no' +SUB_no=NO +SUBPROJECTS=${SUB_${SUB}} +BUILD_SUBPROJECTS_=.build-subprojects +BUILD_SUBPROJECTS_NO= +BUILD_SUBPROJECTS=${BUILD_SUBPROJECTS_${SUBPROJECTS}} +CLEAN_SUBPROJECTS_=.clean-subprojects +CLEAN_SUBPROJECTS_NO= +CLEAN_SUBPROJECTS=${CLEAN_SUBPROJECTS_${SUBPROJECTS}} + + +# Project Name +PROJECTNAME=guild + +# Active Configuration +DEFAULTCONF=Debug +CONF=${DEFAULTCONF} + +# All Configurations +ALLCONFS=Debug Release + + +# build +.build-impl: .build-pre .validate-impl .depcheck-impl + @#echo "=> Running $@... Configuration=$(CONF)" + ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf + + +# clean +.clean-impl: .clean-pre .validate-impl .depcheck-impl + @#echo "=> Running $@... Configuration=$(CONF)" + ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf + + +# clobber +.clobber-impl: .clobber-pre .depcheck-impl + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + ${MAKE} -f nbproject/Makefile-$${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf; \ + done + +# all +.all-impl: .all-pre .depcheck-impl + @#echo "=> Running $@..." + for CONF in ${ALLCONFS}; \ + do \ + ${MAKE} -f nbproject/Makefile-$${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf; \ + done + +# dependency checking support +.depcheck-impl: + @echo "# This code depends on make tool being used" >.dep.inc + @if [ -n "${MAKE_VERSION}" ]; then \ + echo "DEPFILES=\$$(wildcard \$$(addsuffix .d, \$${OBJECTFILES}))" >>.dep.inc; \ + echo "ifneq (\$${DEPFILES},)" >>.dep.inc; \ + echo "include \$${DEPFILES}" >>.dep.inc; \ + echo "endif" >>.dep.inc; \ + else \ + echo ".KEEP_STATE:" >>.dep.inc; \ + echo ".KEEP_STATE_FILE:.make.state.\$${CONF}" >>.dep.inc; \ + fi + +# configuration validation +.validate-impl: + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + echo ""; \ + echo "Error: can not find the makefile for configuration '${CONF}' in project ${PROJECTNAME}"; \ + echo "See 'make help' for details."; \ + echo "Current directory: " `pwd`; \ + echo ""; \ + fi + @if [ ! -f nbproject/Makefile-${CONF}.mk ]; \ + then \ + exit 1; \ + fi + + +# help +.help-impl: .help-pre + @echo "This makefile supports the following configurations:" + @echo " ${ALLCONFS}" + @echo "" + @echo "and the following targets:" + @echo " build (default target)" + @echo " clean" + @echo " clobber" + @echo " all" + @echo " help" + @echo "" + @echo "Makefile Usage:" + @echo " make [CONF=<CONFIGURATION>] [SUB=no] build" + @echo " make [CONF=<CONFIGURATION>] [SUB=no] clean" + @echo " make [SUB=no] clobber" + @echo " make [SUB=no] all" + @echo " make help" + @echo "" + @echo "Target 'build' will build a specific configuration and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'clean' will clean a specific configuration and, unless 'SUB=no'," + @echo " also clean subprojects." + @echo "Target 'clobber' will remove all built files from all configurations and," + @echo " unless 'SUB=no', also from subprojects." + @echo "Target 'all' will will build all configurations and, unless 'SUB=no'," + @echo " also build subprojects." + @echo "Target 'help' prints this message." + @echo "" + diff --git a/src/nbproject/Makefile-variables.mk b/src/nbproject/Makefile-variables.mk new file mode 100644 index 0000000..1d1cd46 --- /dev/null +++ b/src/nbproject/Makefile-variables.mk @@ -0,0 +1,24 @@ +# +# Generated - do not edit! +# +# NOCDDL +# +CND_BASEDIR=`pwd` +CND_BUILDDIR=build +CND_DISTDIR=dist +# Debug configuration +CND_PLATFORM_Debug=GNU-Linux-x86 +CND_ARTIFACT_DIR_Debug=dist/Debug/GNU-Linux-x86 +CND_ARTIFACT_NAME_Debug=guild +CND_ARTIFACT_PATH_Debug=dist/Debug/GNU-Linux-x86/guild +CND_PACKAGE_DIR_Debug=dist/Debug/GNU-Linux-x86/package +CND_PACKAGE_NAME_Debug=guild.tar +CND_PACKAGE_PATH_Debug=dist/Debug/GNU-Linux-x86/package/guild.tar +# Release configuration +CND_PLATFORM_Release=GNU-Linux-x86 +CND_ARTIFACT_DIR_Release=dist/Release/GNU-Linux-x86 +CND_ARTIFACT_NAME_Release=guild +CND_ARTIFACT_PATH_Release=dist/Release/GNU-Linux-x86/guild +CND_PACKAGE_DIR_Release=dist/Release/GNU-Linux-x86/package +CND_PACKAGE_NAME_Release=guild.tar +CND_PACKAGE_PATH_Release=dist/Release/GNU-Linux-x86/package/guild.tar diff --git a/src/nbproject/Package-Debug.bash b/src/nbproject/Package-Debug.bash new file mode 100644 index 0000000..361cd54 --- /dev/null +++ b/src/nbproject/Package-Debug.bash @@ -0,0 +1,74 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux-x86 +CND_CONF=Debug +CND_DISTDIR=dist +TMPDIR=build/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/guild +OUTPUT_BASENAME=guild +PACKAGE_TOP_DIR=guild/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${TMPDIR} +mkdir -p ${TMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory ${TMPDIR}/guild/bin +copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/guild.tar +cd ${TMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/guild.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${TMPDIR} diff --git a/src/nbproject/Package-Release.bash b/src/nbproject/Package-Release.bash new file mode 100644 index 0000000..359438e --- /dev/null +++ b/src/nbproject/Package-Release.bash @@ -0,0 +1,74 @@ +#!/bin/bash -x + +# +# Generated - do not edit! +# + +# Macros +TOP=`pwd` +CND_PLATFORM=GNU-Linux-x86 +CND_CONF=Release +CND_DISTDIR=dist +TMPDIR=build/${CND_CONF}/${CND_PLATFORM}/tmp-packaging +TMPDIRNAME=tmp-packaging +OUTPUT_PATH=${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/guild +OUTPUT_BASENAME=guild +PACKAGE_TOP_DIR=guild/ + +# Functions +function checkReturnCode +{ + rc=$? + if [ $rc != 0 ] + then + exit $rc + fi +} +function makeDirectory +# $1 directory path +# $2 permission (optional) +{ + mkdir -p "$1" + checkReturnCode + if [ "$2" != "" ] + then + chmod $2 "$1" + checkReturnCode + fi +} +function copyFileToTmpDir +# $1 from-file path +# $2 to-file path +# $3 permission +{ + cp "$1" "$2" + checkReturnCode + if [ "$3" != "" ] + then + chmod $3 "$2" + checkReturnCode + fi +} + +# Setup +cd "${TOP}" +mkdir -p ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package +rm -rf ${TMPDIR} +mkdir -p ${TMPDIR} + +# Copy files and create directories and links +cd "${TOP}" +makeDirectory ${TMPDIR}/guild/bin +copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755 + + +# Generate tar file +cd "${TOP}" +rm -f ${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/guild.tar +cd ${TMPDIR} +tar -vcf ../../../../${CND_DISTDIR}/${CND_CONF}/${CND_PLATFORM}/package/guild.tar * +checkReturnCode + +# Cleanup +cd "${TOP}" +rm -rf ${TMPDIR} diff --git a/src/nbproject/configurations.xml b/src/nbproject/configurations.xml new file mode 100644 index 0000000..d276a91 --- /dev/null +++ b/src/nbproject/configurations.xml @@ -0,0 +1,131 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configurationDescriptor version="62"> + <logicalFolder name="root" displayName="root" projectFiles="true"> + <logicalFolder name="HeaderFiles" + displayName="Header Files" + projectFiles="true"> + <logicalFolder name="net" displayName="net" projectFiles="true"> + <itemPath>net/charserverhandler.h</itemPath> + <itemPath>net/chathandler.h</itemPath> + <itemPath>net/loginhandler.h</itemPath> + <itemPath>net/maploginhandler.h</itemPath> + <itemPath>net/messagehandler.h</itemPath> + <itemPath>net/messagein.h</itemPath> + <itemPath>net/messageout.h</itemPath> + <itemPath>net/nethandler.h</itemPath> + <itemPath>net/network.h</itemPath> + <itemPath>net/packet.h</itemPath> + <itemPath>net/protocol.h</itemPath> + </logicalFolder> + <logicalFolder name="utils" displayName="utils" projectFiles="true"> + <itemPath>utils/mutex.h</itemPath> + <itemPath>utils/specialfolder.h</itemPath> + <itemPath>utils/stringutils.h</itemPath> + </logicalFolder> + <itemPath>automation.h</itemPath> + <itemPath>game.h</itemPath> + <itemPath>logindata.h</itemPath> + <itemPath>main.h</itemPath> + <itemPath>onlinelist.h</itemPath> + <itemPath>serverinfo.h</itemPath> + </logicalFolder> + <logicalFolder name="ResourceFiles" + displayName="Resource Files" + projectFiles="true"> + </logicalFolder> + <logicalFolder name="SourceFiles" + displayName="Source Files" + projectFiles="true"> + <logicalFolder name="net" displayName="net" projectFiles="true"> + <itemPath>net/charserverhandler.cpp</itemPath> + <itemPath>net/chathandler.cpp</itemPath> + <itemPath>net/loginhandler.cpp</itemPath> + <itemPath>net/maploginhandler.cpp</itemPath> + <itemPath>net/messagehandler.cpp</itemPath> + <itemPath>net/messagein.cpp</itemPath> + <itemPath>net/messageout.cpp</itemPath> + <itemPath>net/nethandler.cpp</itemPath> + <itemPath>net/network.cpp</itemPath> + <itemPath>net/packet.cpp</itemPath> + <itemPath>net/protocol.cpp</itemPath> + </logicalFolder> + <logicalFolder name="utils" displayName="utils" projectFiles="true"> + <itemPath>utils/specialfolder.cpp</itemPath> + <itemPath>utils/stringutils.cpp</itemPath> + </logicalFolder> + <itemPath>automation.cpp</itemPath> + <itemPath>game.cpp</itemPath> + <itemPath>main.cpp</itemPath> + <itemPath>onlinelist.cpp</itemPath> + </logicalFolder> + <logicalFolder name="ExternalFiles" + displayName="Important Files" + projectFiles="false"> + <itemPath>Makefile</itemPath> + </logicalFolder> + </logicalFolder> + <sourceRootList> + <Elem>net</Elem> + <Elem>utils</Elem> + </sourceRootList> + <projectmakefile>Makefile</projectmakefile> + <confs> + <conf name="Debug" type="1"> + <toolsSet> + <developmentServer>localhost</developmentServer> + <compilerSet>GNU|GNU</compilerSet> + <platform>2</platform> + </toolsSet> + <compileType> + <ccTool> + <incDir> + <pElem>/usr/include/SDL</pElem> + </incDir> + <commandLine>-pg</commandLine> + </ccTool> + <linkerTool> + <linkerAddLib> + <pElem>/usr/lib</pElem> + </linkerAddLib> + <linkerLibItems> + <linkerLibLibItem>SDL</linkerLibLibItem> + <linkerLibLibItem>SDL_net</linkerLibLibItem> + <linkerLibLibItem>pthread</linkerLibLibItem> + <linkerLibLibItem>curl</linkerLibLibItem> + </linkerLibItems> + </linkerTool> + </compileType> + </conf> + <conf name="Release" type="1"> + <toolsSet> + <developmentServer>localhost</developmentServer> + <compilerSet>GNU|GNU</compilerSet> + <platform>2</platform> + </toolsSet> + <compileType> + <cTool> + <developmentMode>5</developmentMode> + </cTool> + <ccTool> + <developmentMode>5</developmentMode> + <stripSymbols>true</stripSymbols> + <commandlineTool>g++</commandlineTool> + <incDir> + <pElem>/usr/include/SDL</pElem> + </incDir> + <commandLine>-march=i686</commandLine> + </ccTool> + <fortranCompilerTool> + <developmentMode>5</developmentMode> + </fortranCompilerTool> + <linkerTool> + <linkerLibItems> + <linkerLibLibItem>SDL</linkerLibLibItem> + <linkerLibLibItem>SDL_net</linkerLibLibItem> + <linkerLibLibItem>curl</linkerLibLibItem> + </linkerLibItems> + </linkerTool> + </compileType> + </conf> + </confs> +</configurationDescriptor> diff --git a/src/nbproject/private/configurations.xml b/src/nbproject/private/configurations.xml new file mode 100644 index 0000000..ef9712c --- /dev/null +++ b/src/nbproject/private/configurations.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<configurationDescriptor version="62"> + <projectmakefile>Makefile</projectmakefile> + <defaultConf>0</defaultConf> + <confs> + <conf name="Debug" type="1"> + <gdbdebugger version="2"> + <gdb_command>gdb</gdb_command> + <array_repeat_threshold>10</array_repeat_threshold> + </gdbdebugger> + <gizmo_options version="3"> + </gizmo_options> + <runprofile version="6"> + <args></args> + <rundir></rundir> + <buildfirst>true</buildfirst> + <console-type>0</console-type> + <terminal-type>0</terminal-type> + <remove-instrumentation>0</remove-instrumentation> + <environment> + </environment> + </runprofile> + </conf> + <conf name="Release" type="1"> + <gdbdebugger version="2"> + <gdb_command>gdb</gdb_command> + <array_repeat_threshold>10</array_repeat_threshold> + </gdbdebugger> + <gizmo_options version="3"> + </gizmo_options> + <runprofile version="6"> + <args></args> + <rundir></rundir> + <buildfirst>true</buildfirst> + <console-type>0</console-type> + <terminal-type>0</terminal-type> + <remove-instrumentation>0</remove-instrumentation> + <environment> + </environment> + </runprofile> + </conf> + </confs> +</configurationDescriptor> diff --git a/src/nbproject/private/private.properties b/src/nbproject/private/private.properties new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/nbproject/private/private.properties diff --git a/src/nbproject/private/private.xml b/src/nbproject/private/private.xml new file mode 100644 index 0000000..c1f155a --- /dev/null +++ b/src/nbproject/private/private.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project-private xmlns="http://www.netbeans.org/ns/project-private/1"> + <editor-bookmarks xmlns="http://www.netbeans.org/ns/editor-bookmarks/1"/> +</project-private> diff --git a/src/nbproject/project.properties b/src/nbproject/project.properties new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/nbproject/project.properties diff --git a/src/nbproject/project.xml b/src/nbproject/project.xml new file mode 100644 index 0000000..f6e48a3 --- /dev/null +++ b/src/nbproject/project.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://www.netbeans.org/ns/project/1"> + <type>org.netbeans.modules.cnd.makeproject</type> + <configuration> + <data xmlns="http://www.netbeans.org/ns/make-project/1"> + <name>guild</name> + <make-project-type>0</make-project-type> + <c-extensions/> + <cpp-extensions>cpp</cpp-extensions> + <header-extensions>h</header-extensions> + <sourceEncoding>UTF-8</sourceEncoding> + <make-dep-projects/> + </data> + </configuration> +</project> diff --git a/src/net/charserverhandler.cpp b/src/net/charserverhandler.cpp new file mode 100644 index 0000000..d500c0d --- /dev/null +++ b/src/net/charserverhandler.cpp @@ -0,0 +1,166 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: charserverhandler.cpp 2137 2006-02-04 16:54:35Z der_doener $ + */ + +#include "charserverhandler.h" + +#include "messagein.h" +#include "network.h" +#include "protocol.h" + +#include "../game.h" +#include "../logindata.h" +#include "../main.h" + +CharServerHandler::CharServerHandler() +{ + static const Uint16 _messages[] = { + 0x006b, + 0x006c, + 0x006d, + 0x0071, + 0x0081, + 0 + }; + handledMessages = _messages; +} + +void CharServerHandler::handleMessage(MessageIn *msg) +{ + int slot; + + /* logger->log("CharServerHandler: Packet ID: %x, Length: %d", + msg->getId(), msg->getLength());*/ + switch (msg->getId()) + { + case 0x006b: + { + int tmpCharID[3]; + // Skip length word and an additional mysterious 20 bytes + msg->skip(2 + 20); + + // Derive number of characters from message length + n_character = (msg->getLength() - 24) / 106; + + for (int i = 0; i < n_character; i++) + { + + tmpCharID[i] = msg->readInt32(); + msg->readInt32(); //xp + msg->readInt32(); //gp + msg->readInt32(); //jobxp + msg->readInt32(); //joblvl + msg->skip(8); // unknown + msg->readInt32(); // option + msg->readInt32(); // karma + msg->readInt32(); // manner + msg->skip(2); // unknown + msg->readInt16(); //hp + msg->readInt16(); //maxhp + msg->readInt16(); //mp + msg->readInt16(); //maxmp + msg->readInt16(); // speed + msg->readInt16(); // class + msg->readInt16(); //hair + msg->readInt16(); //weapon + msg->readInt16(); //lvl + msg->readInt16(); // skill point + msg->readInt16(); // head bottom + msg->readInt16(); // shield + msg->readInt16(); // head option top + msg->readInt16(); // head option mid + msg->readInt16(); // hair color + msg->readInt16(); // unknown + std::string charname = msg->readString(24); + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + int slot = msg->readInt8(); // character slot + charID[slot] = tmpCharID[i]; /* Get the Character Id's, needed for map server.*/ + msg->readInt8(); // unknown + + if (slot == main_charno) + char_name = charname; + + /* logger->log("CharServer: Player: %s (%d)", + charname.c_str(), slot);*/ + } + + state = CHAR_SELECT_STATE; + break; + } + + case 0x006c: + switch (msg->readInt8()) { + case 0: + errorMessage = "Access denied"; + break; + case 1: + errorMessage = "Cannot use this ID"; + break; + default: + errorMessage = "Unknown failure to select character"; + break; + } + break; + + case 0x006d: + state = CONNECTING_STATE; + break; + + case 0x0071: + { + msg->skip(4); // CharID, the same as the one we've already recieved. + map_path = msg->readString(16); + mLoginData->hostname = iptostring(msg->readInt32()); + mLoginData->port = msg->readInt16(); + /*logger->log("Map: Server: %s (%s:%d)", + map_path.c_str(), + mLoginData->hostname.c_str(), + mLoginData->port);*/ + + state = CONNECTING_STATE; + break; + } + + case 0x0081: + switch (msg->readInt8()) { + case 1: + errorMessage = "Map server offline"; + break; + case 3: + errorMessage = "Speed hack detected"; + break; + case 8: + errorMessage = "Duplicated login"; + break; + default: + errorMessage = "Unkown error with 0x0081"; + break; + }; + state = ERROR_STATE; + break; + } +} diff --git a/src/net/charserverhandler.cpp~ b/src/net/charserverhandler.cpp~ new file mode 100644 index 0000000..ea08c00 --- /dev/null +++ b/src/net/charserverhandler.cpp~ @@ -0,0 +1,167 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: charserverhandler.cpp 2137 2006-02-04 16:54:35Z der_doener $ + */ + +#include "charserverhandler.h" + +#include "messagein.h" +#include "network.h" +#include "protocol.h" + +#include "../game.h" +#include "../log.h" +#include "../logindata.h" +#include "../main.h" + +CharServerHandler::CharServerHandler() +{ + static const Uint16 _messages[] = { + 0x006b, + 0x006c, + 0x006d, + 0x0071, + 0x0081, + 0 + }; + handledMessages = _messages; +} + +void CharServerHandler::handleMessage(MessageIn *msg) +{ + int slot; + + /* logger->log("CharServerHandler: Packet ID: %x, Length: %d", + msg->getId(), msg->getLength());*/ + switch (msg->getId()) + { + case 0x006b: + { + int tmpCharID[3]; + // Skip length word and an additional mysterious 20 bytes + msg->skip(2 + 20); + + // Derive number of characters from message length + n_character = (msg->getLength() - 24) / 106; + + for (int i = 0; i < n_character; i++) + { + + tmpCharID[i] = msg->readInt32(); + msg->readInt32(); //xp + msg->readInt32(); //gp + msg->readInt32(); //jobxp + msg->readInt32(); //joblvl + msg->skip(8); // unknown + msg->readInt32(); // option + msg->readInt32(); // karma + msg->readInt32(); // manner + msg->skip(2); // unknown + msg->readInt16(); //hp + msg->readInt16(); //maxhp + msg->readInt16(); //mp + msg->readInt16(); //maxmp + msg->readInt16(); // speed + msg->readInt16(); // class + msg->readInt16(); //hair + msg->readInt16(); //weapon + msg->readInt16(); //lvl + msg->readInt16(); // skill point + msg->readInt16(); // head bottom + msg->readInt16(); // shield + msg->readInt16(); // head option top + msg->readInt16(); // head option mid + msg->readInt16(); // hair color + msg->readInt16(); // unknown + std::string charname = msg->readString(24); + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + msg->readInt8(); //ATTR + int slot = msg->readInt8(); // character slot + charID[slot] = tmpCharID[i]; /* Get the Character Id's, needed for map server.*/ + msg->readInt8(); // unknown + + if (slot == main_charno) + char_name = charname; + + /* logger->log("CharServer: Player: %s (%d)", + charname.c_str(), slot);*/ + } + + state = CHAR_SELECT_STATE; + break; + } + + case 0x006c: + switch (msg->readInt8()) { + case 0: + errorMessage = "Access denied"; + break; + case 1: + errorMessage = "Cannot use this ID"; + break; + default: + errorMessage = "Unknown failure to select character"; + break; + } + break; + + case 0x006d: + state = CONNECTING_STATE; + break; + + case 0x0071: + { + msg->skip(4); // CharID, the same as the one we've already recieved. + map_path = msg->readString(16); + mLoginData->hostname = iptostring(msg->readInt32()); + mLoginData->port = msg->readInt16(); + /*logger->log("Map: Server: %s (%s:%d)", + map_path.c_str(), + mLoginData->hostname.c_str(), + mLoginData->port);*/ + + state = CONNECTING_STATE; + break; + } + + case 0x0081: + switch (msg->readInt8()) { + case 1: + errorMessage = "Map server offline"; + break; + case 3: + errorMessage = "Speed hack detected"; + break; + case 8: + errorMessage = "Duplicated login"; + break; + default: + errorMessage = "Unkown error with 0x0081"; + break; + }; + state = ERROR_STATE; + break; + } +} diff --git a/src/net/charserverhandler.h b/src/net/charserverhandler.h new file mode 100644 index 0000000..c6303a5 --- /dev/null +++ b/src/net/charserverhandler.h @@ -0,0 +1,52 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: charserverhandler.h 2137 2006-02-04 16:54:35Z der_doener $ + */ + +#ifndef _TMW_NET_CHARSERVERHANDLER_H +#define _TMW_NET_CHARSERVERHANDLER_H + +#include "messagehandler.h" + +//#include "../lockedarray.h" + +class LocalPlayer; +class LoginData; + +class CharServerHandler : public MessageHandler +{ + public: + CharServerHandler(); + + void handleMessage(MessageIn *msg); + + //void setCharInfo(LockedArray<LocalPlayer*> *charInfo) { mCharInfo = charInfo; }; + + void setLoginData(LoginData *loginData) { mLoginData = loginData; }; + + protected: + LoginData *mLoginData; + //LockedArray<LocalPlayer*> *mCharInfo; + + //LocalPlayer* readPlayerData(MessageIn *msg, int &slot); +}; + +#endif diff --git a/src/net/chathandler.cpp b/src/net/chathandler.cpp new file mode 100644 index 0000000..19abc24 --- /dev/null +++ b/src/net/chathandler.cpp @@ -0,0 +1,146 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: chathandler.cpp 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#include "chathandler.h" + +#include <SDL_types.h> +#include <string> +#include <sstream> +#include <iostream> + +#include "messagein.h" +#include "protocol.h" +#include "messageout.h" +#include "../automation.h" +#include "../game.h" +#include "../utils/stringutils.h" +#include "nethandler.h" + +ChatHandler::ChatHandler() +{ + static const Uint16 _messages[] = { + SMSG_BEING_CHAT, + SMSG_PLAYER_CHAT, + SMSG_WHISPER, + SMSG_WHISPER_RESPONSE, + SMSG_GM_CHAT, + 0 + }; + handledMessages = _messages; +} + +void ChatHandler::handleMessage(MessageIn *msg) +{ + //Being *being; + std::string chatMsg; + std::stringstream ss; + Sint16 chatMsgLength; + + switch (msg->getId()) + { + // Received speech from being + case SMSG_BEING_CHAT: + { + + chatMsgLength = msg->readInt16() - 8; + msg->readInt32(); + + if (chatMsgLength <= 0) + break; + + chatMsg = msg->readString(chatMsgLength); + + std::string::size_type pos = chatMsg.find(" : ", 0); + std::string sender_name = ((pos == std::string::npos) + ? "" + : chatMsg.substr(0, pos)); + + std::string mess = chatMsg.substr(pos+3); + // do something with chat + break; + } + case SMSG_WHISPER: + { + chatMsgLength = msg->readInt16() - 28; + std::string nick = msg->readString(24); + + if (chatMsgLength <= 0) + break; + + chatMsg = msg->readString(chatMsgLength); + Automation::getAutomationHandler()->commandHandler(chatMsg, nick); + + break; + } + case SMSG_WHISPER_RESPONSE: + { + int type = msg->readInt8(); + switch (type) + { + case 0x00: + break; + case 0x01: + //logger->log("Whisper could not be sent, user is offline."); + break; + case 0x02: + //logger->log("Whisper could not be sent, ignored by user."); + break; + default: + /*if (logger) + logger->log("Unkown Whisper Response.");*/ + break; + } + break; + } + case SMSG_PLAYER_CHAT: + case SMSG_GM_CHAT: + { + chatMsgLength = msg->readInt16() - 4; + + if (chatMsgLength <= 0) + { + break; + } + + chatMsg = msg->readString(chatMsgLength); + + if (msg->getId() == SMSG_PLAYER_CHAT) + { + + std::string::size_type pos = chatMsg.find(" : ", 0); + if (pos != std::string::npos) + { + chatMsg.erase(0, pos + 3); + } + //player_node->setSpeech(chatMsg, SPEECH_TIME); + } + else + { + //chatWindow->chatLog(chatMsg, BY_GM); + } + break; + } + + + } +} diff --git a/src/net/chathandler.cpp~ b/src/net/chathandler.cpp~ new file mode 100644 index 0000000..cb4c32c --- /dev/null +++ b/src/net/chathandler.cpp~ @@ -0,0 +1,147 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: chathandler.cpp 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#include "chathandler.h" + +#include <SDL_types.h> +#include <string> +#include <sstream> +#include <iostream> + +#include "messagein.h" +#include "protocol.h" +#include "messageout.h" +#include "../automation.h" +#include "../game.h" +#include "../utils/stringutils.h" +#include "../log.h" +#include "nethandler.h" + +ChatHandler::ChatHandler() +{ + static const Uint16 _messages[] = { + SMSG_BEING_CHAT, + SMSG_PLAYER_CHAT, + SMSG_WHISPER, + SMSG_WHISPER_RESPONSE, + SMSG_GM_CHAT, + 0 + }; + handledMessages = _messages; +} + +void ChatHandler::handleMessage(MessageIn *msg) +{ + //Being *being; + std::string chatMsg; + std::stringstream ss; + Sint16 chatMsgLength; + + switch (msg->getId()) + { + // Received speech from being + case SMSG_BEING_CHAT: + { + + chatMsgLength = msg->readInt16() - 8; + msg->readInt32(); + + if (chatMsgLength <= 0) + break; + + chatMsg = msg->readString(chatMsgLength); + + std::string::size_type pos = chatMsg.find(" : ", 0); + std::string sender_name = ((pos == std::string::npos) + ? "" + : chatMsg.substr(0, pos)); + + std::string mess = chatMsg.substr(pos+3); + // do something with chat + break; + } + case SMSG_WHISPER: + { + chatMsgLength = msg->readInt16() - 28; + std::string nick = msg->readString(24); + + if (chatMsgLength <= 0) + break; + + chatMsg = msg->readString(chatMsgLength); + Automation::getAutomationHandler()->commandHandler(chatMsg, nick); + + break; + } + case SMSG_WHISPER_RESPONSE: + { + int type = msg->readInt8(); + switch (type) + { + case 0x00: + break; + case 0x01: + //logger->log("Whisper could not be sent, user is offline."); + break; + case 0x02: + //logger->log("Whisper could not be sent, ignored by user."); + break; + default: + /*if (logger) + logger->log("Unkown Whisper Response.");*/ + break; + } + break; + } + case SMSG_PLAYER_CHAT: + case SMSG_GM_CHAT: + { + chatMsgLength = msg->readInt16() - 4; + + if (chatMsgLength <= 0) + { + break; + } + + chatMsg = msg->readString(chatMsgLength); + + if (msg->getId() == SMSG_PLAYER_CHAT) + { + + std::string::size_type pos = chatMsg.find(" : ", 0); + if (pos != std::string::npos) + { + chatMsg.erase(0, pos + 3); + } + //player_node->setSpeech(chatMsg, SPEECH_TIME); + } + else + { + //chatWindow->chatLog(chatMsg, BY_GM); + } + break; + } + + + } +}
\ No newline at end of file diff --git a/src/net/chathandler.h b/src/net/chathandler.h new file mode 100644 index 0000000..25874f0 --- /dev/null +++ b/src/net/chathandler.h @@ -0,0 +1,38 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: chathandler.h 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#ifndef _TMW_NET_CHATHANDLER_H +#define _TMW_NET_CHATHANDLER_H + +#include "messagehandler.h" +#include <string> + +class ChatHandler : public MessageHandler +{ + public: + ChatHandler(); + + void handleMessage(MessageIn *msg); +}; + +#endif diff --git a/src/net/loginhandler.cpp b/src/net/loginhandler.cpp new file mode 100644 index 0000000..b6f5b98 --- /dev/null +++ b/src/net/loginhandler.cpp @@ -0,0 +1,126 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: loginhandler.cpp 2184 2006-02-23 16:02:00Z der_doener $ + */ + +#include <stdio.h> + +#include "loginhandler.h" + +#include "messagein.h" +#include "network.h" +#include "protocol.h" + +#include "../logindata.h" +#include "../main.h" +#include "../serverinfo.h" + +extern SERVER_INFO **server_info; + +LoginHandler::LoginHandler() +{ + static const Uint16 _messages[] = { + 0x0063, + 0x0069, + 0x006a, + 0 + }; + handledMessages = _messages; +} + +void LoginHandler::handleMessage(MessageIn *msg) +{ + switch (msg->getId()) + { + case 0x0063: + // This is the update host. The bot doesn't need it. + msg->skip(2); + msg->skip(msg->getLength() - 4); + break; + + case 0x0069: + // Skip the length word + msg->skip(2); + + n_server = (msg->getLength() - 47) / 32; + server_info = (SERVER_INFO**)malloc(sizeof(SERVER_INFO*) * n_server); + + mLoginData->session_ID1 = msg->readInt32(); + mLoginData->account_ID = msg->readInt32(); + mLoginData->session_ID2 = msg->readInt32(); + msg->skip(30); // unknown + mLoginData->sex = msg->readInt8(); + + for (int i = 0; i < n_server; i++) + { + server_info[i] = new SERVER_INFO; + + server_info[i]->address = msg->readInt32(); + server_info[i]->port = msg->readInt16(); + server_info[i]->name = msg->readString(20); + + if (server_info[i]->name == "The Mana World") + world = i; + + server_info[i]->online_users = msg->readInt16(); + msg->skip(4); // unknown + + /*logger->log("Network: Server: %s (%s:%d)", + server_info[i]->name.c_str(), + iptostring(server_info[i]->address), + server_info[i]->port);*/ + } + state = CHAR_SERVER_STATE; + break; + + case 0x006a: + int loginError = msg->readInt8(); + //logger->log("Login::error code: %i", loginError); + switch (loginError) { + case 0: + errorMessage = "Unregistered ID"; + break; + case 1: + errorMessage = "Wrong password"; + break; + case 2: + errorMessage = "Account expired"; + break; + case 3: + errorMessage = "Rejected from server"; + break; + case 4: + errorMessage = "You have been blocked by the GM Team"; + break; + case 6: + errorMessage = "You have been banned for 5 minutes"; + break; + case 9: + errorMessage = "This account is already logged in"; + break; + default: + errorMessage = "Unknown error"; + break; + } + state = ERROR_STATE; + break; + } +} diff --git a/src/net/loginhandler.cpp~ b/src/net/loginhandler.cpp~ new file mode 100644 index 0000000..070127e --- /dev/null +++ b/src/net/loginhandler.cpp~ @@ -0,0 +1,119 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: loginhandler.cpp 2184 2006-02-23 16:02:00Z der_doener $ + */ + +#include "loginhandler.h" + +#include "messagein.h" +#include "network.h" +#include "protocol.h" + +#include "../log.h" +#include "../logindata.h" +#include "../main.h" +#include "../serverinfo.h" + +extern SERVER_INFO **server_info; + +LoginHandler::LoginHandler() +{ + static const Uint16 _messages[] = { + 0x0069, + 0x006a, + 0 + }; + handledMessages = _messages; +} + +void LoginHandler::handleMessage(MessageIn *msg) +{ + switch (msg->getId()) + { + case 0x0069: + // Skip the length word + msg->skip(2); + + n_server = (msg->getLength() - 47) / 32; + server_info = (SERVER_INFO**)malloc(sizeof(SERVER_INFO*) * n_server); + + mLoginData->session_ID1 = msg->readInt32(); + mLoginData->account_ID = msg->readInt32(); + mLoginData->session_ID2 = msg->readInt32(); + msg->skip(30); // unknown + mLoginData->sex = msg->readInt8(); + + for (int i = 0; i < n_server; i++) + { + server_info[i] = new SERVER_INFO; + + server_info[i]->address = msg->readInt32(); + server_info[i]->port = msg->readInt16(); + server_info[i]->name = msg->readString(20); + + if (server_info[i]->name == "The Mana World") + world = i; + + server_info[i]->online_users = msg->readInt32(); + msg->skip(2); // unknown + + /*logger->log("Network: Server: %s (%s:%d)", + server_info[i]->name.c_str(), + iptostring(server_info[i]->address), + server_info[i]->port);*/ + } + state = CHAR_SERVER_STATE; + break; + + case 0x006a: + int loginError = msg->readInt8(); + //logger->log("Login::error code: %i", loginError); + + switch (loginError) { + case 0: + errorMessage = "Unregistered ID"; + break; + case 1: + errorMessage = "Wrong password"; + break; + case 2: + errorMessage = "Account expired"; + break; + case 3: + errorMessage = "Rejected from server"; + break; + case 4: + errorMessage = "You have been blocked by the GM Team"; + break; + case 6: + errorMessage = "You have been banned for 5 minutes"; + break; + case 9: + errorMessage = "This account is already logged in"; + break; + default: + errorMessage = "Unknown error"; + break; + } + state = ERROR_STATE; + break; + } +} diff --git a/src/net/loginhandler.h b/src/net/loginhandler.h new file mode 100644 index 0000000..7a8feef --- /dev/null +++ b/src/net/loginhandler.h @@ -0,0 +1,45 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: loginhandler.h 2137 2006-02-04 16:54:35Z der_doener $ + */ + +#ifndef _TMW_NET_LOGINHANDLER_H +#define _TMW_NET_LOGINHANDLER_H + +#include "messagehandler.h" +#include "../serverinfo.h" + +struct LoginData; + +class LoginHandler : public MessageHandler +{ + public: + LoginHandler(); + + void handleMessage(MessageIn *msg); + + void setLoginData(LoginData *loginData) { mLoginData = loginData; }; + + protected: + LoginData *mLoginData; +}; + +#endif diff --git a/src/net/maploginhandler.cpp b/src/net/maploginhandler.cpp new file mode 100644 index 0000000..1b0c4e7 --- /dev/null +++ b/src/net/maploginhandler.cpp @@ -0,0 +1,62 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: maploginhandler.cpp 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#include "maploginhandler.h" + +#include "messagein.h" +#include "protocol.h" + +#include "../main.h" + +MapLoginHandler::MapLoginHandler() +{ + static const Uint16 _messages[] = { + SMSG_LOGIN_SUCCESS, + 0x0081, + 0 + }; + handledMessages = _messages; +} + +void MapLoginHandler::handleMessage(MessageIn *msg) +{ + unsigned char direction; + + switch (msg->getId()) + { + case SMSG_LOGIN_SUCCESS: + msg->readInt32(); // server tick + unsigned short startX, startY; + msg->readCoordinates(startX, startY, direction); + msg->skip(2); // unknown + /*logger->log("Protocol: Player start position: (%d, %d), Direction: %d", + startX, startX, direction);*/ + state = GAME_STATE; + break; + + case 0x0081: + /*logger->log("Warning: Map server D/C");*/ + state = ERROR_STATE; + break; + } +} diff --git a/src/net/maploginhandler.cpp~ b/src/net/maploginhandler.cpp~ new file mode 100644 index 0000000..1b0c4e7 --- /dev/null +++ b/src/net/maploginhandler.cpp~ @@ -0,0 +1,62 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: maploginhandler.cpp 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#include "maploginhandler.h" + +#include "messagein.h" +#include "protocol.h" + +#include "../main.h" + +MapLoginHandler::MapLoginHandler() +{ + static const Uint16 _messages[] = { + SMSG_LOGIN_SUCCESS, + 0x0081, + 0 + }; + handledMessages = _messages; +} + +void MapLoginHandler::handleMessage(MessageIn *msg) +{ + unsigned char direction; + + switch (msg->getId()) + { + case SMSG_LOGIN_SUCCESS: + msg->readInt32(); // server tick + unsigned short startX, startY; + msg->readCoordinates(startX, startY, direction); + msg->skip(2); // unknown + /*logger->log("Protocol: Player start position: (%d, %d), Direction: %d", + startX, startX, direction);*/ + state = GAME_STATE; + break; + + case 0x0081: + /*logger->log("Warning: Map server D/C");*/ + state = ERROR_STATE; + break; + } +} diff --git a/src/net/maploginhandler.h b/src/net/maploginhandler.h new file mode 100644 index 0000000..6ff6bc0 --- /dev/null +++ b/src/net/maploginhandler.h @@ -0,0 +1,37 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: maploginhandler.h 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#ifndef _TMW_NET_MAPLOGINHANDLER_H +#define _TMW_NET_MAPLOGINHANDLER_H + +#include "messagehandler.h" + +class MapLoginHandler : public MessageHandler +{ + public: + MapLoginHandler(); + + void handleMessage(MessageIn *msg); +}; + +#endif diff --git a/src/net/messagehandler.cpp b/src/net/messagehandler.cpp new file mode 100644 index 0000000..370a01a --- /dev/null +++ b/src/net/messagehandler.cpp @@ -0,0 +1,45 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: messagehandler.cpp 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#include "messagehandler.h" + +#include <cassert> + +#include "network.h" + +MessageHandler::MessageHandler(): + mNetwork(0) +{ +} + +MessageHandler::~MessageHandler() +{ + if (mNetwork) + mNetwork->unregisterHandler(this); +} + +void MessageHandler::setNetwork(Network *network) +{ + assert(!(network && mNetwork)); + mNetwork = network; +} diff --git a/src/net/messagehandler.h b/src/net/messagehandler.h new file mode 100644 index 0000000..90ffa48 --- /dev/null +++ b/src/net/messagehandler.h @@ -0,0 +1,48 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: messagehandler.h 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#ifndef _TMW_NET_MESSAGEHANDLER_H +#define _TMW_NET_MESSAGEHANDLER_H + +#include <SDL_types.h> + +class MessageIn; +class Network; + +class MessageHandler +{ + public: + const Uint16 *handledMessages; + + MessageHandler(); + virtual ~MessageHandler(); + + virtual void handleMessage(MessageIn *msg) =0; + + void setNetwork(Network *network); + + protected: + Network *mNetwork; +}; + +#endif diff --git a/src/net/messagein.cpp b/src/net/messagein.cpp new file mode 100644 index 0000000..192e857 --- /dev/null +++ b/src/net/messagein.cpp @@ -0,0 +1,198 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: messagein.cpp 2158 2006-02-07 10:37:54Z der_doener $ + */ + +#include "messagein.h" + +#include <cassert> +#include <SDL.h> +#include <SDL_endian.h> + +#define MAKEWORD(low,high) \ + ((unsigned short)(((unsigned char)(low)) | \ + ((unsigned short)((unsigned char)(high))) << 8)) + + +MessageIn::MessageIn(const char *data, unsigned int length): + mData(data), + mLength(length), + mPos(0) +{ + // Read the message ID + mId = readInt16(); +} + +Sint8 +MessageIn::readInt8() +{ + assert(mPos < mLength); + return mData[mPos++]; +} + +Sint16 +MessageIn::readInt16() +{ + assert(mPos + 2 <= mLength); + mPos += 2; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap16(*(Sint16*)(mData + (mPos - 2))); +#else + return (*(Sint16*)(mData + (mPos - 2))); +#endif +} + +Sint32 +MessageIn::readInt32() +{ + assert(mPos + 4 <= mLength); + mPos += 4; +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap32(*(Sint32*)(mData + (mPos - 4))); +#else + return (*(Sint32*)(mData + (mPos - 4))); +#endif +} + +void +MessageIn::readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction) +{ + assert(mPos + 3 <= mLength); + + const char *data = mData + mPos; + Sint16 temp; + + temp = MAKEWORD(data[1] & 0x00c0, data[0] & 0x00ff); + x = temp >> 6; + temp = MAKEWORD(data[2] & 0x00f0, data[1] & 0x003f); + y = temp >> 4; + + direction = data[2] & 0x000f; + + // Translate from eAthena format + switch (direction) + { + case 0: + direction = 1; + break; + case 1: + direction = 3; + break; + case 2: + direction = 2; + break; + case 3: + direction = 6; + break; + case 4: + direction = 4; + break; + case 5: + direction = 12; + break; + case 6: + direction = 8; + break; + case 7: + direction = 9; + break; + default: + // OOPSIE! Impossible or unknown + direction = 0; + } + + mPos += 3; +} + +void +MessageIn::readCoordinatePair(Uint16 &srcX, Uint16 &srcY, + Uint16 &dstX, Uint16 &dstY) +{ + assert(mPos + 5 <= mLength); + + const char *data = mData + mPos; + Sint16 temp; + + temp = MAKEWORD(data[3], data[2] & 0x000f); + dstX = temp >> 2; + + dstY = MAKEWORD(data[4], data[3] & 0x0003); + + temp = MAKEWORD(data[1], data[0]); + srcX = temp >> 6; + + temp = MAKEWORD(data[2], data[1] & 0x003f); + srcY = temp >> 4; + + mPos += 5; +} + +void +MessageIn::skip(unsigned int length) +{ + assert(mPos + length <= mLength); + mPos += length; +} + +std::string +MessageIn::readString(int length) +{ + int stringLength = 0; + + // Get string length + if (length < 0) { + stringLength = readInt16(); + } else { + stringLength = length; + } + + // Make sure there is enough data available + assert(mPos + length <= mLength); + + // Read the string + char *tmpString = new char[stringLength + 1]; + memcpy(tmpString, (void*)&mData[mPos], stringLength); + tmpString[stringLength] = 0; + mPos += stringLength; + + std::string read = tmpString; + delete[] tmpString; + + return read; +} + +Sint8& operator<<(Sint8 &lhs, MessageIn &msg) +{ + lhs = msg.readInt8(); + return lhs; +} + +Sint16& operator<<(Sint16 &lhs, MessageIn &msg) +{ + lhs = msg.readInt16(); + return lhs; +} + +Sint32& operator<<(Sint32 &lhs, MessageIn &msg) +{ + lhs = msg.readInt32(); + return lhs; +} diff --git a/src/net/messagein.h b/src/net/messagein.h new file mode 100644 index 0000000..0a6b8b8 --- /dev/null +++ b/src/net/messagein.h @@ -0,0 +1,97 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: messagein.h 1879 2005-10-16 21:18:11Z der_doener $ + */ + +#ifndef _TMW_MESSAGEIN_ +#define _TMW_MESSAGEIN_ + +#include <string> +#include <SDL_types.h> + +/** + * Used for parsing an incoming message. + */ +class MessageIn +{ + friend Sint8& operator<<(Sint8 &lhs, MessageIn &msg); + friend Sint16& operator<<(Sint16 &lhs, MessageIn &msg); + friend Sint32& operator<<(Sint32 &lhs, MessageIn &msg); + + public: + /** + * Constructor. + */ + MessageIn(const char *data, unsigned int length); + + /** + * Returns the message ID. + */ + short + getId() { return mId; } + + /** + * Returns the message length. + */ + unsigned int + getLength() { return mLength; } + + Sint8 readInt8(); /**< Reads a byte. */ + Sint16 readInt16(); /**< Reads a short. */ + Sint32 readInt32(); /**< Reads a long. */ + + /** + * Reads a special 3 byte block used by eAthena, containing x and y + * coordinates and direction. + */ + void + readCoordinates(Uint16 &x, Uint16 &y, Uint8 &direction); + + /** + * Reads a special 5 byte block used by eAthena, containing a source + * and destination coordinate pair. + */ + void + readCoordinatePair(Uint16 &srcX, Uint16 &srcY, + Uint16 &dstX, Uint16 &dstY); + + /** + * Skips a given number of bytes. + */ + void + skip(unsigned int length); + + /** + * Reads a string. If a length is not given (-1), it is assumed + * that the length of the string is stored in a short at the + * start of the string. + */ + std::string + readString(int length = -1); + + private: + const char* mData; /**< The message data. */ + unsigned int mLength; /**< The length of the data. */ + unsigned int mPos; /**< The position in the data. */ + short mId; /**< The message ID. */ +}; + +#endif diff --git a/src/net/messageout.cpp b/src/net/messageout.cpp new file mode 100644 index 0000000..b6a826c --- /dev/null +++ b/src/net/messageout.cpp @@ -0,0 +1,116 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: messageout.cpp 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#include "messageout.h" + +#include <string> +#include <SDL.h> +#include <SDL_endian.h> + +#include "network.h" +#include "packet.h" + +MessageOut::MessageOut(Network *network): + mNetwork(network), + mData(0), + mDataSize(0), + mPos(0) +{ + mData = mNetwork->mOutBuffer + mNetwork->mOutSize; +} + +void MessageOut::writeInt8(Sint8 value) +{ + mData[mPos] = value; + mPos += sizeof(Sint8); + mNetwork->mOutSize+= sizeof(Sint8); +} + +void MessageOut::writeInt16(Sint16 value) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + (*(Sint16 *)(mData + mPos)) = SDL_Swap16(value); +#else + (*(Sint16 *)(mData + mPos)) = value; +#endif + mPos += sizeof(Sint16); + mNetwork->mOutSize += sizeof(Sint16); +} + +void MessageOut::writeInt32(Sint32 value) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + (*(Sint32 *)(mData + mPos)) = SDL_Swap32(value); +#else + (*(Sint32 *)(mData + mPos)) = value; +#endif + mPos += sizeof(Sint32); + mNetwork->mOutSize += sizeof(Sint32); +} + +void MessageOut::writeString(const std::string &string, int length) +{ + std::string toWrite = string; + + if (length < 0) + { + // Write the length at the start if not fixed + writeInt16(string.length()); + } + else + { + // Make sure the length of the string is no longer than specified + toWrite = string.substr(0, length); + } + + // Write the actual string + memcpy(&mData[mPos], (void*)toWrite.c_str(), toWrite.length()); + mPos += toWrite.length(); + mNetwork->mOutSize += toWrite.length(); + + // Pad remaining space with zeros + if (length > (int)toWrite.length()) + { + memset(&mData[mPos], '\0', length - toWrite.length()); + mPos += length - toWrite.length(); + mNetwork->mOutSize += length - toWrite.length(); + } +} + +MessageOut& operator<<(MessageOut &msg, const Sint8 &rhs) +{ + msg.writeInt8(rhs); + return msg; +} + +MessageOut& operator<<(MessageOut &msg, const Sint16 &rhs) +{ + msg.writeInt16(rhs); + return msg; +} + +MessageOut& operator<<(MessageOut &msg, const Sint32 &rhs) +{ + msg.writeInt32(rhs); + return msg; +} diff --git a/src/net/messageout.h b/src/net/messageout.h new file mode 100644 index 0000000..33deb1b --- /dev/null +++ b/src/net/messageout.h @@ -0,0 +1,65 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: messageout.h 2112 2006-01-22 13:31:13Z der_doener $ + */ + +#ifndef _TMW_MESSAGEOUT_ +#define _TMW_MESSAGEOUT_ + +#include <iosfwd> +#include <SDL_types.h> + +class Network; + +/** + * Used for building an outgoing message. + */ +class MessageOut +{ + friend MessageOut& operator<<(MessageOut &msg, const Sint8 &rhs); + friend MessageOut& operator<<(MessageOut &msg, const Sint16 &rhs); + friend MessageOut& operator<<(MessageOut &msg, const Sint32 &rhs); + + public: + /** + * Constructor. + */ + MessageOut(Network *network); + + void writeInt8(Sint8 value); /**< Writes a byte. */ + void writeInt16(Sint16 value); /**< Writes a short. */ + void writeInt32(Sint32 value); /**< Writes a long. */ + + /** + * Writes a string. If a fixed length is not given (-1), it is stored + * as a short at the start of the string. + */ + void writeString(const std::string &string, int length = -1); + + private: + Network *mNetwork; + + char *mData; /**< Data building up. */ + unsigned int mDataSize; /**< Size of data. */ + unsigned int mPos; /**< Position in the data. */ +}; + +#endif diff --git a/src/net/nethandler.cpp b/src/net/nethandler.cpp new file mode 100644 index 0000000..8021e55 --- /dev/null +++ b/src/net/nethandler.cpp @@ -0,0 +1,182 @@ +#include "nethandler.h" +#include "network.h" +#include "protocol.h" +#include "messageout.h" + +#include "loginhandler.h" +#include "chathandler.h" +#include "charserverhandler.h" +#include "maploginhandler.h" + +#include "../main.h" +#include "../game.h" + +static NetHandler *NetInstance = NULL; +static Network *mNetwork = NULL; +MessageHandler *mChatHandler = NULL; + +LoginHandler loginHandler; +CharServerHandler charServerHandler; +MapLoginHandler mapLoginHandler; + +NetHandler::NetHandler() +{ + NetInstance = this; +} + +NetHandler::~NetHandler() +{ + delete mNetwork; + + if (mChatHandler != NULL) + delete mChatHandler; + + delete NetInstance; +} + +void NetHandler::clean_up() +{ + delete mNetwork; + + if (mChatHandler != NULL) // fix a crash caused by map server D/C + delete mChatHandler; + + mNetwork = new Network(); +} + +NetHandler *NetHandler::getNetInstance() +{ + return NetInstance; +} + +Network *NetHandler::getNetwork() +{ + if (mNetwork == NULL) + mNetwork = new Network(); + + return mNetwork; +} + +void NetHandler::loadHandlers() +{ + mChatHandler = new ChatHandler(); + mNetwork->registerHandler(mChatHandler); +} + +// All code related to login, from main.cpp + +void NetHandler::accountLogin(LoginData *loginData) +{ + /* + logger->log("Trying to connect to account server..."); + logger->log("Username is %s", loginData->username.c_str());*/ + mNetwork->connect(loginData->hostname, loginData->port); + mNetwork->registerHandler(&loginHandler); + loginHandler.setLoginData(loginData); + + // Send login infos + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0064); + outMsg.writeInt32(9); // client version + outMsg.writeString(loginData->username, 24); + outMsg.writeString(loginData->password, 24); + outMsg.writeInt8(1 | 2); // flags +} + +void NetHandler::charLogin(LoginData *loginData) +{ + /*logger->log("Trying to connect to char server..."); + + logger->log("Server: %s (%s:%d)", + server_info[0]->name.c_str(), + loginData->hostname.c_str(), + loginData->port);*/ + + mNetwork->connect(loginData->hostname, loginData->port); + mNetwork->registerHandler(&charServerHandler); + charServerHandler.setLoginData(loginData); + + // Send login infos + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0065); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + outMsg.writeInt16(1); // this should match MIN_CLIENT_VERSION in tmwa/src/char/char.hpp + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + mNetwork->skip(4); +} + +void NetHandler::mapLogin(LoginData *loginData) +{ + MessageOut outMsg(mNetwork); + + /*logger->log("Trying to connect to map server..."); + logger->log("Map: %s", map_path.c_str());*/ + + mNetwork->connect(loginData->hostname, loginData->port); + mNetwork->registerHandler(&mapLoginHandler); + + // Send login infos + outMsg.writeInt16(0x0072); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(charID[main_charno]); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + mNetwork->skip(4); +} + +// add a few of the packets that need to be sent. +void NetHandler::attemptCharSelect() +{ + /*logger->log("CharServer: Character Select: %s", + char_name.c_str());*/ + // Request character selection + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0066); + outMsg.writeInt8(main_charno); +} + +void NetHandler::mapLoaded() +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_MAP_LOADED); +} + +void NetHandler::privateMessage(std::string name, std::string msg) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CHAT_WHISPER); + outMsg.writeInt16(static_cast<short>(msg.length() + 28)); + outMsg.writeString(name, 24); + outMsg.writeString(msg, static_cast<int>(msg.length())); +} + +void NetHandler::publicMessage(std::string msg) +{ + std::string mes = std::string("guild") + " : " + msg; + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CHAT_MESSAGE); + outMsg.writeInt16(static_cast<short>(mes.length() + 4 + 1)); + outMsg.writeString(mes, static_cast<int>(mes.length() + 1)); +} + +void NetHandler::sit() +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_CHANGE_ACT); + outMsg.writeInt32(0); + outMsg.writeInt8(2); +} + +void NetHandler::ping(int tick) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CLIENT_PING); + outMsg.writeInt32(tick); +} diff --git a/src/net/nethandler.cpp~ b/src/net/nethandler.cpp~ new file mode 100644 index 0000000..d6f031e --- /dev/null +++ b/src/net/nethandler.cpp~ @@ -0,0 +1,183 @@ +#include "nethandler.h" +#include "network.h" +#include "protocol.h" +#include "messageout.h" + +#include "loginhandler.h" +#include "chathandler.h" +#include "charserverhandler.h" +#include "maploginhandler.h" + +#include "../log.h" +#include "../main.h" +#include "../game.h" + +static NetHandler *NetInstance = NULL; +static Network *mNetwork = NULL; +MessageHandler *mChatHandler = NULL; + +LoginHandler loginHandler; +CharServerHandler charServerHandler; +MapLoginHandler mapLoginHandler; + +NetHandler::NetHandler() +{ + NetInstance = this; +} + +NetHandler::~NetHandler() +{ + delete mNetwork; + + if (mChatHandler != NULL) + delete mChatHandler; + + delete NetInstance; +} + +void NetHandler::clean_up() +{ + delete mNetwork; + + if (mChatHandler != NULL) // fix a crash caused by map server D/C + delete mChatHandler; + + mNetwork = new Network(); +} + +NetHandler *NetHandler::getNetInstance() +{ + return NetInstance; +} + +Network *NetHandler::getNetwork() +{ + if (mNetwork == NULL) + mNetwork = new Network(); + + return mNetwork; +} + +void NetHandler::loadHandlers() +{ + mChatHandler = new ChatHandler(); + mNetwork->registerHandler(mChatHandler); +} + +// All code related to login, from main.cpp + +void NetHandler::accountLogin(LoginData *loginData) +{ + /* + logger->log("Trying to connect to account server..."); + logger->log("Username is %s", loginData->username.c_str());*/ + mNetwork->connect(loginData->hostname, loginData->port); + mNetwork->registerHandler(&loginHandler); + loginHandler.setLoginData(loginData); + + // Send login infos + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0064); + outMsg.writeInt32(0); // client version + outMsg.writeString(loginData->username, 24); + outMsg.writeString(loginData->password, 24); + outMsg.writeInt8(0); // unknown +} + +void NetHandler::charLogin(LoginData *loginData) +{ + /*logger->log("Trying to connect to char server..."); + + logger->log("Server: %s (%s:%d)", + server_info[0]->name.c_str(), + loginData->hostname.c_str(), + loginData->port);*/ + + mNetwork->connect(loginData->hostname, loginData->port); + mNetwork->registerHandler(&charServerHandler); + charServerHandler.setLoginData(loginData); + + // Send login infos + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0065); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + outMsg.writeInt16(0); // unknown + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + mNetwork->skip(4); +} + +void NetHandler::mapLogin(LoginData *loginData) +{ + MessageOut outMsg(mNetwork); + + /*logger->log("Trying to connect to map server..."); + logger->log("Map: %s", map_path.c_str());*/ + + mNetwork->connect(loginData->hostname, loginData->port); + mNetwork->registerHandler(&mapLoginHandler); + + // Send login infos + outMsg.writeInt16(0x0072); + outMsg.writeInt32(loginData->account_ID); + outMsg.writeInt32(charID[main_charno]); + outMsg.writeInt32(loginData->session_ID1); + outMsg.writeInt32(loginData->session_ID2); + outMsg.writeInt8(loginData->sex); + + // We get 4 useless bytes before the real answer comes in + mNetwork->skip(4); +} + +// add a few of the packets that need to be sent. +void NetHandler::attemptCharSelect() +{ + /*logger->log("CharServer: Character Select: %s", + char_name.c_str());*/ + // Request character selection + MessageOut outMsg(mNetwork); + outMsg.writeInt16(0x0066); + outMsg.writeInt8(main_charno); +} + +void NetHandler::mapLoaded() +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_MAP_LOADED); +} + +void NetHandler::privateMessage(std::string name, std::string msg) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CHAT_WHISPER); + outMsg.writeInt16(static_cast<short>(msg.length() + 28)); + outMsg.writeString(name, 24); + outMsg.writeString(msg, static_cast<int>(msg.length())); +} + +void NetHandler::publicMessage(std::string msg) +{ + std::string mes = std::string("guild") + " : " + msg; + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CHAT_MESSAGE); + outMsg.writeInt16(static_cast<short>(mes.length() + 4 + 1)); + outMsg.writeString(mes, static_cast<int>(mes.length() + 1)); +} + +void NetHandler::sit() +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_PLAYER_CHANGE_ACT); + outMsg.writeInt32(0); + outMsg.writeInt8(2); +} + +void NetHandler::ping(int tick) +{ + MessageOut outMsg(mNetwork); + outMsg.writeInt16(CMSG_CLIENT_PING); + outMsg.writeInt32(tick); +}
\ No newline at end of file diff --git a/src/net/nethandler.h b/src/net/nethandler.h new file mode 100644 index 0000000..41f523c --- /dev/null +++ b/src/net/nethandler.h @@ -0,0 +1,33 @@ +#include "network.h" + +#include "loginhandler.h" +#include "../logindata.h" + +class NetHandler +{ + + +public: + + NetHandler(); + ~NetHandler(); + + static NetHandler *getNetInstance(); + + void loadHandlers(); + Network *getNetwork(); + void clean_up(); // for restart + + void accountLogin(LoginData *loginData); + void charLogin(LoginData *loginData); + void mapLogin(LoginData *loginData); + void attemptCharSelect(); + + void mapLoaded(); + void privateMessage(std::string name, std::string msg); + void publicMessage(std::string msg); + void ping(int tick); + void sit(); +private: + +}; diff --git a/src/net/network.cpp b/src/net/network.cpp new file mode 100644 index 0000000..e4c6e65 --- /dev/null +++ b/src/net/network.cpp @@ -0,0 +1,442 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: network.cpp 2187 2006-02-24 20:15:19Z der_doener $ + */ + +#include "network.h" + +#include "messagehandler.h" +#include "messagein.h" + +#include "../main.h" + +/** Warning: buffers and other variables are shared, + so there can be only one connection active at a time */ + +short packet_lengths[] = { + 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// #0x0040 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, -1, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2, + 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6, +// #0x0080 + 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, + 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6, + 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6, + 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3, +// #0x00C0 + 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27, + 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1, + 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2, + 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10, +// #0x0100 + 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1, + 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16, + 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1, + 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26, +// #0x0140 + 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6, + 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42, + -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182, + 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1, +// #0x0180 + 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6, + 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6, + 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4, + 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3, +// #0x01C0 + 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28, + 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, + 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, + -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, +// #0x200 + 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const unsigned int BUFFER_SIZE = 65536; + +int networkThread(void *data) +{ + Network *network = static_cast<Network*>(data); + + if (!network->realConnect()) + return -1; + + network->receive(); + + return 0; +} + +Network::Network(): + mAddress(), mPort(0), + mInBuffer(new char[BUFFER_SIZE]), + mOutBuffer(new char[BUFFER_SIZE]), + mInSize(0), mOutSize(0), + mToSkip(0), + mState(IDLE), + mWorkerThread(0) +{ + mMutex = SDL_CreateMutex(); +} + +Network::~Network() +{ + clearHandlers(); + + if (mState != IDLE && mState != ERROR_BROKE) + disconnect(); + + SDL_DestroyMutex(mMutex); + + delete mInBuffer; + delete mOutBuffer; +} + +bool Network::connect(const std::string &address, short port) +{ + if (mState != IDLE && mState != ERROR_BROKE) + { + //logger->log("Tried to connect an already connected socket!"); + return false; + } + + if (address.empty()) + { + //logger->log("Empty address given to Network::connect()!"); + mState = ERROR_BROKE; + return false; + } + + //logger->log("Network::Connecting to %s:%i", address.c_str(), port); + + mAddress = address; + mPort = port; + + // Reset to sane values + mOutSize = 0; + mInSize = 0; + mToSkip = 0; + + mState = CONNECTING; + mWorkerThread = SDL_CreateThread(networkThread, this); + if (!mWorkerThread) + { + //logger->log("Unable to create network worker thread"); + mState = ERROR_BROKE; + return false; + } + + return true; +} + +void Network::disconnect() +{ + if (mState != CONNECTED && mState != CONNECTING) + return; + + mState = IDLE; + + if (mWorkerThread) + { + SDL_WaitThread(mWorkerThread, NULL); + mWorkerThread = NULL; + } + SDLNet_TCP_Close(mSocket); +} + +void Network::registerHandler(MessageHandler *handler) +{ + const Uint16 *i = handler->handledMessages; + + while(*i) + { + mMessageHandlers[*i] = handler; + i++; + } + + handler->setNetwork(this); +} + +void Network::unregisterHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; i++) + { + mMessageHandlers.erase(*i); + } + + handler->setNetwork(0); +} + +void Network::clearHandlers() +{ + MessageHandlerIterator i; + for (i = mMessageHandlers.begin(); i != mMessageHandlers.end(); i++) + { + i->second->setNetwork(0); + } + mMessageHandlers.clear(); +} + +void Network::dispatchMessages() +{ + while (messageReady()) + { + MessageIn msg = getNextMessage(); + + MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); + + if (iter != mMessageHandlers.end()) + iter->second->handleMessage(&msg); + /*else + logger->log("Unhandled packet: %x", msg.getId());*/ + + skip(msg.getLength()); + } +} + +void Network::flush() +{ + if (!mOutSize || mState != CONNECTED) + return; + + int ret; + + + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); + if (ret < (int)mOutSize) + { + //logger->log("Error in SDLNet_TCP_Send(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + } + mOutSize = 0; + SDL_mutexV(mMutex); +} + +void Network::skip(int len) +{ + SDL_mutexP(mMutex); + mToSkip += len; + if (!mInSize) + { + SDL_mutexV(mMutex); + return; + } + + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + SDL_mutexV(mMutex); +} + +bool Network::messageReady() +{ + int len = -1; + + SDL_mutexP(mMutex); + if (mInSize >= 2) + { + len = packet_lengths[readWord(0)]; + + if (len == -1 && mInSize > 4) + len = readWord(2); + + } + + bool ret = (mInSize >= static_cast<unsigned int>(len)); + SDL_mutexV(mMutex); + + return ret; +} + +MessageIn Network::getNextMessage() +{ + while (!messageReady()) + { + if (mState == ERROR_BROKE) + break; + } + + SDL_mutexP(mMutex); + int msgId = readWord(0); + int len = packet_lengths[msgId]; + + if (len == -1) + len = readWord(2); + +#ifdef DEBUG + printf("Received packet 0x%x of length %d\n", msgId, length); +#endif + + MessageIn msg(mInBuffer, len); + SDL_mutexV(mMutex); + + return msg; +} + +bool Network::realConnect() +{ + IPaddress ipAddress; + + if (SDLNet_ResolveHost(&ipAddress, mAddress.c_str(), mPort) == -1) + { + //logger->log("Error in SDLNet_ResolveHost(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + return false; + } + + mState = CONNECTING; + + mSocket = SDLNet_TCP_Open(&ipAddress); + if (!mSocket) + { + //logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + return false; + } + + /*logger->log("Network::Started session with %s:%i", + iptostring(ipAddress.host), ipAddress.port);*/ + + mState = CONNECTED; + + return true; +} + +void Network::receive() +{ + SDLNet_SocketSet set; + + if (!(set = SDLNet_AllocSocketSet(1))) + { + //logger->log("Error in SDLNet_AllocSocketSet(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + return; + } + + if (SDLNet_TCP_AddSocket(set, mSocket) == -1) + { + //logger->log("Error in SDLNet_AddSocket(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + } + + while (mState == CONNECTED) + { + // TODO Try to get this to block all the time while still being able + // to escape the loop + int numReady = SDLNet_CheckSockets(set, ((Uint32)500)); + int ret; + switch (numReady) + { + case -1: + // logger->log("Error: SDLNet_CheckSockets"); + // FALLTHROUGH + case 0: + break; + + case 1: + // Receive data from the socket + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize); + + if (!ret) + { + // We got disconnected + mState = ERROR_BROKE; //IDLE - changed to error to force a restart. + //logger->log("Disconnected."); + //state = LOGIN_STATE; + } + else if (ret < 0) + { + //logger->log("Error in SDLNet_TCP_Recv(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + } + else { + mInSize += ret; + if (mToSkip) + { + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + } + } + SDL_mutexV(mMutex); + break; + + default: + // more than one socket is ready.. + // this should not happen since we only listen once socket. + //logger->log("Error in SDLNet_TCP_Recv(), %d sockets are ready : %s", numReady, SDLNet_GetError()); + mState = ERROR_BROKE; + break; + } + } + + if (SDLNet_TCP_DelSocket(set, mSocket) == -1) + { + //logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); + } + + SDLNet_FreeSocketSet(set); +} + +char *iptostring(int address) +{ + static char asciiIP[16]; + + sprintf(asciiIP, "%i.%i.%i.%i", + (unsigned char)(address), + (unsigned char)(address >> 8), + (unsigned char)(address >> 16), + (unsigned char)(address >> 24)); + + return asciiIP; +} + +Uint16 Network::readWord(int pos) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap16((*(Uint16*)(mInBuffer+(pos)))); +#else + return (*(Uint16*)(mInBuffer+(pos))); +#endif +} diff --git a/src/net/network.cpp~ b/src/net/network.cpp~ new file mode 100644 index 0000000..fb531de --- /dev/null +++ b/src/net/network.cpp~ @@ -0,0 +1,443 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: network.cpp 2187 2006-02-24 20:15:19Z der_doener $ + */ + +#include "network.h" + +#include "messagehandler.h" +#include "messagein.h" + +#include "../main.h" +#include "../log.h" + +/** Warning: buffers and other variables are shared, + so there can be only one connection active at a time */ + +short packet_lengths[] = { + 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// #0x0040 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 55, 17, 3, 37, 46, -1, 23, -1, 3,108, 3, 2, + 3, 28, 19, 11, 3, -1, 9, 5, 54, 53, 58, 60, 41, 2, 6, 6, +// #0x0080 + 7, 3, 2, 2, 2, 5, 16, 12, 10, 7, 29, 23, -1, -1, -1, 0, + 7, 22, 28, 2, 6, 30, -1, -1, 3, -1, -1, 5, 9, 17, 17, 6, + 23, 6, 6, -1, -1, -1, -1, 8, 7, 6, 7, 4, 7, 0, -1, 6, + 8, 8, 3, 3, -1, 6, 6, -1, 7, 6, 2, 5, 6, 44, 5, 3, +// #0x00C0 + 7, 2, 6, 8, 6, 7, -1, -1, -1, -1, 3, 3, 6, 6, 2, 27, + 3, 4, 4, 2, -1, -1, 3, -1, 6, 14, 3, -1, 28, 29, -1, -1, + 30, 30, 26, 2, 6, 26, 3, 3, 8, 19, 5, 2, 3, 2, 2, 2, + 3, 2, 6, 8, 21, 8, 8, 2, 2, 26, 3, -1, 6, 27, 30, 10, +// #0x0100 + 2, 6, 6, 30, 79, 31, 10, 10, -1, -1, 4, 6, 6, 2, 11, -1, + 10, 39, 4, 10, 31, 35, 10, 18, 2, 13, 15, 20, 68, 2, 3, 16, + 6, 14, -1, -1, 21, 8, 8, 8, 8, 8, 2, 2, 3, 4, 2, -1, + 6, 86, 6, -1, -1, 7, -1, 6, 3, 16, 4, 4, 4, 6, 24, 26, +// #0x0140 + 22, 14, 6, 10, 23, 19, 6, 39, 8, 9, 6, 27, -1, 2, 6, 6, + 110, 6, -1, -1, -1, -1, -1, 6, -1, 54, 66, 54, 90, 42, 6, 42, + -1, -1, -1, -1, -1, 30, -1, 3, 14, 3, 30, 10, 43, 14,186,182, + 14, 30, 10, 3, -1, 6,106, -1, 4, 5, 4, -1, 6, 7, -1, -1, +// #0x0180 + 6, 3,106, 10, 10, 34, 0, 6, 8, 4, 4, 4, 29, -1, 10, 6, + 90, 86, 24, 6, 30,102, 9, 4, 8, 4, 14, 10, 4, 6, 2, 6, + 3, 3, 35, 5, 11, 26, -1, 4, 4, 6, 10, 12, 6, -1, 4, 4, + 11, 7, -1, 67, 12, 18,114, 6, 3, 6, 26, 26, 26, 26, 2, 3, +// #0x01C0 + 2, 14, 10, -1, 22, 22, 4, 2, 13, 97, 0, 9, 9, 29, 6, 28, + 8, 14, 10, 35, 6, 8, 4, 11, 54, 53, 60, 2, -1, 47, 33, 6, + 30, 8, 34, 14, 2, 6, 26, 2, 28, 81, 6, 10, 26, 2, -1, -1, + -1, -1, 20, 10, 32, 9, 34, 14, 2, 6, 48, 56, -1, 4, 5, 10, +// #0x200 + 26, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const unsigned int BUFFER_SIZE = 65536; + +int networkThread(void *data) +{ + Network *network = static_cast<Network*>(data); + + if (!network->realConnect()) + return -1; + + network->receive(); + + return 0; +} + +Network::Network(): + mAddress(), mPort(0), + mInBuffer(new char[BUFFER_SIZE]), + mOutBuffer(new char[BUFFER_SIZE]), + mInSize(0), mOutSize(0), + mToSkip(0), + mState(IDLE), + mWorkerThread(0) +{ + mMutex = SDL_CreateMutex(); +} + +Network::~Network() +{ + clearHandlers(); + + if (mState != IDLE && mState != ERROR_BROKE) + disconnect(); + + SDL_DestroyMutex(mMutex); + + delete mInBuffer; + delete mOutBuffer; +} + +bool Network::connect(const std::string &address, short port) +{ + if (mState != IDLE && mState != ERROR_BROKE) + { + //logger->log("Tried to connect an already connected socket!"); + return false; + } + + if (address.empty()) + { + //logger->log("Empty address given to Network::connect()!"); + mState = ERROR_BROKE; + return false; + } + + //logger->log("Network::Connecting to %s:%i", address.c_str(), port); + + mAddress = address; + mPort = port; + + // Reset to sane values + mOutSize = 0; + mInSize = 0; + mToSkip = 0; + + mState = CONNECTING; + mWorkerThread = SDL_CreateThread(networkThread, this); + if (!mWorkerThread) + { + //logger->log("Unable to create network worker thread"); + mState = ERROR_BROKE; + return false; + } + + return true; +} + +void Network::disconnect() +{ + if (mState != CONNECTED && mState != CONNECTING) + return; + + mState = IDLE; + + if (mWorkerThread) + { + SDL_WaitThread(mWorkerThread, NULL); + mWorkerThread = NULL; + } + SDLNet_TCP_Close(mSocket); +} + +void Network::registerHandler(MessageHandler *handler) +{ + const Uint16 *i = handler->handledMessages; + + while(*i) + { + mMessageHandlers[*i] = handler; + i++; + } + + handler->setNetwork(this); +} + +void Network::unregisterHandler(MessageHandler *handler) +{ + for (const Uint16 *i = handler->handledMessages; *i; i++) + { + mMessageHandlers.erase(*i); + } + + handler->setNetwork(0); +} + +void Network::clearHandlers() +{ + MessageHandlerIterator i; + for (i = mMessageHandlers.begin(); i != mMessageHandlers.end(); i++) + { + i->second->setNetwork(0); + } + mMessageHandlers.clear(); +} + +void Network::dispatchMessages() +{ + while (messageReady()) + { + MessageIn msg = getNextMessage(); + + MessageHandlerIterator iter = mMessageHandlers.find(msg.getId()); + + if (iter != mMessageHandlers.end()) + iter->second->handleMessage(&msg); + /*else + logger->log("Unhandled packet: %x", msg.getId());*/ + + skip(msg.getLength()); + } +} + +void Network::flush() +{ + if (!mOutSize || mState != CONNECTED) + return; + + int ret; + + + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Send(mSocket, mOutBuffer, mOutSize); + if (ret < (int)mOutSize) + { + //logger->log("Error in SDLNet_TCP_Send(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + } + mOutSize = 0; + SDL_mutexV(mMutex); +} + +void Network::skip(int len) +{ + SDL_mutexP(mMutex); + mToSkip += len; + if (!mInSize) + { + SDL_mutexV(mMutex); + return; + } + + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + SDL_mutexV(mMutex); +} + +bool Network::messageReady() +{ + int len = -1; + + SDL_mutexP(mMutex); + if (mInSize >= 2) + { + len = packet_lengths[readWord(0)]; + + if (len == -1 && mInSize > 4) + len = readWord(2); + + } + + bool ret = (mInSize >= static_cast<unsigned int>(len)); + SDL_mutexV(mMutex); + + return ret; +} + +MessageIn Network::getNextMessage() +{ + while (!messageReady()) + { + if (mState == ERROR_BROKE) + break; + } + + SDL_mutexP(mMutex); + int msgId = readWord(0); + int len = packet_lengths[msgId]; + + if (len == -1) + len = readWord(2); + +#ifdef DEBUG + printf("Received packet 0x%x of length %d\n", msgId, length); +#endif + + MessageIn msg(mInBuffer, len); + SDL_mutexV(mMutex); + + return msg; +} + +bool Network::realConnect() +{ + IPaddress ipAddress; + + if (SDLNet_ResolveHost(&ipAddress, mAddress.c_str(), mPort) == -1) + { + //logger->log("Error in SDLNet_ResolveHost(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + return false; + } + + mState = CONNECTING; + + mSocket = SDLNet_TCP_Open(&ipAddress); + if (!mSocket) + { + //logger->log("Error in SDLNet_TCP_Open(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + return false; + } + + /*logger->log("Network::Started session with %s:%i", + iptostring(ipAddress.host), ipAddress.port);*/ + + mState = CONNECTED; + + return true; +} + +void Network::receive() +{ + SDLNet_SocketSet set; + + if (!(set = SDLNet_AllocSocketSet(1))) + { + //logger->log("Error in SDLNet_AllocSocketSet(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + return; + } + + if (SDLNet_TCP_AddSocket(set, mSocket) == -1) + { + //logger->log("Error in SDLNet_AddSocket(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + } + + while (mState == CONNECTED) + { + // TODO Try to get this to block all the time while still being able + // to escape the loop + int numReady = SDLNet_CheckSockets(set, ((Uint32)500)); + int ret; + switch (numReady) + { + case -1: + // logger->log("Error: SDLNet_CheckSockets"); + // FALLTHROUGH + case 0: + break; + + case 1: + // Receive data from the socket + SDL_mutexP(mMutex); + ret = SDLNet_TCP_Recv(mSocket, mInBuffer + mInSize, BUFFER_SIZE - mInSize); + + if (!ret) + { + // We got disconnected + mState = ERROR_BROKE; //IDLE - changed to error to force a restart. + //logger->log("Disconnected."); + //state = LOGIN_STATE; + } + else if (ret < 0) + { + //logger->log("Error in SDLNet_TCP_Recv(): %s", SDLNet_GetError()); + mState = ERROR_BROKE; + } + else { + mInSize += ret; + if (mToSkip) + { + if (mInSize >= mToSkip) + { + mInSize -= mToSkip; + memmove(mInBuffer, mInBuffer + mToSkip, mInSize); + mToSkip = 0; + } + else + { + mToSkip -= mInSize; + mInSize = 0; + } + } + } + SDL_mutexV(mMutex); + break; + + default: + // more than one socket is ready.. + // this should not happen since we only listen once socket. + //logger->log("Error in SDLNet_TCP_Recv(), %d sockets are ready : %s", numReady, SDLNet_GetError()); + mState = ERROR_BROKE; + break; + } + } + + if (SDLNet_TCP_DelSocket(set, mSocket) == -1) + { + //logger->log("Error in SDLNet_DelSocket(): %s", SDLNet_GetError()); + } + + SDLNet_FreeSocketSet(set); +} + +char *iptostring(int address) +{ + static char asciiIP[16]; + + sprintf(asciiIP, "%i.%i.%i.%i", + (unsigned char)(address), + (unsigned char)(address >> 8), + (unsigned char)(address >> 16), + (unsigned char)(address >> 24)); + + return asciiIP; +} + +Uint16 Network::readWord(int pos) +{ +#if SDL_BYTEORDER == SDL_BIG_ENDIAN + return SDL_Swap16((*(Uint16*)(mInBuffer+(pos)))); +#else + return (*(Uint16*)(mInBuffer+(pos))); +#endif +} diff --git a/src/net/network.h b/src/net/network.h new file mode 100644 index 0000000..45a9838 --- /dev/null +++ b/src/net/network.h @@ -0,0 +1,103 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: network.h 2187 2006-02-24 20:15:19Z der_doener $ + */ + +#ifndef _TMW_NETWORK_ +#define _TMW_NETWORK_ + +#include <map> +#include <SDL_net.h> +#include <SDL_thread.h> +#include <string> + +class MessageHandler; +class MessageIn; + +class Network; + +class Network +{ + public: + friend int networkThread(void *data); + friend class MessageOut; + + Network(); + ~Network(); + + bool connect(const std::string &address, short port); + void disconnect(); + + void registerHandler(MessageHandler *handler); + void unregisterHandler(MessageHandler *handler); + void clearHandlers(); + + int getState() const { return mState; } + bool isConnected() const { return mState == CONNECTED; } + + int getInSize() const { return mInSize; } + + void skip(int len); + + bool messageReady(); + MessageIn getNextMessage(); + + void dispatchMessages(); + void flush(); + + enum { + IDLE, + CONNECTED, + CONNECTING, + DATA, + ERROR_BROKE + }; + + protected: + Uint16 readWord(int pos); + + TCPsocket mSocket; + + std::string mAddress; + short mPort; + + char *mInBuffer, *mOutBuffer; + unsigned int mInSize, mOutSize; + + unsigned int mToSkip; + + int mState; + + SDL_Thread *mWorkerThread; + SDL_mutex *mMutex; + + typedef std::map<Uint16, MessageHandler*> MessageHandlers; + typedef MessageHandlers::iterator MessageHandlerIterator; + MessageHandlers mMessageHandlers; + + bool realConnect(); + void receive(); +}; + +/** Convert an address from int format to string */ +char *iptostring(int address); + +#endif diff --git a/src/net/packet.cpp b/src/net/packet.cpp new file mode 100644 index 0000000..53fb3ff --- /dev/null +++ b/src/net/packet.cpp @@ -0,0 +1,40 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: packet.cpp 1846 2005-10-09 03:34:45Z b_lindeijer $ + */ + +#include "packet.h" + +#include <cstring> + +Packet::Packet(const char *data, int length): + mLength(length) +{ + // Create a copy of the data + mData = new char[mLength]; + memcpy(mData, data, mLength); +} + +Packet::~Packet() +{ + // Clean up the data + delete[] mData; +} diff --git a/src/net/packet.h b/src/net/packet.h new file mode 100644 index 0000000..5f4e8a2 --- /dev/null +++ b/src/net/packet.h @@ -0,0 +1,47 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: packet.h 1846 2005-10-09 03:34:45Z b_lindeijer $ + */ + +#ifndef _TMW_PACKET_ +#define _TMW_PACKET_ + +/** + * A packet wraps a certain amount of bytes for sending and receiving. + */ +class Packet +{ + public: + /** + * Constructor. + */ + Packet(const char *data, int length); + + /** + * Destructor. + */ + ~Packet(); + + char *mData; /**< Packet data */ + unsigned int mLength; /**< Length of data in bytes */ +}; + +#endif diff --git a/src/net/protocol.cpp b/src/net/protocol.cpp new file mode 100644 index 0000000..791b7fe --- /dev/null +++ b/src/net/protocol.cpp @@ -0,0 +1,79 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: protocol.cpp 2158 2006-02-07 10:37:54Z der_doener $ + */ + +#include "protocol.h" + +#define LOBYTE(w) ((unsigned char)(w)) +#define HIBYTE(w) ((unsigned char)(((unsigned short)(w)) >> 8)) + +void set_coordinates(char *data, + unsigned short x, + unsigned short y, + unsigned char direction) +{ + short temp; + temp = x; + temp <<= 6; + data[0] = 0; + data[1] = 1; + data[2] = 2; + data[0] = HIBYTE(temp); + data[1] = (unsigned char)(temp); + temp = y; + temp <<= 4; + data[1] |= HIBYTE(temp); + data[2] = LOBYTE(temp); + + // Translate direction to eAthena format + switch (direction) + { + case 1: + direction = 0; + break; + case 3: + direction = 1; + break; + case 2: + direction = 2; + break; + case 6: + direction = 3; + break; + case 4: + direction = 4; + break; + case 12: + direction = 5; + break; + case 8: + direction = 6; + break; + case 9: + direction = 7; + break; + default: + // OOPSIE! Impossible or unknown + direction = (unsigned char)-1; + } + data[2] |= direction; +} diff --git a/src/net/protocol.h b/src/net/protocol.h new file mode 100644 index 0000000..06b3df3 --- /dev/null +++ b/src/net/protocol.h @@ -0,0 +1,118 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: protocol.h 2135 2006-02-03 13:53:50Z der_doener $ + */ + +#ifndef _TMW_PROTOCOL_ +#define _TMW_PROTOCOL_ + +// Packets from server to client +#define SMSG_SERVER_PING 0x007f /**< Contains server tick */ +#define SMSG_LOGIN_SUCCESS 0x0073 /**< Contains starting location */ +#define SMSG_QUEST_PLAYER_VARS 0x0215 /**< Quest Log info (ignored) */ +#define SMSG_PLAYER_UPDATE_1 0x01d8 +#define SMSG_PLAYER_UPDATE_2 0x01d9 +#define SMSG_PLAYER_MOVE 0x01da /**< A nearby player moves */ +#define SMSG_PLAYER_STAT_UPDATE_1 0x00b0 +#define SMSG_PLAYER_STAT_UPDATE_2 0x00b1 +#define SMSG_PLAYER_STAT_UPDATE_3 0x0141 +#define SMSG_PLAYER_STAT_UPDATE_4 0x00bc +#define SMSG_PLAYER_STAT_UPDATE_5 0x00bd +#define SMSG_PLAYER_STAT_UPDATE_6 0x00be +#define SMSG_WHO_ANSWER 0x00c2 +#define SMSG_PLAYER_WARP 0x0091 /**< Warp player to map/location */ +#define SMSG_PLAYER_INVENTORY 0x01ee +#define SMSG_PLAYER_INVENTORY_ADD 0x00a0 +#define SMSG_PLAYER_INVENTORY_REMOVE 0x00af +#define SMSG_PLAYER_INVENTORY_USE 0x01c8 +#define SMSG_PLAYER_EQUIPMENT 0x00a4 +#define SMSG_PLAYER_EQUIP 0x00aa +#define SMSG_PLAYER_UNEQUIP 0x00ac +#define SMSG_PLAYER_ARROW_EQUIP 0x013c +#define SMSG_PLAYER_ARROW_MESSAGE 0x013b +#define SMSG_PLAYER_SKILLS 0x010f +#define SMSG_SKILL_FAILED 0x0110 +#define SMSG_ITEM_USE_RESPONSE 0x00a8 +#define SMSG_ITEM_VISIBLE 0x009d /**< An item is on the floor */ +#define SMSG_ITEM_DROPPED 0x009e /**< An item is dropped */ +#define SMSG_ITEM_REMOVE 0x00a1 /**< An item disappers */ +#define SMSG_BEING_VISIBLE 0x0078 +#define SMSG_BEING_MOVE 0x007b /**< A nearby monster moves */ +#define SMSG_BEING_REMOVE 0x0080 +#define SMSG_BEING_CHANGE_LOOKS 0x00c3 +#define SMSG_BEING_LEVELUP 0x019b +#define SMSG_BEING_EMOTION 0x00c0 +#define SMSG_BEING_ACTION 0x008a /**< Attack, sit, stand up, ... */ +#define SMSG_BEING_CHAT 0x008d /**< A being talks */ +#define SMSG_BEING_NAME_RESPONSE 0x0095 /**< Has to be requested */ +#define SMSG_NPC_MESSAGE 0x00b4 +#define SMSG_NPC_NEXT 0x00b5 +#define SMSG_NPC_CLOSE 0x00b6 +#define SMSG_NPC_CHOICE 0x00b7 /**< Display a choice */ +#define SMSG_NPC_BUY_SELL_CHOICE 0x00c4 +#define SMSG_NPC_BUY 0x00c6 +#define SMSG_NPC_SELL 0x00c7 +#define SMSG_NPC_BUY_RESPONSE 0x00ca +#define SMSG_NPC_SELL_RESPONSE 0x00cb +#define SMSG_PLAYER_CHAT 0x008e /**< Player talks */ +#define SMSG_WHISPER 0x0097 /**< Whisper Recieved */ +#define SMSG_WHISPER_RESPONSE 0x0098 +#define SMSG_GM_CHAT 0x009a /**< GM announce */ +#define SMSG_WALK_RESPONSE 0x0087 +#define SMSG_TRADE_REQUEST 0x00e5 /**< Receiving a request to trade */ +#define SMSG_TRADE_RESPONSE 0x00e7 +#define SMSG_TRADE_ITEM_ADD 0x00e9 +#define SMSG_TRADE_ITEM_ADD_RESPONSE 0x01b1 /**< Not standard eAthena! */ +#define SMSG_TRADE_OK 0x00ec +#define SMSG_TRADE_CANCEL 0x00ee +#define SMSG_TRADE_COMPLETE 0x00f0 + +// Packets from client to server +#define CMSG_CLIENT_PING 0x007e +#define CMSG_TRADE_RESPONSE 0x00e6 +#define CMSG_ITEM_PICKUP 0x009f +#define CMSG_MAP_LOADED 0x007d +#define CMSG_NPC_BUY_REQUEST 0x00c8 +#define CMSG_NPC_BUY_SELL_REQUEST 0x00c5 +#define CMSG_CHAT_MESSAGE 0x008c +#define CMSG_CHAT_WHISPER 0x0096 +#define CMSG_NPC_LIST_CHOICE 0x00b8 +#define CMSG_NPC_NEXT_REQUEST 0x00b9 +#define CMSG_NPC_SELL_REQUEST 0x00c9 +#define CMSG_SKILL_LEVELUP_REQUEST 0x0112 +#define CMSG_STAT_UPDATE_REQUEST 0x00bb +#define CMSG_TRADE_ITEM_ADD_REQUEST 0x00e8 +#define CMSG_TRADE_CANCEL_REQUEST 0x00ed +#define CMSG_TRADE_ADD_COMPLETE 0x00eb +#define CMSG_TRADE_OK 0x00ef +#define CMSG_NPC_TALK 0x0090 +#define CMSG_TRADE_REQUEST 0x00e4 +#define CMSG_PLAYER_INVENTORY_USE 0x00a7 +#define CMSG_PLAYER_INVENTORY_DROP 0x00a2 +#define CMSG_PLAYER_EQUIP 0x00a9 +#define CMSG_PLAYER_UNEQUIP 0x00ab +#define CMSG_PLAYER_CHANGE_ACT 0x0089 + + +/** Encodes coords and direction in 3 bytes data */ +void set_coordinates(char *data, unsigned short x, unsigned short y, unsigned char direction); + +#endif diff --git a/src/onlinelist.cpp b/src/onlinelist.cpp new file mode 100644 index 0000000..1c326af --- /dev/null +++ b/src/onlinelist.cpp @@ -0,0 +1,145 @@ +/* + * 4144's whoisonline code. + * + */ + +#include "onlinelist.h" + +#include <iostream> +#include <fstream> +#include <SDL.h> +#include <SDL_thread.h> +#include <vector> +#include <algorithm> + +#include "automation.h" +#include "game.h" +#include "main.h" +#include "utils/stringutils.h" + +OnlineList::OnlineList(): + mThread(NULL), + mDownloadStatus(UPDATE_LIST), + mDownloadComplete(true), + mAllowUpdate(true), + mOnlinePlayers() +{ + download(); +} + +OnlineList::~OnlineList() +{ + if (mThread && SDL_GetThreadID(mThread)) + SDL_WaitThread(mThread, NULL); +} + + +int OnlineList::downloadThread(void *ptr) +{ + OnlineList *wio = reinterpret_cast<OnlineList *>(ptr); + + std::string namelist = "online.txt"; + std::ifstream listFile (namelist.c_str(), std::ifstream::in); + + if (!wio->mAllowUpdate) + { + return 0; + } + + if (listFile.is_open()) + { + wio->mOnlinePlayers.clear(); + const std::string gmText = "(GM)"; + bool listStarted(false); + + while (!listFile.eof()) + { + std::string line; + getline(listFile, line); + if (!line.empty()) + { + std::string lineStr = line; + utils_trim(lineStr); + std::string::size_type pos = lineStr.find(gmText, 0); + if (pos != std::string::npos && pos == lineStr.length() - gmText.length()) + { + lineStr = lineStr.substr(0, pos-1); + utils_trim(lineStr); + + } + + if (listStarted == true) + { + size_t found = lineStr.find(" users are online."); //Dodgy hack! + if (found == std::string::npos) + wio->mOnlinePlayers.insert(lineStr); + } + else if (lineStr == "------------------------------") + listStarted = true; + } + } + listFile.close(); + } + else + { + wio->mDownloadStatus = UPDATE_ERROR; + return 0; + } + + wio->mDownloadComplete = true; + return 0; +} + +void OnlineList::download() +{ + mDownloadComplete = true; + if (mThread && SDL_GetThreadID(mThread)) + SDL_WaitThread(mThread, NULL); + + mDownloadComplete = false; + mThread = SDL_CreateThread(OnlineList::downloadThread, this); + + if (mThread == NULL) + mDownloadStatus = UPDATE_ERROR; +} + +void OnlineList::logic() +{ + + if (!mAllowUpdate) + return; + + if (mUpdateTimer == 0) + mUpdateTimer = cur_time; + + double timeDiff = difftime(cur_time, mUpdateTimer); + int timeLimit = 2; // Downloads the online list every 20 seconds. + + if (timeDiff >= timeLimit && mDownloadStatus != UPDATE_LIST) + { + mUpdateTimer = 0; + mDownloadStatus = UPDATE_LIST; + download(); + } + + switch (mDownloadStatus) + { + case UPDATE_ERROR: + mDownloadStatus = UPDATE_COMPLETE; + break; + case UPDATE_LIST: + if (mDownloadComplete == true) + { + mDownloadStatus = UPDATE_COMPLETE; + mUpdateTimer = 0; + + if (mOnlinePlayers.size() > 0) + Automation::getAutomationHandler()->updateOnline(mOnlinePlayers); + + } + break; + default: + break; + } +} + diff --git a/src/onlinelist.h b/src/onlinelist.h new file mode 100644 index 0000000..4c4b5f3 --- /dev/null +++ b/src/onlinelist.h @@ -0,0 +1,86 @@ +/* + * File: onlinelist.h + * Author: dipesh + * + * Created on August 2, 2010, 1:12 AM + */ + +#ifndef _ONLINELIST_H +#define _ONLINELIST_H + + +#include <string> +#include <set> + +#include "utils/mutex.h" + +struct SDL_Thread; + +/** + * Update progress window GUI + * + * \ingroup GUI + */ +class OnlineList +{ + public: + /** + * Constructor. + */ + OnlineList(); + + /** + * Destructor + */ + ~OnlineList(); + + void logic(); + + std::set<std::string> &getOnlinePlayers() + { return mOnlinePlayers; } + + void setAllowUpdate(bool n) + { mAllowUpdate = n; } + +private: + void download(); + + /** + * The thread function that download the files. + */ + static int downloadThread(void *ptr); + + enum DownloadStatus + { + UPDATE_ERROR = 0, + UPDATE_COMPLETE, + UPDATE_LIST + }; + + /** A thread that use libcurl to download updates. */ + SDL_Thread *mThread; + + /** Status of the current download. */ + DownloadStatus mDownloadStatus; + + /** Flag that show if current download is complete. */ + bool mDownloadComplete; + + /** Byte count currently downloaded in mMemoryBuffer. */ + int mDownloadedBytes; + + /** Buffer for files downloaded to memory. */ + char *mMemoryBuffer; + + /** Buffer to handler human readable error provided by curl. */ + char *mCurlError; + + time_t mUpdateTimer; + std::set<std::string> mOnlinePlayers; + + bool mAllowUpdate; +}; + +#endif /* _ONLINELIST_H */ + + diff --git a/src/serverinfo.h b/src/serverinfo.h new file mode 100644 index 0000000..e79bdf2 --- /dev/null +++ b/src/serverinfo.h @@ -0,0 +1,37 @@ +/* + * The Mana World + * Copyright 2004 The Mana World Development Team + * + * This file is part of The Mana World. + * + * The Mana World 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; either version 2 of the License, or + * any later version. + * + * The Mana World is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 The Mana World; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serverinfo.h 1735 2005-09-13 22:56:29Z der_doener $ + */ + +#ifndef _TMW_SERVERINFO_ +#define _TMW_SERVERINFO_ + +#include <string> + +struct SERVER_INFO +{ + int address; + short port; + std::string name; + short online_users; +}; + +#endif diff --git a/src/utils/mutex.h b/src/utils/mutex.h new file mode 100644 index 0000000..80569e2 --- /dev/null +++ b/src/utils/mutex.h @@ -0,0 +1,91 @@ +/* + * The Mana Client + * Copyright (C) 2008-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * 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; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef MUTEX_H +#define MUTEX_H + +#include <SDL_thread.h> + +/** + * A mutex provides mutual exclusion of access to certain data that is + * accessed by multiple threads. + */ +class Mutex +{ +public: + Mutex(); + ~Mutex(); + + void lock(); + void unlock(); + +private: + Mutex(const Mutex&); // prevent copying + Mutex& operator=(const Mutex&); + + SDL_mutex *mMutex; +}; + +/** + * A convenience class for locking a mutex. + */ +class MutexLocker +{ +public: + MutexLocker(Mutex *mutex); + ~MutexLocker(); + +private: + Mutex *mMutex; +}; + + +inline Mutex::Mutex() +{ + mMutex = SDL_CreateMutex(); +} + +inline Mutex::~Mutex() +{ + SDL_DestroyMutex(mMutex); +} + +inline void Mutex::lock() +{ +} + +inline void Mutex::unlock() +{ +} + + +inline MutexLocker::MutexLocker(Mutex *mutex): + mMutex(mutex) +{ + mMutex->lock(); +} + +inline MutexLocker::~MutexLocker() +{ + mMutex->unlock(); +} + +#endif // MUTEX_H diff --git a/src/utils/specialfolder.cpp b/src/utils/specialfolder.cpp new file mode 100644 index 0000000..6460771 --- /dev/null +++ b/src/utils/specialfolder.cpp @@ -0,0 +1,78 @@ +/* + * The Mana Client + * Copyright (C) 2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * 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; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>. + */ + +#ifdef WIN32 +#include "specialfolder.h" +#include <windows.h> + +#ifdef _SPECIALFOLDERLOCATION_TEST_ +// compile with -D_SPECIALFOLDERLOCATION_TEST_ to get a standalone +// binary for testing +#include <iostream> +#endif + +/* + * Retrieve the pathname of special folders on win32, or an empty string + * on error / if the folder does not exist. + * See http://msdn.microsoft.com/en-us/library/bb762494(VS.85).aspx for + * a list of folder ids + */ +std::string getSpecialFolderLocation(int folderId) +{ + std::string ret; + LPITEMIDLIST pItemIdList; + LPMALLOC pMalloc; + char szPath[_MAX_PATH]; + + // get the item ID list for folderId + HRESULT hr = SHGetSpecialFolderLocation(NULL, folderId, &pItemIdList); + if (hr != S_OK) + return ret; + + // convert the ID list into a file system path + if (SHGetPathFromIDList(pItemIdList, szPath) == FALSE) + return ret; + + // get the IMalloc pointer and free all resources we used + hr = SHGetMalloc(&pMalloc); + pMalloc->Free(pItemIdList); + pMalloc->Release(); + + ret = szPath; + return ret; +} + +#ifdef _SPECIALFOLDERLOCATION_TEST_ +int main() +{ + std::cout << "APPDATA " << getSpecialFolderLocation(CSIDL_APPDATA) + << std::endl; + std::cout << "DESKTOP " << getSpecialFolderLocation(CSIDL_DESKTOP) + << std::endl; + std::cout << "LOCAL_APPDATA " + << getSpecialFolderLocation(CSIDL_LOCAL_APPDATA) + << std::endl; + std::cout << "MYPICTURES " << getSpecialFolderLocation(CSIDL_MYPICTURES) + << std::endl; + std::cout << "PERSONAL " << getSpecialFolderLocation(CSIDL_PERSONAL) + << std::endl; +} +#endif +#endif diff --git a/src/utils/specialfolder.h b/src/utils/specialfolder.h new file mode 100644 index 0000000..c2c2e0b --- /dev/null +++ b/src/utils/specialfolder.h @@ -0,0 +1,30 @@ +/* + * The Mana Client + * Copyright (C) 2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * 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; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _SPECIALFOLDER_H +#define _SPECIALFOLDER_H + +#ifdef WIN32 +#include <shlobj.h> +#include <string> +std::string getSpecialFolderLocation(int folderId); +#endif + +#endif diff --git a/src/utils/stringutils.cpp b/src/utils/stringutils.cpp new file mode 100644 index 0000000..c7f83c3 --- /dev/null +++ b/src/utils/stringutils.cpp @@ -0,0 +1,177 @@ +/* + * The Mana Client + * Copyright (C) 2007-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * 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; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>. + */ + +#include "stringutils.h" + +#include <string.h> +#include <algorithm> +#include <cstdarg> +#include <cstdio> + +const int UTF8_MAX_SIZE = 10; + +std::string &utils_trim(std::string &str) +{ + std::string::size_type pos = str.find_last_not_of(' '); + if (pos != std::string::npos) + { + str.erase(pos + 1); + pos = str.find_first_not_of(' '); + + if (pos != std::string::npos) + str.erase(0, pos); + } + else + { + // There is nothing else but whitespace in the string + str.clear(); + } + return str; +} + +std::string &toLower(std::string &str) +{ + std::transform(str.begin(), str.end(), str.begin(), tolower); + return str; +} + +std::string &toUpper(std::string &str) +{ + std::transform(str.begin(), str.end(), str.begin(), toupper); + return str; +} + +unsigned int atox(const std::string &str) +{ + unsigned int value; + sscanf(str.c_str(), "0x%06x", &value); + + return value; +} + +const char *ipToString(int address) +{ + static char asciiIP[16]; + + sprintf(asciiIP, "%i.%i.%i.%i", + (unsigned char)(address), + (unsigned char)(address >> 8), + (unsigned char)(address >> 16), + (unsigned char)(address >> 24)); + + return asciiIP; +} + +std::string strprintf(char const *format, ...) +{ + char buf[256]; + va_list(args); + va_start(args, format); + int nb = vsnprintf(buf, 256, format, args); + va_end(args); + if (nb < 256) + { + return buf; + } + // The static size was not big enough, try again with a dynamic allocation. + ++nb; + char *buf2 = new char[nb]; + va_start(args, format); + vsnprintf(buf2, nb, format, args); + va_end(args); + std::string res(buf2); + delete [] buf2; + return res; +} + +std::string &removeBadChars(std::string &str) +{ + std::string::size_type pos; + do + { + pos = str.find_first_of("@#[]"); + if (pos != std::string::npos) + str.erase(pos, 1); + } while (pos != std::string::npos); + + return str; +} + +std::string removeColors(std::string msg) +{ + for (unsigned int f = 0; f < msg.length() - 2 && msg.length() > 2; f++) + { + while (msg.length() > f + 2 && msg.at(f) == '#' && msg.at(f + 1) == '#') + { + msg = msg.erase(f, 3); + } + } + return msg; +} + +int compareStrI(const std::string &a, const std::string &b) +{ + std::string::const_iterator itA = a.begin(); + std::string::const_iterator endA = a.end(); + std::string::const_iterator itB = b.begin(); + std::string::const_iterator endB = b.end(); + + for (; itA < endA, itB < endB; ++itA, ++itB) + { + int comp = tolower(*itA) - tolower(*itB); + if (comp) + return comp; + } + + // Check string lengths + if (itA == endA && itB == endB) + return 0; + else if (itA == endA) + return -1; + else + return 1; +} + +bool isWordSeparator(char chr) +{ + return (chr == ' ' || chr == ',' || chr == '.' || chr == '"'); +} + +const std::string findSameSubstring(const std::string &str1, const std::string &str2) +{ + int minLength = str1.length() > str2.length() ? str2.length() : str1.length(); + for (int f = 0; f < minLength; f ++) + { + if (str1.at(f) != str2.at(f)) + { + return str1.substr(0, f); + } + } + return str1.substr(0, minLength); +} + +const char* getSafeUtf8String(std::string text) +{ + char* buf = new char[text.size() + UTF8_MAX_SIZE]; + memcpy(buf, text.c_str(), text.size()); + memset(buf + text.size(), 0, UTF8_MAX_SIZE); + return buf; +} diff --git a/src/utils/stringutils.h b/src/utils/stringutils.h new file mode 100644 index 0000000..5f79f5b --- /dev/null +++ b/src/utils/stringutils.h @@ -0,0 +1,142 @@ +/* + * The Mana Client + * Copyright (C) 2007-2009 The Mana World Development Team + * Copyright (C) 2009-2010 The Mana Developers + * + * This file is part of The Mana Client. + * + * 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; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef UTILS_STRINGUTILS_H +#define UTILS_STRINGUTILS_H + +#include <string> +#include <sstream> + +/** + * Trims spaces off the end and the beginning of the given string. + * + * @param str the string to trim spaces off + * @return a reference to the trimmed string + */ +std::string &utils_trim(std::string &str); + +/** + * Converts the given string to lower case. + * + * @param str the string to convert to lower case + * @return a reference to the given string converted to lower case + */ +std::string &toLower(std::string &str); + +/** + * Converts the given string to upper case. + * + * @param str the string to convert to upper case + * @return a reference to the given string converted to upper case + */ +std::string &toUpper(std::string &str); + + +/** + * Converts an ascii hexidecimal string to an integer + * + * @param str the hex string to convert to an int + * @return the integer representation of the hex string + */ +unsigned int atox(const std::string &str); + +/** + * Converts the given value to a string using std::stringstream. + * + * @param arg the value to convert to a string + * @return the string representation of arg + */ +template<typename T> std::string toString(const T &arg) +{ + std::stringstream ss; + ss << arg; + return ss.str(); +} +/** + * Converts the given value to a int using std::stringstream. + * + * @param arg the value to convert to a int + * @return the int representation of arg + */ + +template<typename T> int toInt(const T &arg) +{ + std::stringstream ss(arg); + int out; + ss >> out; + return out; +} + +/** + * Converts the given IP address to a string. + * + * The returned string is statically allocated, and shouldn't be freed. It is + * changed upon the next use of this method. + * + * @param address the address to convert to a string + * @return the string representation of the address + */ +const char *ipToString(int address); + +/** + * A safe version of sprintf that returns a std::string of the result. + */ +std::string strprintf(char const *, ...) +#ifdef __GNUC__ + /* This attribute is nice: it even works through gettext invokation. For + example, gcc will complain that strprintf(_("%s"), 42) is ill-formed. */ + __attribute__((__format__(__printf__, 1, 2))) +#endif +; + +/** + * Removes bad characters from a string + * + * @param str the string to remove the bad chars from + * @return a reference to the string without bad chars + */ +std::string &removeBadChars(std::string &str); + +/** + * Removes colors from a string + * + * @param msg the string to remove the colors from + * @return string without colors + */ +std::string removeColors(std::string msg); + +/** + * Compares the two strings case-insensitively. + * + * @param a the first string in the comparison + * @param b the second string in the comparison + * @return 0 if the strings are equal, positive if the first is greater, + * negative if the second is greater + */ +int compareStrI(const std::string &a, const std::string &b); + +bool isWordSeparator(char chr); + +const std::string findSameSubstring(const std::string &str1, const std::string &str2); + +const char* getSafeUtf8String(std::string text); + +#endif // UTILS_STRINGUTILS_H |