From: Akiko Date: Tue, 19 May 2015 10:06:06 +0000 (+0200) Subject: - renamed a missed file (including buildsystem update) X-Git-Url: http://community.linux-addicted.net/gitweb/?a=commitdiff_plain;h=5861ccf61fb30562b8ab364947f14f3cdc982c45;p=tinns.git - renamed a missed file (including buildsystem update) - changed windows/dos linefeeds to unix ones --- diff --git a/TinNS/Source/Common/Config.cxx b/TinNS/Source/Common/Config.cxx index 1d30b06..3803b1c 100644 --- a/TinNS/Source/Common/Config.cxx +++ b/TinNS/Source/Common/Config.cxx @@ -1,165 +1,165 @@ -#include -#include "Common/Includes.hxx" - -PConfig::PConfig() -{ - mOptValRegEx = new RegEx("^\\s*([[:graph:]]+)\\s*=\\s*(.+?)\\s*$", PCRE_CASELESS); - mIncludeRegEx = new RegEx("^\\s*include\\s+([[:graph:]]+)\\s*$", PCRE_CASELESS); -} - -PConfig::~PConfig() -{ - delete mOptValRegEx; - delete mIncludeRegEx; -} - -bool PConfig::LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile, int nDepth) -{ - FILE *ConfigFile; - char line[255]; - std::string Opt, Val; - //int numOptions = 0; - int i; - bool Found; - bool NoError = true; - - ConfigFile = fopen(nConfigFile,"r"); - - if(!ConfigFile) - { - Console->Print("%s Cant open file \"%s\"", Console->ColorText(RED, BLACK, "[Error]"), nConfigFile); - return false; - } - - if(nDepth) - Console->Print("%s Including file %s (nesting level %d)", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile, nDepth); - else - Console->Print("%s Loading configuration file %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile); - - while(!feof(ConfigFile) && fgets(line, 255, ConfigFile)) - { - //Console->Print("LINE: '%s'", line); - if (line[0] == '/' && line[1] == '/') - continue; - - if(mOptValRegEx->Search(line)) - { - Opt = mOptValRegEx->Match(1); - Val = mOptValRegEx->Match(2); - //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str()); - - Trim(&Opt); - Trim(&Val); - //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str()); - } - else if(mIncludeRegEx->Search(line)) - { - if(nDepth < CONFIG_MAXDEPTH) - { - std::string TargetName = mIncludeRegEx->Match(1); - std::string StartName = nConfigFile; - int BasenamePos = StartName.rfind("/"); - if(BasenamePos > 0) - TargetName = StartName.substr(0, BasenamePos) + "/" + TargetName; - - NoError = LoadOptions(nConfigTemplate, TargetName.c_str(), nDepth+1) && NoError; - continue; - } - else - { - Console->Print("%s Max nesting level (%d) reached. Can't include configuration file %s", Console->ColorText(RED, BLACK, "[Error]"), CONFIG_MAXDEPTH,mIncludeRegEx->Match(1)); - NoError = false; - } - } - else - { - continue; - } - - i = 0; - Found = false; - while(!Found && (nConfigTemplate[i][0][0] != '\0')) - { - if(!strcmp(Opt.c_str(), nConfigTemplate[i++][0])) - { - Found = true; - break; - } - } - - if(!Opt.empty() && !Val.empty()) - { - //Console->Print("#%d [%s] [%s]", numOptions, Opt.c_str(), Val.c_str()); - if (Found) - { - if (GetOption(Opt) != "") - { - Console->Print("%s trying to set option %s more than once (old value '%s' - new value '%s' ignored)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), GetOption(Opt).c_str(), Val.c_str()); - } - else - { - //Console->Print(GREEN, BLACK, "New option %s set to %s", Opt.c_str(), Val.c_str()); - mOptions.insert(std::make_pair(Opt, Val)); - } - } - else - { - Console->Print("%s option %s unknow and ignored (value %s)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), Val.c_str()); - } - } - } - - // Now check for completeness and set default values when needed and available - if(!nDepth) // Check only if we're at top level (ie. not in an included file) - { - i = 0; - while(nConfigTemplate[i][0][0] != '\0') - { - if (GetOption(nConfigTemplate[i][0]) == "") - { - if(nConfigTemplate[i][1][0] == '\0') - { - Console->Print("%s required option %s missing from config file", Console->ColorText(RED, BLACK, "[Error]"), nConfigTemplate[i][0]); - NoError = false; - } - else - { - Console->Print("%s using default value %s for option %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigTemplate[i][1], nConfigTemplate[i][0]); - mOptions.insert(std::make_pair(nConfigTemplate[i][0], nConfigTemplate[i][1])); - } - } - ++i; - } - } - - if (NoError) - { - if(nDepth) - Console->Print("%s file included", Console->ColorText(GREEN, BLACK, "[Info]") ); - else - Console->Print("%s Configuration file loaded", Console->ColorText(GREEN, BLACK, "[Success]") ); - } - else - Console->Print(RED, BLACK, "[Error] Fatal errors found in configuration file"); - - return (NoError); -} - -const std::string &PConfig::GetOption(const std::string Name) const -{ - static std::string NullString = ""; - OptionsMap::const_iterator i = mOptions.find(Name); - if(i!=mOptions.end()) - return i->second; - - return NullString; -} - -int PConfig::GetOptionInt(const std::string Name) const -{ - OptionsMap::const_iterator i = mOptions.find(Name); - if(i!=mOptions.end()) - return atoi(i->second.c_str()); - - return 0; -} +#include +#include "Common/Includes.hxx" + +PConfig::PConfig() +{ + mOptValRegEx = new RegEx("^\\s*([[:graph:]]+)\\s*=\\s*(.+?)\\s*$", PCRE_CASELESS); + mIncludeRegEx = new RegEx("^\\s*include\\s+([[:graph:]]+)\\s*$", PCRE_CASELESS); +} + +PConfig::~PConfig() +{ + delete mOptValRegEx; + delete mIncludeRegEx; +} + +bool PConfig::LoadOptions(const char* nConfigTemplate[][2], const char* nConfigFile, int nDepth) +{ + FILE *ConfigFile; + char line[255]; + std::string Opt, Val; + //int numOptions = 0; + int i; + bool Found; + bool NoError = true; + + ConfigFile = fopen(nConfigFile,"r"); + + if(!ConfigFile) + { + Console->Print("%s Cant open file \"%s\"", Console->ColorText(RED, BLACK, "[Error]"), nConfigFile); + return false; + } + + if(nDepth) + Console->Print("%s Including file %s (nesting level %d)", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile, nDepth); + else + Console->Print("%s Loading configuration file %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigFile); + + while(!feof(ConfigFile) && fgets(line, 255, ConfigFile)) + { + //Console->Print("LINE: '%s'", line); + if (line[0] == '/' && line[1] == '/') + continue; + + if(mOptValRegEx->Search(line)) + { + Opt = mOptValRegEx->Match(1); + Val = mOptValRegEx->Match(2); + //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str()); + + Trim(&Opt); + Trim(&Val); + //Console->Print("'%s'='%s'", Opt.c_str(), Val.c_str()); + } + else if(mIncludeRegEx->Search(line)) + { + if(nDepth < CONFIG_MAXDEPTH) + { + std::string TargetName = mIncludeRegEx->Match(1); + std::string StartName = nConfigFile; + int BasenamePos = StartName.rfind("/"); + if(BasenamePos > 0) + TargetName = StartName.substr(0, BasenamePos) + "/" + TargetName; + + NoError = LoadOptions(nConfigTemplate, TargetName.c_str(), nDepth+1) && NoError; + continue; + } + else + { + Console->Print("%s Max nesting level (%d) reached. Can't include configuration file %s", Console->ColorText(RED, BLACK, "[Error]"), CONFIG_MAXDEPTH,mIncludeRegEx->Match(1)); + NoError = false; + } + } + else + { + continue; + } + + i = 0; + Found = false; + while(!Found && (nConfigTemplate[i][0][0] != '\0')) + { + if(!strcmp(Opt.c_str(), nConfigTemplate[i++][0])) + { + Found = true; + break; + } + } + + if(!Opt.empty() && !Val.empty()) + { + //Console->Print("#%d [%s] [%s]", numOptions, Opt.c_str(), Val.c_str()); + if (Found) + { + if (GetOption(Opt) != "") + { + Console->Print("%s trying to set option %s more than once (old value '%s' - new value '%s' ignored)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), GetOption(Opt).c_str(), Val.c_str()); + } + else + { + //Console->Print(GREEN, BLACK, "New option %s set to %s", Opt.c_str(), Val.c_str()); + mOptions.insert(std::make_pair(Opt, Val)); + } + } + else + { + Console->Print("%s option %s unknow and ignored (value %s)", Console->ColorText(YELLOW, BLACK, "[Warning]"), Opt.c_str(), Val.c_str()); + } + } + } + + // Now check for completeness and set default values when needed and available + if(!nDepth) // Check only if we're at top level (ie. not in an included file) + { + i = 0; + while(nConfigTemplate[i][0][0] != '\0') + { + if (GetOption(nConfigTemplate[i][0]) == "") + { + if(nConfigTemplate[i][1][0] == '\0') + { + Console->Print("%s required option %s missing from config file", Console->ColorText(RED, BLACK, "[Error]"), nConfigTemplate[i][0]); + NoError = false; + } + else + { + Console->Print("%s using default value %s for option %s", Console->ColorText(GREEN, BLACK, "[Info]"), nConfigTemplate[i][1], nConfigTemplate[i][0]); + mOptions.insert(std::make_pair(nConfigTemplate[i][0], nConfigTemplate[i][1])); + } + } + ++i; + } + } + + if (NoError) + { + if(nDepth) + Console->Print("%s file included", Console->ColorText(GREEN, BLACK, "[Info]") ); + else + Console->Print("%s Configuration file loaded", Console->ColorText(GREEN, BLACK, "[Success]") ); + } + else + Console->Print(RED, BLACK, "[Error] Fatal errors found in configuration file"); + + return (NoError); +} + +const std::string &PConfig::GetOption(const std::string Name) const +{ + static std::string NullString = ""; + OptionsMap::const_iterator i = mOptions.find(Name); + if(i!=mOptions.end()) + return i->second; + + return NullString; +} + +int PConfig::GetOptionInt(const std::string Name) const +{ + OptionsMap::const_iterator i = mOptions.find(Name); + if(i!=mOptions.end()) + return atoi(i->second.c_str()); + + return 0; +} diff --git a/TinNS/Source/Common/Config.hxx b/TinNS/Source/Common/Config.hxx index 0741022..8f605dd 100644 --- a/TinNS/Source/Common/Config.hxx +++ b/TinNS/Source/Common/Config.hxx @@ -1,57 +1,57 @@ -#pragma once - -#include -#include -#include -#include - -class RegEx; - -class PConfig { -private: - typedef std::map OptionsMap; - OptionsMap mOptions; - RegEx *mOptValRegEx; - RegEx *mIncludeRegEx; - - bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile, int32_t nDepth); - -public: - PConfig(); - ~PConfig(); - - inline bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile) - { return LoadOptions(nConfigTemplate, nConfigFile, 0); } - inline const std::string &GetOption(const char *Name) const { return GetOption((std::string) Name); } - const std::string &GetOption(const std::string Name) const; - int32_t GetOptionInt(const char *Name) const { return GetOptionInt((std::string) Name); } - int32_t GetOptionInt(const std::string Name) const; -}; - -// Max nested includes -#define CONFIG_MAXDEPTH 4 - -/* - The list of valid config options is now set in the array ConfigTemplate - A default value can be set for each option, whiches makes the option optionnal in config file - If no default value is set, the option is mandatory. - Duplicate option entries in config file are also checked, and only the first value is kept - Unkown options are rejected - Duplicates, unkown and default use generate a warning in logs but don't break options loading - Missing mandatory option generate an error in log and break option loading (imediate return false) - - The ConfigTemplate parameter must have the structure shown in the following exemple: - -const char* ConfigTemplate[][2] = { - // {option_name, default_value} if default_value is empty string, it means option is mandatory - // List ends with empty string for option_name - {"info_sql_host", "127.0.0.1"}, - {"info_sql_port", "3306"}, - {"info_sql_username", ""}, - {"info_sql_password", ""}, - {"", ""} // do not change this line (end mark) -}; - -*/ - -extern class PConfig* Config; +#pragma once + +#include +#include +#include +#include + +class RegEx; + +class PConfig { +private: + typedef std::map OptionsMap; + OptionsMap mOptions; + RegEx *mOptValRegEx; + RegEx *mIncludeRegEx; + + bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile, int32_t nDepth); + +public: + PConfig(); + ~PConfig(); + + inline bool LoadOptions(const char *nConfigTemplate[][2], const char *nConfigFile) + { return LoadOptions(nConfigTemplate, nConfigFile, 0); } + inline const std::string &GetOption(const char *Name) const { return GetOption((std::string) Name); } + const std::string &GetOption(const std::string Name) const; + int32_t GetOptionInt(const char *Name) const { return GetOptionInt((std::string) Name); } + int32_t GetOptionInt(const std::string Name) const; +}; + +// Max nested includes +#define CONFIG_MAXDEPTH 4 + +/* + The list of valid config options is now set in the array ConfigTemplate + A default value can be set for each option, whiches makes the option optionnal in config file + If no default value is set, the option is mandatory. + Duplicate option entries in config file are also checked, and only the first value is kept + Unkown options are rejected + Duplicates, unkown and default use generate a warning in logs but don't break options loading + Missing mandatory option generate an error in log and break option loading (imediate return false) + + The ConfigTemplate parameter must have the structure shown in the following exemple: + +const char* ConfigTemplate[][2] = { + // {option_name, default_value} if default_value is empty string, it means option is mandatory + // List ends with empty string for option_name + {"info_sql_host", "127.0.0.1"}, + {"info_sql_port", "3306"}, + {"info_sql_username", ""}, + {"info_sql_password", ""}, + {"", ""} // do not change this line (end mark) +}; + +*/ + +extern class PConfig* Config; diff --git a/TinNS/Source/Common/Console.cxx b/TinNS/Source/Common/Console.cxx index cc12a3b..a222c7c 100644 --- a/TinNS/Source/Common/Console.cxx +++ b/TinNS/Source/Common/Console.cxx @@ -1,148 +1,148 @@ -#include -#include -#include -#include "Common/Includes.hxx" - -PConsole::PConsole(const char *nLogFile) -{ - std::time(&mLastLogTime); - mLogFile.open(nLogFile); -} - -PConsole::~PConsole() -{ - Print("%s Shutdown complete", ColorText(GREEN, BLACK, "[Done]")); - mLogFile.close(); -} - -void PConsole::Print(const char *Fmt, ...) -{ - static char Str[2048]; - va_list args; - va_start(args, Fmt); - vsnprintf(Str, 2047, Fmt, args); - va_end(args); - - std::time(&mLastLogTime); - std::tm *now = std::localtime(&mLastLogTime); - - static char datestr[64]; - std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); - std::stringstream str; - str << datestr << Str << std::endl; - - std::printf("%s", str.str().c_str()); - mLogFile << str.str(); - mLogFile.flush(); -} - -void PConsole::Print(COLORS foreground, COLORS background, const char *Fmt, ...) -{ - static char Str[2048]; - va_list args; - va_start(args, Fmt); - vsnprintf(Str, 2047, Fmt, args); - va_end(args); - - char c_color[13]; - char c_reset[13]; - std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40); - std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40); - - std::time(&mLastLogTime); - std::tm *now = std::localtime(&mLastLogTime); - - static char datestr[64]; - std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); - std::stringstream str; - str << datestr << c_color << Str << c_reset << std::endl; - - std::printf("%s", str.str().c_str()); - mLogFile << str.str(); - - mLogFile.flush(); -} - -char *PConsole::ColorText(COLORS foreground, COLORS background, const char *Fmt, ...) -{ - static char Str[2048]; - va_list args; - va_start(args, Fmt); - vsnprintf(Str, 2047, Fmt, args); - va_end(args); - - char c_color[13]; - char c_reset[13]; - std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40); - std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40); - - static char returnbuffer[2048]; - strncpy (returnbuffer, c_color, 2048); - strncat (returnbuffer, Str, 2047 - strlen(returnbuffer)); - strncat (returnbuffer, c_reset, 2047 - strlen(returnbuffer)); - - return returnbuffer; -} - -void PConsole::LPrint(const char *Fmt, ...) -{ - static char Str[2048]; - va_list args; - va_start(args, Fmt); - vsnprintf(Str, 2047, Fmt, args); - va_end(args); - - std::time(&mLastLogTime); - std::tm *now = std::localtime(&mLastLogTime); - - static char datestr[64]; - std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); - std::stringstream str; - str << datestr << Str; - - std::printf("%s", str.str().c_str()); - mLogFile << str.str(); - mLogFile.flush(); -} - -void PConsole::LPrint(COLORS foreground, COLORS background, const char *Fmt, ...) -{ - static char Str[2048]; - va_list args; - va_start(args, Fmt); - vsnprintf(Str, 2047, Fmt, args); - va_end(args); - - char c_color[13]; - char c_reset[13]; - std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40); - std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40); - - std::stringstream str; - str << c_color << Str << c_reset; - - std::printf("%s", str.str().c_str()); - mLogFile << str.str(); - - mLogFile.flush(); -} - -void PConsole::LClose() -{ - std::stringstream str; - str << std::endl; - - std::printf("%s", str.str().c_str()); - mLogFile << str.str(); - - mLogFile.flush(); -} - -void PConsole::Update() -{ - // place a marker into the log each 15 minutes if no output has been generated - std::time_t t; - std::time(&t); - if(std::difftime(t, mLastLogTime) >= 900) - Print("--MARK--"); -} +#include +#include +#include +#include "Common/Includes.hxx" + +PConsole::PConsole(const char *nLogFile) +{ + std::time(&mLastLogTime); + mLogFile.open(nLogFile); +} + +PConsole::~PConsole() +{ + Print("%s Shutdown complete", ColorText(GREEN, BLACK, "[Done]")); + mLogFile.close(); +} + +void PConsole::Print(const char *Fmt, ...) +{ + static char Str[2048]; + va_list args; + va_start(args, Fmt); + vsnprintf(Str, 2047, Fmt, args); + va_end(args); + + std::time(&mLastLogTime); + std::tm *now = std::localtime(&mLastLogTime); + + static char datestr[64]; + std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + std::stringstream str; + str << datestr << Str << std::endl; + + std::printf("%s", str.str().c_str()); + mLogFile << str.str(); + mLogFile.flush(); +} + +void PConsole::Print(COLORS foreground, COLORS background, const char *Fmt, ...) +{ + static char Str[2048]; + va_list args; + va_start(args, Fmt); + vsnprintf(Str, 2047, Fmt, args); + va_end(args); + + char c_color[13]; + char c_reset[13]; + std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40); + std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40); + + std::time(&mLastLogTime); + std::tm *now = std::localtime(&mLastLogTime); + + static char datestr[64]; + std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + std::stringstream str; + str << datestr << c_color << Str << c_reset << std::endl; + + std::printf("%s", str.str().c_str()); + mLogFile << str.str(); + + mLogFile.flush(); +} + +char *PConsole::ColorText(COLORS foreground, COLORS background, const char *Fmt, ...) +{ + static char Str[2048]; + va_list args; + va_start(args, Fmt); + vsnprintf(Str, 2047, Fmt, args); + va_end(args); + + char c_color[13]; + char c_reset[13]; + std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40); + std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40); + + static char returnbuffer[2048]; + strncpy (returnbuffer, c_color, 2048); + strncat (returnbuffer, Str, 2047 - strlen(returnbuffer)); + strncat (returnbuffer, c_reset, 2047 - strlen(returnbuffer)); + + return returnbuffer; +} + +void PConsole::LPrint(const char *Fmt, ...) +{ + static char Str[2048]; + va_list args; + va_start(args, Fmt); + vsnprintf(Str, 2047, Fmt, args); + va_end(args); + + std::time(&mLastLogTime); + std::tm *now = std::localtime(&mLastLogTime); + + static char datestr[64]; + std::snprintf(datestr, 64, "%02i/%02i %02i:%02i:%02i ", now->tm_mon+1, now->tm_mday, now->tm_hour, now->tm_min, now->tm_sec); + std::stringstream str; + str << datestr << Str; + + std::printf("%s", str.str().c_str()); + mLogFile << str.str(); + mLogFile.flush(); +} + +void PConsole::LPrint(COLORS foreground, COLORS background, const char *Fmt, ...) +{ + static char Str[2048]; + va_list args; + va_start(args, Fmt); + vsnprintf(Str, 2047, Fmt, args); + va_end(args); + + char c_color[13]; + char c_reset[13]; + std::snprintf(c_color, 13, "%c[%d;%d;%dm", 0x1B, 0, foreground + 30, background + 40); + std::snprintf(c_reset, 13, "%c[%d;%d;%dm", 0x1B, 0, 37, 40); + + std::stringstream str; + str << c_color << Str << c_reset; + + std::printf("%s", str.str().c_str()); + mLogFile << str.str(); + + mLogFile.flush(); +} + +void PConsole::LClose() +{ + std::stringstream str; + str << std::endl; + + std::printf("%s", str.str().c_str()); + mLogFile << str.str(); + + mLogFile.flush(); +} + +void PConsole::Update() +{ + // place a marker into the log each 15 minutes if no output has been generated + std::time_t t; + std::time(&t); + if(std::difftime(t, mLastLogTime) >= 900) + Print("--MARK--"); +} diff --git a/TinNS/Source/Common/Console.hxx b/TinNS/Source/Common/Console.hxx index 8b610c4..fc477a7 100644 --- a/TinNS/Source/Common/Console.hxx +++ b/TinNS/Source/Common/Console.hxx @@ -1,35 +1,35 @@ -#pragma once - -#include -#include - -enum COLORS { - BLACK, - RED, - GREEN, - YELLOW, - BLUE, - MAGENTA, - CYAN, - WHITE -}; - -class PConsole { -private: - std::ofstream mLogFile; - time_t mLastLogTime; - -public: - PConsole(const char *nLogFile); - ~PConsole(); - void Print(const char *Fmt_, ...); - void Print(COLORS foreground, COLORS background, const char *Fmt_, ...); - char *ColorText(COLORS foreground, COLORS background, const char *Fmt, ...); - - void LPrint(const char *Fmt_, ...); - void LPrint(COLORS foreground, COLORS background, const char *Fmt_, ...); - void LClose(); - void Update(); -}; - -extern class PConsole *Console; +#pragma once + +#include +#include + +enum COLORS { + BLACK, + RED, + GREEN, + YELLOW, + BLUE, + MAGENTA, + CYAN, + WHITE +}; + +class PConsole { +private: + std::ofstream mLogFile; + time_t mLastLogTime; + +public: + PConsole(const char *nLogFile); + ~PConsole(); + void Print(const char *Fmt_, ...); + void Print(COLORS foreground, COLORS background, const char *Fmt_, ...); + char *ColorText(COLORS foreground, COLORS background, const char *Fmt, ...); + + void LPrint(const char *Fmt_, ...); + void LPrint(COLORS foreground, COLORS background, const char *Fmt_, ...); + void LClose(); + void Update(); +}; + +extern class PConsole *Console; diff --git a/TinNS/Source/Common/FileSystem.cxx b/TinNS/Source/Common/FileSystem.cxx index 633b79d..0cbc179 100644 --- a/TinNS/Source/Common/FileSystem.cxx +++ b/TinNS/Source/Common/FileSystem.cxx @@ -1,319 +1,319 @@ -#include -#include -#include -#include "Common/Includes.hxx" - -const int8_t DELIM = '/'; - -PFile::PFile() -{ - mDataSize=0; - mDataOffs=0; -} - -PFile::~PFile() -{ -} - -bool PFile::ReadData(FILE *F, uint32_t Size) -{ - mBuffer.reserve(Size); - std::fread(&mBuffer[0], 1, Size, F); - mDataSize = Size; - return true; -} - -bool PFile::ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize) -{ - std::vector temp; - temp.reserve(Size); - mBuffer.reserve(UncSize); - - std::fread(&temp[0], 1, Size, F); - - unsigned long us=UncSize; - unsigned long s=Size; - uncompress(reinterpret_cast(&mBuffer[0]), &us, reinterpret_cast(&temp[0]), s); - mDataSize=us; - return true; -} - -int PFile::Read(void *Dest, uint32_t DestSize) -{ - int m = std::min(mDataSize-mDataOffs, DestSize); - if (m <= 0) - return 0; - memcpy(Dest, &mBuffer[mDataOffs], m); - mDataOffs+=m; - return m; -} - -void PFile::Seek(uint32_t Offset) -{ - mDataOffs = std::min(mDataSize-1, Offset); -} - -std::string PFile::ReadString() -{ - int l=0; - int s=mDataOffs; - char last=0; - while(mDataOffs < mDataSize && last!='\n') - { - last=mBuffer[mDataOffs++]; - l++; - } - - char *str = new char[l+1]; - std::memcpy(str, &mBuffer[s], l); - str[l]=0; - - std::string Result = str; - delete str; - return Result; -} - -// --------------- - -PFileSystem::PFileSystem() -{ -} - -PFileSystem::~PFileSystem() -{ - for(PPakFiles::iterator i=mPaks.begin(); i!=mPaks.end(); i++) - { - PPakFileList *list = i->second; - for(PPakFileList::iterator j=list->begin(); j!=list->end(); j++) - delete j->second; - delete i->second; - } -} - -PFileSystem::PPakFileList* PFileSystem::CachePak(const std::string &Pak, FILE *F) -{ - PPakFiles::iterator n = mPaks.find(Pak); - if(n != mPaks.end()) - return n->second; - - if(!F) - return 0; - - PPakFileList *Result = 0; - - int off = std::ftell(F); - std::fseek(F, 0, SEEK_SET); - PPakHeader header; - std::fread(&header, 1, sizeof(header), F); - if(header.mID==0x3d458cde && header.mNumFiles > 0) - { - Result = new PPakFileList(); - for(int i=0; imFilename = new char[h->mNameLen+1]; - std::fread(h->mFilename, 1, h->mNameLen, F); - Result->insert(std::make_pair(h->mFilename, h)); - } - mPaks.insert(std::make_pair(Pak, Result)); -//Console->Print("%s: %i files registered", Pak.c_str(), header.mNumFiles); - } else - { - Console->Print("%s: invalid pakfile", Pak.c_str()); - } - std::fseek(F, off, SEEK_SET); - return Result; -} - -void PFileSystem::ClearCache() -{ - PFileSystem::PPakFiles::iterator nPak; - PFileSystem::PPakFileList::iterator nFList; - PPakFileHeader* FHeader; - PFileSystem::PPakFileList* FList; - - for( nPak = mPaks.begin(); nPak != mPaks.end(); nPak++) - { - FList = nPak->second; - for( nFList = FList->begin(); nFList != FList->end(); nFList++) - { - FHeader = nFList->second; - FList->erase(nFList); - delete[] FHeader->mFilename; - delete FHeader; - } - mPaks.erase(nPak); - delete FList; - } -} - -void splitpath(const std::string& file, std::string& path, std::string& name, std::string& ext) -{ - unsigned long pos = file.rfind(DELIM); - - if (pos == std::string::npos) - { - path = ""; - name = file; - } - else - { - path = file.substr(0, pos); - name = file.substr(pos + 1); - } - - pos = name.rfind('.'); - if (pos == std::string::npos) - { - ext = ""; - } - else - { - ext = name.substr(pos + 1); - name = name.substr(0, pos); - } -} - -PFile *PFileSystem::Open(const std::string& Package, const char *File, std::string BasePath) -{ - std::string name = ""; - std::string ext = ""; - std::string path = ""; - splitpath(File, path, name, ext); - - std::string pak2; - std::string name2; - - if ((BasePath == ".") || (BasePath == "./")) - { - BasePath = ""; - } - else - { - if (BasePath.substr(0, 2) == "./") - { - BasePath = BasePath.substr(2, BasePath.length() -2); - } - if ( BasePath[BasePath.length()-1] != '/' ) - { - BasePath += '/'; - } - } -//Console->Print("Basepath:%s", BasePath.c_str()); - - std::string pak = Package; - if(pak=="") - { - pak=path; - if (path.substr(0, 2) == "./") - { - path = path.substr(2, path.length() -2); - } - unsigned long pos = path.find(DELIM); - if (pos == std::string::npos) - { - pak2 = path; - name2 = name; - } - else - { - pak2 = path.substr(0, pos); - name2 = path.substr(pos + 1) + '\\' + name; - pos = name2.find(DELIM); - while (pos != std::string::npos) - { - name2[pos] = '\\'; - pos = name2.find(DELIM); - } - } - } - - std::stringstream package; - //package << pak << ".pak" << '\0'; - package << BasePath << pak2 << ".pak" << '\0'; - std::stringstream fname; - fname << BasePath << pak << '/' << name << "." << ext << '\0'; - std::stringstream pakname; - pakname << BasePath << pak << "/pak_" << name << "." << ext << '\0'; - - std::FILE *f = std::fopen(fname.str().c_str(), "rb"); - if(f) - { - PFile *Result = new PFile(); - std::fseek(f, 0, SEEK_END); - int s = std::ftell(f); - std::fseek(f, 0, SEEK_SET); - Result->ReadData(f, s); - std::fclose(f); - return Result; - } -//else -// Console->Print("File not found:%s", fname.str().c_str()); - f = std::fopen(pakname.str().c_str(), "rb"); - if(f) - { - PFile *Result = new PFile(); - std::fseek(f, 0, SEEK_END); - int s = std::ftell(f)-16; - std::fseek(f, 12, SEEK_SET); - int os; - std::fread(&os, 1, 4, f); - Result->ReadUnpakData(f, s, os); - std::fclose(f); - return Result; - } -//else -// Console->Print("Pak_ not found:%s", pakname.str().c_str()); - -//Console->Print("Serching package %s, file %s.%s", package.str().c_str(), name2.c_str(), ext.c_str()); - f = std::fopen(package.str().c_str(), "rb"); - if(f) - { - //std::string filename = name; - std::string filename = name2 + "." + ext; - //filename.append(ext); - - PPakFileHeader *file = 0; - PPakFileList *list = CachePak(std::string(package.str()), f); - for(PPakFileList::iterator i=list->begin(); i!=list->end(); i++) - { - PPakFileHeader *h = i->second; - if(!strcasecmp(i->first.c_str(), filename.c_str())) - { - file = h; - break; - } - } - PFile *Result = 0; - if(list && file) - { - Result = new PFile(); - std::fseek(f, file->mOffset, SEEK_SET); - Result->ReadUnpakData(f, file->mCompressedSize, file->mUncompressedSize); -//Console->Print("%s, %s: file found", package.str().c_str(), filename.c_str()); - } - else - { - if(!list) - //Console->Print("%s, %s: pak error", Package.c_str(), File); - Console->Print("%s, %s: pak error", package.str().c_str(), File); -//else -//if(!file) -//Console->Print("%s, %s: file not found", Package.c_str(), File); -// Console->Print("%s, %s: file not found", package.str().c_str(), filename.c_str()); - } - - std::fclose(f); - return Result; - } - - return 0; -} - -bool PFileSystem::Close(PFile *File) -{ - delete File; - return true; -} - +#include +#include +#include +#include "Common/Includes.hxx" + +const int8_t DELIM = '/'; + +PFile::PFile() +{ + mDataSize=0; + mDataOffs=0; +} + +PFile::~PFile() +{ +} + +bool PFile::ReadData(FILE *F, uint32_t Size) +{ + mBuffer.reserve(Size); + std::fread(&mBuffer[0], 1, Size, F); + mDataSize = Size; + return true; +} + +bool PFile::ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize) +{ + std::vector temp; + temp.reserve(Size); + mBuffer.reserve(UncSize); + + std::fread(&temp[0], 1, Size, F); + + unsigned long us=UncSize; + unsigned long s=Size; + uncompress(reinterpret_cast(&mBuffer[0]), &us, reinterpret_cast(&temp[0]), s); + mDataSize=us; + return true; +} + +int PFile::Read(void *Dest, uint32_t DestSize) +{ + int m = std::min(mDataSize-mDataOffs, DestSize); + if (m <= 0) + return 0; + memcpy(Dest, &mBuffer[mDataOffs], m); + mDataOffs+=m; + return m; +} + +void PFile::Seek(uint32_t Offset) +{ + mDataOffs = std::min(mDataSize-1, Offset); +} + +std::string PFile::ReadString() +{ + int l=0; + int s=mDataOffs; + char last=0; + while(mDataOffs < mDataSize && last!='\n') + { + last=mBuffer[mDataOffs++]; + l++; + } + + char *str = new char[l+1]; + std::memcpy(str, &mBuffer[s], l); + str[l]=0; + + std::string Result = str; + delete str; + return Result; +} + +// --------------- + +PFileSystem::PFileSystem() +{ +} + +PFileSystem::~PFileSystem() +{ + for(PPakFiles::iterator i=mPaks.begin(); i!=mPaks.end(); i++) + { + PPakFileList *list = i->second; + for(PPakFileList::iterator j=list->begin(); j!=list->end(); j++) + delete j->second; + delete i->second; + } +} + +PFileSystem::PPakFileList* PFileSystem::CachePak(const std::string &Pak, FILE *F) +{ + PPakFiles::iterator n = mPaks.find(Pak); + if(n != mPaks.end()) + return n->second; + + if(!F) + return 0; + + PPakFileList *Result = 0; + + int off = std::ftell(F); + std::fseek(F, 0, SEEK_SET); + PPakHeader header; + std::fread(&header, 1, sizeof(header), F); + if(header.mID==0x3d458cde && header.mNumFiles > 0) + { + Result = new PPakFileList(); + for(int i=0; imFilename = new char[h->mNameLen+1]; + std::fread(h->mFilename, 1, h->mNameLen, F); + Result->insert(std::make_pair(h->mFilename, h)); + } + mPaks.insert(std::make_pair(Pak, Result)); +//Console->Print("%s: %i files registered", Pak.c_str(), header.mNumFiles); + } else + { + Console->Print("%s: invalid pakfile", Pak.c_str()); + } + std::fseek(F, off, SEEK_SET); + return Result; +} + +void PFileSystem::ClearCache() +{ + PFileSystem::PPakFiles::iterator nPak; + PFileSystem::PPakFileList::iterator nFList; + PPakFileHeader* FHeader; + PFileSystem::PPakFileList* FList; + + for( nPak = mPaks.begin(); nPak != mPaks.end(); nPak++) + { + FList = nPak->second; + for( nFList = FList->begin(); nFList != FList->end(); nFList++) + { + FHeader = nFList->second; + FList->erase(nFList); + delete[] FHeader->mFilename; + delete FHeader; + } + mPaks.erase(nPak); + delete FList; + } +} + +void splitpath(const std::string& file, std::string& path, std::string& name, std::string& ext) +{ + unsigned long pos = file.rfind(DELIM); + + if (pos == std::string::npos) + { + path = ""; + name = file; + } + else + { + path = file.substr(0, pos); + name = file.substr(pos + 1); + } + + pos = name.rfind('.'); + if (pos == std::string::npos) + { + ext = ""; + } + else + { + ext = name.substr(pos + 1); + name = name.substr(0, pos); + } +} + +PFile *PFileSystem::Open(const std::string& Package, const char *File, std::string BasePath) +{ + std::string name = ""; + std::string ext = ""; + std::string path = ""; + splitpath(File, path, name, ext); + + std::string pak2; + std::string name2; + + if ((BasePath == ".") || (BasePath == "./")) + { + BasePath = ""; + } + else + { + if (BasePath.substr(0, 2) == "./") + { + BasePath = BasePath.substr(2, BasePath.length() -2); + } + if ( BasePath[BasePath.length()-1] != '/' ) + { + BasePath += '/'; + } + } +//Console->Print("Basepath:%s", BasePath.c_str()); + + std::string pak = Package; + if(pak=="") + { + pak=path; + if (path.substr(0, 2) == "./") + { + path = path.substr(2, path.length() -2); + } + unsigned long pos = path.find(DELIM); + if (pos == std::string::npos) + { + pak2 = path; + name2 = name; + } + else + { + pak2 = path.substr(0, pos); + name2 = path.substr(pos + 1) + '\\' + name; + pos = name2.find(DELIM); + while (pos != std::string::npos) + { + name2[pos] = '\\'; + pos = name2.find(DELIM); + } + } + } + + std::stringstream package; + //package << pak << ".pak" << '\0'; + package << BasePath << pak2 << ".pak" << '\0'; + std::stringstream fname; + fname << BasePath << pak << '/' << name << "." << ext << '\0'; + std::stringstream pakname; + pakname << BasePath << pak << "/pak_" << name << "." << ext << '\0'; + + std::FILE *f = std::fopen(fname.str().c_str(), "rb"); + if(f) + { + PFile *Result = new PFile(); + std::fseek(f, 0, SEEK_END); + int s = std::ftell(f); + std::fseek(f, 0, SEEK_SET); + Result->ReadData(f, s); + std::fclose(f); + return Result; + } +//else +// Console->Print("File not found:%s", fname.str().c_str()); + f = std::fopen(pakname.str().c_str(), "rb"); + if(f) + { + PFile *Result = new PFile(); + std::fseek(f, 0, SEEK_END); + int s = std::ftell(f)-16; + std::fseek(f, 12, SEEK_SET); + int os; + std::fread(&os, 1, 4, f); + Result->ReadUnpakData(f, s, os); + std::fclose(f); + return Result; + } +//else +// Console->Print("Pak_ not found:%s", pakname.str().c_str()); + +//Console->Print("Serching package %s, file %s.%s", package.str().c_str(), name2.c_str(), ext.c_str()); + f = std::fopen(package.str().c_str(), "rb"); + if(f) + { + //std::string filename = name; + std::string filename = name2 + "." + ext; + //filename.append(ext); + + PPakFileHeader *file = 0; + PPakFileList *list = CachePak(std::string(package.str()), f); + for(PPakFileList::iterator i=list->begin(); i!=list->end(); i++) + { + PPakFileHeader *h = i->second; + if(!strcasecmp(i->first.c_str(), filename.c_str())) + { + file = h; + break; + } + } + PFile *Result = 0; + if(list && file) + { + Result = new PFile(); + std::fseek(f, file->mOffset, SEEK_SET); + Result->ReadUnpakData(f, file->mCompressedSize, file->mUncompressedSize); +//Console->Print("%s, %s: file found", package.str().c_str(), filename.c_str()); + } + else + { + if(!list) + //Console->Print("%s, %s: pak error", Package.c_str(), File); + Console->Print("%s, %s: pak error", package.str().c_str(), File); +//else +//if(!file) +//Console->Print("%s, %s: file not found", Package.c_str(), File); +// Console->Print("%s, %s: file not found", package.str().c_str(), filename.c_str()); + } + + std::fclose(f); + return Result; + } + + return 0; +} + +bool PFileSystem::Close(PFile *File) +{ + delete File; + return true; +} + diff --git a/TinNS/Source/Common/FileSystem.hxx b/TinNS/Source/Common/FileSystem.hxx index 00366bd..6cd0100 100644 --- a/TinNS/Source/Common/FileSystem.hxx +++ b/TinNS/Source/Common/FileSystem.hxx @@ -1,55 +1,55 @@ -#pragma once - -#include -#include -#include - -class PFile { - friend class PFileSystem; -private: - std::vector mBuffer; - uint32_t mDataSize; - uint32_t mDataOffs; - bool ReadData(FILE *F, uint32_t Size); - bool ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize); - -public: - PFile(); - ~PFile(); - inline bool Eof() { return mDataOffs>=mDataSize; } - int Read(void *Dest, uint32_t DestSize); - void Seek(uint32_t Offset); - std::string ReadString(); - inline uint32_t GetSize() const { return mDataSize; } -}; - -#pragma pack(push, 1) -struct PPakHeader { - int mID; - int mNumFiles; -}; - -struct PPakFileHeader { - int mUnknown0; - int mOffset; - int mCompressedSize; - int mUncompressedSize; - int mNameLen; // including 0 - char *mFilename; -}; -#pragma pack(pop) - -class PFileSystem { -private: - typedef std::map PPakFileList; - typedef std::map PPakFiles; - PPakFiles mPaks; - PPakFileList *CachePak(const std::string &Pak, FILE *F); - -public: - PFileSystem(); - ~PFileSystem(); - PFile *Open(const std::string &Package, const char *File, std::string BasePath); - bool Close(PFile *File); - void ClearCache(); -}; +#pragma once + +#include +#include +#include + +class PFile { + friend class PFileSystem; +private: + std::vector mBuffer; + uint32_t mDataSize; + uint32_t mDataOffs; + bool ReadData(FILE *F, uint32_t Size); + bool ReadUnpakData(FILE *F, uint32_t Size, uint32_t UncSize); + +public: + PFile(); + ~PFile(); + inline bool Eof() { return mDataOffs>=mDataSize; } + int Read(void *Dest, uint32_t DestSize); + void Seek(uint32_t Offset); + std::string ReadString(); + inline uint32_t GetSize() const { return mDataSize; } +}; + +#pragma pack(push, 1) +struct PPakHeader { + int mID; + int mNumFiles; +}; + +struct PPakFileHeader { + int mUnknown0; + int mOffset; + int mCompressedSize; + int mUncompressedSize; + int mNameLen; // including 0 + char *mFilename; +}; +#pragma pack(pop) + +class PFileSystem { +private: + typedef std::map PPakFileList; + typedef std::map PPakFiles; + PPakFiles mPaks; + PPakFileList *CachePak(const std::string &Pak, FILE *F); + +public: + PFileSystem(); + ~PFileSystem(); + PFile *Open(const std::string &Package, const char *File, std::string BasePath); + bool Close(PFile *File); + void ClearCache(); +}; diff --git a/TinNS/Source/Common/Misc.cxx b/TinNS/Source/Common/Misc.cxx index 1f8fa3b..28b8049 100644 --- a/TinNS/Source/Common/Misc.cxx +++ b/TinNS/Source/Common/Misc.cxx @@ -1,266 +1,266 @@ -#include -#include -#include -#include "Common/Includes.hxx" - -uint32_t IPStringToDWord( const char *IP ) -{ - if ( !IP ) - return 0; - - uint32_t a, b, c, d; - if ( std::sscanf( IP, "%u.%u.%u.%u", &a, &b, &c, &d ) != 4 ) - return 0; - - return ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a; -} - -char *IPlongToString( const uint32_t IP ) -{ - struct in_addr in_IP; - - in_IP.s_addr = IP; - return inet_ntoa( in_IP ); -} - -//NEW -//this function allow to print a packet -//just for tracking values -void PrintPacket( uint8_t *Packet, int PacketSize ) -{ - Console->Print( "inside : PrintPacket" ); - - if ( PacketSize < 1 ){Console->Print( "Wrong packet" );}//do nothing - else - { - Console->Print( "PacketSize is : %d", PacketSize ); - - uint8_t value = 0; - for ( int i = 0;i < PacketSize;i++ ) - { - value = *( uint8_t* ) & Packet[i]; - Console->Print( "value[%d] is : %x", i, value ); - } - } - -}//end function - -void CleanUpString(std::string *nString) -{ - if(!nString) - return; - - // Skip if string is >" "< - if(nString->length() > 3) - { - size_t tfound; - std::string t_replacechr ("\""); - - tfound = nString->find(t_replacechr); - while(tfound != std::string::npos) - { - nString->replace(tfound, 1, " "); - tfound = nString->find( t_replacechr, tfound +1 ); - } - // Skip if string consists of spaces now - if(strncmp(nString->c_str(), " ", 3) == 0) - { - // Set empty - *nString = ""; - } - else - { - // Trim spaces - Trim(nString); - } - } - else - { - *nString = ""; - } -} - - -void Trim( char *t ) -{ - RTrim( t ); - if ( strlen( t ) ) - LTrim( t ); -} - -void Trim( std::string *stString ) -{ - RTrim( stString ); - if ( stString->length() ) - LTrim( stString ); -} - -void RTrim( char *t ) -{ - char *buf; - - if ( !strlen( t ) ) return; - - buf = t; - buf += strlen( t ) - 1; - - while ( *buf == ' ' && strlen( t ) ) - *buf-- = '\0'; -} - -void RTrim( std::string *stString ) -{ - int i; //Count VAR - - if ( !stString->length() ) //If There Is No Length - return; - - i = stString->length() - 1; //Set The Counter To The String Length -1 - - while ( stString->substr( i, 1 ) == " " ) //While There Is Still " " - { - *stString = stString->substr( 0, i ); //Remove Off The End Of The String - i--; //Advance The Counter - } - -} - -void LTrim( char *t ) -{ - char tmp[2048]; //Temp Char VAR - char *buf; //Pointer - - if ( !strlen( t ) ) return; - - strncpy( tmp, t, 2048 ); - tmp[2047] = 0; - buf = tmp; - - while ( *buf == ' ' && strlen( buf ) ) *buf++; - - strncpy( t, buf, 2048 ); // just because without length is forbidden ! -} - -void LTrim( std::string *stString ) -{ - unsigned int i; //Count VAR - std::string buf; //Temp String VAR - - if ( !stString->length() ) return; //If The Length Is 0 - - i = 0; //Setup The Counter VAR - - while ( stString->substr( i, 1 ) == " " ) //While " " - i++; //Increase Counter - - if ( i == stString->length() ) //If The Whole String Is " " - { - *stString = ""; //Return Blank String - return; - } - - try - { - *stString = stString->substr( i, stString->length() - i ); //Send The String Back Without The Spaces - } - catch ( ... ) - { - *stString = ""; //Return Blank String - return; - } - -} - -std::string GetAccessString( int level ) -{ - switch ( level ) - { - case 0: return "Unregistered"; - case 1: return "Registered"; - case 30: return "Volunteer"; - case 50: return "Gamemaster"; - case 100: return "Administrator"; - } - return "Error"; -} - -std::string &Ssprintf( const char *fmt, ... ) -{ - static std::string tmpstring; - char buff[1024]; - va_list args; - - va_start( args, fmt ); - vsnprintf( buff, 1024, fmt, args ); - va_end( args ); - buff[1023] = '\0'; - tmpstring = buff; - return tmpstring; -} - -uint16_t DistanceApprox( const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2 ) -{ - uint16_t DX, DY, DZ, DMax; - uint32_t DMinSum, DApprox; - - DMax = DX = ( x1 >= x2 ) ? x1 - x2 : x2 - x1; - DMinSum = DY = ( y1 >= y2 ) ? y1 - y2 : y2 - y1; - DZ = ( z1 >= z2 ) ? z1 - z2 : z2 - z1; - if ( DX < DY ) - { - DMax = DY; - DMinSum = DX; - } - if ( DMax < DZ ) - { - DMinSum += DMax; - DMax = DZ; - } - else - { - DMinSum += DZ; - } - - DApprox = DMax + ( uint32_t )( 0.33 * DMinSum ); - if ( DApprox > 65535 ) - { - DApprox = 65535; - } - - // We use Dapprox = max(dx, dy) + K * min(dx, dy) - // Dapprox = (DX > DY) ? DX + (DY >> 1) : DY + (DX >> 1); // Fastest, but max error on dist is around 10% real dist - //Dapprox = (u16)((DX > DY) ? DX + 0.33*DY : DY + 0.33*DX); // max error on dist is around 5%, which should be enough - /* - // for dist approx debug - float fDX, fDY, fDZ, fDist; - fDX=(x1 - x2); - fDY=(y1 - y2); - fDZ=(z1 - z2); - fDist=sqrt(fDX*fDX + fDY*fDY + fDZ*fDZ); - if (fDist != 0) Console->Print("Dist: %f\tApprox: %d\tError: %d (%d%)", fDist, DApprox, (int)(DApprox-fDist), (int)(100*(DApprox-fDist)/fDist)); - */ - - return ( uint16_t )DApprox; -} - -/*** Portable pseudo-random number generator ***/ -// until native standardized C++ lib support - -uint32_t mInternalRand = 1; - -void InitRandom( uint32_t nInitialisationValue ) -{ - mInternalRand = nInitialisationValue; -} - -uint16_t GetRandom( uint16_t MaxVal, uint16_t MinVal ) -{ - mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage - return ( uint16_t )( MinVal + (( mInternalRand >> 16 ) % 32768 % ( MaxVal - MinVal + 1 ) ) ); -} - -float GetRandomFloat() -{ - mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage - return (( float )(( mInternalRand >> 16 ) % 32768 ) / ( float )32768 ); -} +#include +#include +#include +#include "Common/Includes.hxx" + +uint32_t IPStringToDWord( const char *IP ) +{ + if ( !IP ) + return 0; + + uint32_t a, b, c, d; + if ( std::sscanf( IP, "%u.%u.%u.%u", &a, &b, &c, &d ) != 4 ) + return 0; + + return ( d << 24 ) | ( c << 16 ) | ( b << 8 ) | a; +} + +char *IPlongToString( const uint32_t IP ) +{ + struct in_addr in_IP; + + in_IP.s_addr = IP; + return inet_ntoa( in_IP ); +} + +//NEW +//this function allow to print a packet +//just for tracking values +void PrintPacket( uint8_t *Packet, int PacketSize ) +{ + Console->Print( "inside : PrintPacket" ); + + if ( PacketSize < 1 ){Console->Print( "Wrong packet" );}//do nothing + else + { + Console->Print( "PacketSize is : %d", PacketSize ); + + uint8_t value = 0; + for ( int i = 0;i < PacketSize;i++ ) + { + value = *( uint8_t* ) & Packet[i]; + Console->Print( "value[%d] is : %x", i, value ); + } + } + +}//end function + +void CleanUpString(std::string *nString) +{ + if(!nString) + return; + + // Skip if string is >" "< + if(nString->length() > 3) + { + size_t tfound; + std::string t_replacechr ("\""); + + tfound = nString->find(t_replacechr); + while(tfound != std::string::npos) + { + nString->replace(tfound, 1, " "); + tfound = nString->find( t_replacechr, tfound +1 ); + } + // Skip if string consists of spaces now + if(strncmp(nString->c_str(), " ", 3) == 0) + { + // Set empty + *nString = ""; + } + else + { + // Trim spaces + Trim(nString); + } + } + else + { + *nString = ""; + } +} + + +void Trim( char *t ) +{ + RTrim( t ); + if ( strlen( t ) ) + LTrim( t ); +} + +void Trim( std::string *stString ) +{ + RTrim( stString ); + if ( stString->length() ) + LTrim( stString ); +} + +void RTrim( char *t ) +{ + char *buf; + + if ( !strlen( t ) ) return; + + buf = t; + buf += strlen( t ) - 1; + + while ( *buf == ' ' && strlen( t ) ) + *buf-- = '\0'; +} + +void RTrim( std::string *stString ) +{ + int i; //Count VAR + + if ( !stString->length() ) //If There Is No Length + return; + + i = stString->length() - 1; //Set The Counter To The String Length -1 + + while ( stString->substr( i, 1 ) == " " ) //While There Is Still " " + { + *stString = stString->substr( 0, i ); //Remove Off The End Of The String + i--; //Advance The Counter + } + +} + +void LTrim( char *t ) +{ + char tmp[2048]; //Temp Char VAR + char *buf; //Pointer + + if ( !strlen( t ) ) return; + + strncpy( tmp, t, 2048 ); + tmp[2047] = 0; + buf = tmp; + + while ( *buf == ' ' && strlen( buf ) ) *buf++; + + strncpy( t, buf, 2048 ); // just because without length is forbidden ! +} + +void LTrim( std::string *stString ) +{ + unsigned int i; //Count VAR + std::string buf; //Temp String VAR + + if ( !stString->length() ) return; //If The Length Is 0 + + i = 0; //Setup The Counter VAR + + while ( stString->substr( i, 1 ) == " " ) //While " " + i++; //Increase Counter + + if ( i == stString->length() ) //If The Whole String Is " " + { + *stString = ""; //Return Blank String + return; + } + + try + { + *stString = stString->substr( i, stString->length() - i ); //Send The String Back Without The Spaces + } + catch ( ... ) + { + *stString = ""; //Return Blank String + return; + } + +} + +std::string GetAccessString( int level ) +{ + switch ( level ) + { + case 0: return "Unregistered"; + case 1: return "Registered"; + case 30: return "Volunteer"; + case 50: return "Gamemaster"; + case 100: return "Administrator"; + } + return "Error"; +} + +std::string &Ssprintf( const char *fmt, ... ) +{ + static std::string tmpstring; + char buff[1024]; + va_list args; + + va_start( args, fmt ); + vsnprintf( buff, 1024, fmt, args ); + va_end( args ); + buff[1023] = '\0'; + tmpstring = buff; + return tmpstring; +} + +uint16_t DistanceApprox( const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2 ) +{ + uint16_t DX, DY, DZ, DMax; + uint32_t DMinSum, DApprox; + + DMax = DX = ( x1 >= x2 ) ? x1 - x2 : x2 - x1; + DMinSum = DY = ( y1 >= y2 ) ? y1 - y2 : y2 - y1; + DZ = ( z1 >= z2 ) ? z1 - z2 : z2 - z1; + if ( DX < DY ) + { + DMax = DY; + DMinSum = DX; + } + if ( DMax < DZ ) + { + DMinSum += DMax; + DMax = DZ; + } + else + { + DMinSum += DZ; + } + + DApprox = DMax + ( uint32_t )( 0.33 * DMinSum ); + if ( DApprox > 65535 ) + { + DApprox = 65535; + } + + // We use Dapprox = max(dx, dy) + K * min(dx, dy) + // Dapprox = (DX > DY) ? DX + (DY >> 1) : DY + (DX >> 1); // Fastest, but max error on dist is around 10% real dist + //Dapprox = (u16)((DX > DY) ? DX + 0.33*DY : DY + 0.33*DX); // max error on dist is around 5%, which should be enough + /* + // for dist approx debug + float fDX, fDY, fDZ, fDist; + fDX=(x1 - x2); + fDY=(y1 - y2); + fDZ=(z1 - z2); + fDist=sqrt(fDX*fDX + fDY*fDY + fDZ*fDZ); + if (fDist != 0) Console->Print("Dist: %f\tApprox: %d\tError: %d (%d%)", fDist, DApprox, (int)(DApprox-fDist), (int)(100*(DApprox-fDist)/fDist)); + */ + + return ( uint16_t )DApprox; +} + +/*** Portable pseudo-random number generator ***/ +// until native standardized C++ lib support + +uint32_t mInternalRand = 1; + +void InitRandom( uint32_t nInitialisationValue ) +{ + mInternalRand = nInitialisationValue; +} + +uint16_t GetRandom( uint16_t MaxVal, uint16_t MinVal ) +{ + mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage + return ( uint16_t )( MinVal + (( mInternalRand >> 16 ) % 32768 % ( MaxVal - MinVal + 1 ) ) ); +} + +float GetRandomFloat() +{ + mInternalRand = mInternalRand * 1103515245 + 12345; //from rand() manpage + return (( float )(( mInternalRand >> 16 ) % 32768 ) / ( float )32768 ); +} diff --git a/TinNS/Source/Common/Misc.hxx b/TinNS/Source/Common/Misc.hxx index 33bf941..e62b864 100644 --- a/TinNS/Source/Common/Misc.hxx +++ b/TinNS/Source/Common/Misc.hxx @@ -1,29 +1,29 @@ -#pragma once - -#include -#include - -uint32_t IPStringToDWord(const char *IP); -char *IPlongToString(const uint32_t IP); -std::string GetAccessString(int32_t level); -//void GetSVNRev(char *version); - -void PrintPacket(uint8_t *Packet, int32_t PacketSize); - -// Cleanup for strings read from .def -void CleanUpString(std::string *nString); -void Trim(char *t); -void Trim(std::string *stString); -void RTrim(char *t); -void RTrim(std::string *stString); -void LTrim(char *t); -void LTrim(std::string *stString); -std::string &Ssprintf(const char *fmt, ...); - -uint16_t DistanceApprox(const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2); -float Distance(const float x1, const float y1, const float z1, const float x2, const float y2, const float z2); -float Distance(const float x1, const float y1, const float x2, const float y2); // 2D only version - -void InitRandom(uint32_t nInitialisationValue); -uint16_t GetRandom(uint16_t MaxVal, uint16_t MinVal = 0); // u16 value between MinVal and MaxVal (inclusive) with max range 32768 -float GetRandomFloat(); // f32 value between 0 and 1 +#pragma once + +#include +#include + +uint32_t IPStringToDWord(const char *IP); +char *IPlongToString(const uint32_t IP); +std::string GetAccessString(int32_t level); +//void GetSVNRev(char *version); + +void PrintPacket(uint8_t *Packet, int32_t PacketSize); + +// Cleanup for strings read from .def +void CleanUpString(std::string *nString); +void Trim(char *t); +void Trim(std::string *stString); +void RTrim(char *t); +void RTrim(std::string *stString); +void LTrim(char *t); +void LTrim(std::string *stString); +std::string &Ssprintf(const char *fmt, ...); + +uint16_t DistanceApprox(const uint16_t x1, const uint16_t y1, const uint16_t z1, const uint16_t x2, const uint16_t y2, const uint16_t z2); +float Distance(const float x1, const float y1, const float z1, const float x2, const float y2, const float z2); +float Distance(const float x1, const float y1, const float x2, const float y2); // 2D only version + +void InitRandom(uint32_t nInitialisationValue); +uint16_t GetRandom(uint16_t MaxVal, uint16_t MinVal = 0); // u16 value between MinVal and MaxVal (inclusive) with max range 32768 +float GetRandomFloat(); // f32 value between 0 and 1 diff --git a/TinNS/Source/Common/Mutex.hxx b/TinNS/Source/Common/Mutex.hxx index 8e388fb..a2ca8c8 100644 --- a/TinNS/Source/Common/Mutex.hxx +++ b/TinNS/Source/Common/Mutex.hxx @@ -1,43 +1,43 @@ -#pragma once - -#include - -class Mutex { -private: - mutable pthread_mutex_t mut; - - void operator = (Mutex &mut) {} - - Mutex(const Mutex &mut) {} - -public: - Mutex() - { - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mut, &attr); - pthread_mutexattr_destroy(&attr); - } - - virtual ~Mutex() - { - pthread_mutex_unlock(&mut); - pthread_mutex_destroy(&mut); - } - - int Lock() const - { - return (pthread_mutex_lock(&mut)); - } - - int TryLock() const - { - return (pthread_mutex_trylock(&mut)); - } - - int Unlock() const - { - return (pthread_mutex_unlock(&mut)); - } -}; +#pragma once + +#include + +class Mutex { +private: + mutable pthread_mutex_t mut; + + void operator = (Mutex &mut) {} + + Mutex(const Mutex &mut) {} + +public: + Mutex() + { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mut, &attr); + pthread_mutexattr_destroy(&attr); + } + + virtual ~Mutex() + { + pthread_mutex_unlock(&mut); + pthread_mutex_destroy(&mut); + } + + int Lock() const + { + return (pthread_mutex_lock(&mut)); + } + + int TryLock() const + { + return (pthread_mutex_trylock(&mut)); + } + + int Unlock() const + { + return (pthread_mutex_unlock(&mut)); + } +}; diff --git a/TinNS/Source/Common/Semaphore.hxx b/TinNS/Source/Common/Semaphore.hxx index 023982d..89f71b6 100644 --- a/TinNS/Source/Common/Semaphore.hxx +++ b/TinNS/Source/Common/Semaphore.hxx @@ -1,49 +1,49 @@ -#pragma once - -#include - -class Semaphore { -private: - sem_t sem; - -public: - Semaphore(int init = 0) - { - sem_init(&sem, 0, init); - } - - virtual ~Semaphore() - { - sem_destroy(&sem); - } - - void Wait() const - { - sem_wait((sem_t *)&sem); - } - - int TryWait() const - { - return (sem_trywait((sem_t *)&sem) ? errno : 0); - } - - int Post() const - { - return (sem_post((sem_t *)&sem) ? errno : 0); - } - - int GetValue() const - { - int val = -1; - - sem_getvalue((sem_t *)&sem, &val); - - return (val); - } - - void Reset(int init = 0) - { - sem_destroy(&sem); - sem_init(&sem, 0, init); - } -}; +#pragma once + +#include + +class Semaphore { +private: + sem_t sem; + +public: + Semaphore(int init = 0) + { + sem_init(&sem, 0, init); + } + + virtual ~Semaphore() + { + sem_destroy(&sem); + } + + void Wait() const + { + sem_wait((sem_t *)&sem); + } + + int TryWait() const + { + return (sem_trywait((sem_t *)&sem) ? errno : 0); + } + + int Post() const + { + return (sem_post((sem_t *)&sem) ? errno : 0); + } + + int GetValue() const + { + int val = -1; + + sem_getvalue((sem_t *)&sem, &val); + + return (val); + } + + void Reset(int init = 0) + { + sem_destroy(&sem); + sem_init(&sem, 0, init); + } +}; diff --git a/TinNS/Source/Common/Thread.hxx b/TinNS/Source/Common/Thread.hxx index 70c0e8a..5ddb652 100644 --- a/TinNS/Source/Common/Thread.hxx +++ b/TinNS/Source/Common/Thread.hxx @@ -1,166 +1,166 @@ -#pragma once - -#include -#include -#include - -#define INVALID_HANDLE 0 - -typedef void *(*pthread_fn)(void*); - -template -class Thread { - private: - typedef struct Instance; - - public: - typedef Thread_T &Thread_; - typedef const Thread_T &Thread__; - typedef pthread_t Handle; - typedef void (*Handler)(Thread_); - - protected: - Thread() { - } - - virtual void ThreadMain(Thread_) = 0; - - static void Exit() { - pthread_exit(0); - } - - static void TestCancel() { - pthread_testcancel(); - } - - static Handle Self() { - return(Handle)pthread_self(); - } - - public: - static int Create(const Handler &Func, Thread__ Param, Handle *const &H = 0, - const bool &CreateDetached = false, const unsigned int &StackSize = 0, - const bool &CancelEnable = false, const bool &CancelAsync = false) { - M_Create().Lock(); - pthread_attr_t attr; - pthread_attr_init(&attr); - - if(CreateDetached) - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - if(StackSize) - pthread_attr_setstacksize(&attr, StackSize); - - Instance I(Param, 0, Func, CancelEnable, CancelAsync); - - Handle h = INVALID_HANDLE; - int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I); - - pthread_attr_destroy(&attr); - - if(H) - *H = h; - if(!run) - S_Create().Wait(); - - M_Create().Unlock(); - - return(errno); - } - - int Create(Thread__ Param, Handle *const &H = 0, const bool &CreateDetached = false, - const unsigned int &StackSize = 0, const bool &CancelEnable = false, - const bool &CancelAsync = false ) const { - M_Create().Lock(); - pthread_attr_t attr; - pthread_attr_init(&attr); - - if(CreateDetached) - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - if(StackSize) - pthread_attr_setstacksize(&attr, StackSize); - - Instance I(Param, const_cast(this), 0, CancelEnable, CancelAsync); - - Handle h = INVALID_HANDLE; - int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I); - - pthread_attr_destroy(&attr); - - if(H) - *H = h; - if(!run) - S_Create().Wait(); - - M_Create().Unlock(); - - return(errno); - } - - static int Join(Handle H) { - return(pthread_join(H, 0)); - } - - static int Kill(Handle H) { - return(pthread_cancel(H)); - } - - static int Detach(Handle H) { - return(pthread_detach(H)); - } - - private: - static const Mutex &M_Create() { - static Mutex M; - - return(M); - } - - static const Semaphore &S_Create() { - static Semaphore S; - - return(S); - } - - static void ThreadMainHandler(Instance *Param) { - Instance I(*Param); - Thread_T Data(I.Data); - - S_Create().Post(); - - if(I.Flags & 1) { - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - - if(I.Flags & 2) - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - else - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); - } - else - pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); - - if(I.Owner) - I.Owner->ThreadMain(Data); - else - I.pFN(Data); - - return(0); - } - - struct Instance { - Instance(Thread__ P, Thread *const &O, const Thread::Handler &pH = 0, - const bool &CE = false, const bool &CA = false) : Data(P), Owner(O), pFN(pH), - Flags(0) { - if(CE) - Flags |= 1; - if(CA) - Flags |= 2; - } - - Thread__ Data; - Thread *Owner; - Handler pFN; - unsigned char Flags; - }; -}; +#pragma once + +#include +#include +#include + +#define INVALID_HANDLE 0 + +typedef void *(*pthread_fn)(void*); + +template +class Thread { + private: + typedef struct Instance; + + public: + typedef Thread_T &Thread_; + typedef const Thread_T &Thread__; + typedef pthread_t Handle; + typedef void (*Handler)(Thread_); + + protected: + Thread() { + } + + virtual void ThreadMain(Thread_) = 0; + + static void Exit() { + pthread_exit(0); + } + + static void TestCancel() { + pthread_testcancel(); + } + + static Handle Self() { + return(Handle)pthread_self(); + } + + public: + static int Create(const Handler &Func, Thread__ Param, Handle *const &H = 0, + const bool &CreateDetached = false, const unsigned int &StackSize = 0, + const bool &CancelEnable = false, const bool &CancelAsync = false) { + M_Create().Lock(); + pthread_attr_t attr; + pthread_attr_init(&attr); + + if(CreateDetached) + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + if(StackSize) + pthread_attr_setstacksize(&attr, StackSize); + + Instance I(Param, 0, Func, CancelEnable, CancelAsync); + + Handle h = INVALID_HANDLE; + int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I); + + pthread_attr_destroy(&attr); + + if(H) + *H = h; + if(!run) + S_Create().Wait(); + + M_Create().Unlock(); + + return(errno); + } + + int Create(Thread__ Param, Handle *const &H = 0, const bool &CreateDetached = false, + const unsigned int &StackSize = 0, const bool &CancelEnable = false, + const bool &CancelAsync = false ) const { + M_Create().Lock(); + pthread_attr_t attr; + pthread_attr_init(&attr); + + if(CreateDetached) + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + if(StackSize) + pthread_attr_setstacksize(&attr, StackSize); + + Instance I(Param, const_cast(this), 0, CancelEnable, CancelAsync); + + Handle h = INVALID_HANDLE; + int run = pthread_create((pthread_t *)&h, &attr, (pthread_fn)ThreadMainHandler, (void *)&I); + + pthread_attr_destroy(&attr); + + if(H) + *H = h; + if(!run) + S_Create().Wait(); + + M_Create().Unlock(); + + return(errno); + } + + static int Join(Handle H) { + return(pthread_join(H, 0)); + } + + static int Kill(Handle H) { + return(pthread_cancel(H)); + } + + static int Detach(Handle H) { + return(pthread_detach(H)); + } + + private: + static const Mutex &M_Create() { + static Mutex M; + + return(M); + } + + static const Semaphore &S_Create() { + static Semaphore S; + + return(S); + } + + static void ThreadMainHandler(Instance *Param) { + Instance I(*Param); + Thread_T Data(I.Data); + + S_Create().Post(); + + if(I.Flags & 1) { + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + if(I.Flags & 2) + pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + else + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); + } + else + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); + + if(I.Owner) + I.Owner->ThreadMain(Data); + else + I.pFN(Data); + + return(0); + } + + struct Instance { + Instance(Thread__ P, Thread *const &O, const Thread::Handler &pH = 0, + const bool &CE = false, const bool &CA = false) : Data(P), Owner(O), pFN(pH), + Flags(0) { + if(CE) + Flags |= 1; + if(CA) + Flags |= 2; + } + + Thread__ Data; + Thread *Owner; + Handler pFN; + unsigned char Flags; + }; +}; diff --git a/TinNS/Source/Common/Version.hxx b/TinNS/Source/Common/Version.hxx index 684ebd2..6048471 100644 --- a/TinNS/Source/Common/Version.hxx +++ b/TinNS/Source/Common/Version.hxx @@ -1,7 +1,7 @@ -#pragma once - -#include "Common/SVNrevision.hxx" - -#define TINNS_PATCH_VERSION "0.0.2 Dev" -#define TINNS_INFO_VERSION "0.0.2 Dev" -#define TINNS_GAME_VERSION "0.1.38 Dev" +#pragma once + +#include "Common/SVNrevision.hxx" + +#define TINNS_PATCH_VERSION "0.0.2 Dev" +#define TINNS_INFO_VERSION "0.0.2 Dev" +#define TINNS_GAME_VERSION "0.1.38 Dev" diff --git a/TinNS/Source/DevelopmentTools/CMakeLists.txt b/TinNS/Source/DevelopmentTools/CMakeLists.txt index 9f60614..50b0b11 100644 --- a/TinNS/Source/DevelopmentTools/CMakeLists.txt +++ b/TinNS/Source/DevelopmentTools/CMakeLists.txt @@ -1,2 +1,2 @@ -ADD_EXECUTABLE (getsvnrev getsvnrev.cpp) +ADD_EXECUTABLE (getsvnrev getsvnrev.cxx) ADD_EXECUTABLE (cleandepfile cleandepfile.c) diff --git a/TinNS/Source/DevelopmentTools/getsvnrev.cpp b/TinNS/Source/DevelopmentTools/getsvnrev.cxx similarity index 95% rename from TinNS/Source/DevelopmentTools/getsvnrev.cpp rename to TinNS/Source/DevelopmentTools/getsvnrev.cxx index dc88289..501129d 100644 --- a/TinNS/Source/DevelopmentTools/getsvnrev.cpp +++ b/TinNS/Source/DevelopmentTools/getsvnrev.cxx @@ -1,104 +1,104 @@ -/* - TinNS (TinNS is not a Neocron Server) - Copyright (C) 2005 Linux Addicted Community - maintainer Akiko - - 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 (at your option) 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - - - -/* - getsvnrev - a simple tool to read out actual SVN revision-number - - Why? - Well for example my server doesnt have any SVN libs installed. Therefore, - the getsvnrev script fails. I need this little tool, and maybe someone else too ^^ - - Usage: - call getsvnrev either without parameters or with the directory you - want to know the SVN revision. - - Console output: - If no .svn directory is found, the tool returns 0. - Otherwise it will return the SVN revision of the target dir - - MODIFIED: 22 Dec 2006 Namikon - REASON: - started this tool - MODIFIED: 09 Jun 2009 Akiko - REASON: - more C++ stylish - - missing libs (cstring, cstdlib) - - TODO: - - Better way to get SVN rev than this (2nd number in file) -*/ - - -#include -#include -#include -#include - -int main(int argc, char **argv) -{ - std::string targetdir; - FILE *f; - - if(argc == 2) - { - int i = 0; - while(argv[1][i] != '\0') { i++; }; - if(argv[1][i-1] == '/') - { - targetdir = strcat(argv[1], ".svn/entries"); - } - else - { - targetdir = strcat(argv[1], "/.svn/entries"); - } - } - else - { - targetdir = ".svn/entries"; - } - - - if ((f = fopen(targetdir.c_str(), "r")) != NULL) { - char line[255]; - int rev; - bool firstnrfound = false; - - do - { - fgets (line, 255, f); - rev = atoi(line); - if(rev > 0 && firstnrfound == false) - { - firstnrfound = true; - rev = 0; - } - } while (rev == 0); - - fclose(f); - - std::cout << rev << std::endl; - } - else - { - std::cout << "0" << std::endl; - } - return(0); -} +/* + TinNS (TinNS is not a Neocron Server) + Copyright (C) 2005 Linux Addicted Community + maintainer Akiko + + 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 (at your option) 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, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + + + +/* + getsvnrev - a simple tool to read out actual SVN revision-number + + Why? + Well for example my server doesnt have any SVN libs installed. Therefore, + the getsvnrev script fails. I need this little tool, and maybe someone else too ^^ + + Usage: + call getsvnrev either without parameters or with the directory you + want to know the SVN revision. + + Console output: + If no .svn directory is found, the tool returns 0. + Otherwise it will return the SVN revision of the target dir + + MODIFIED: 22 Dec 2006 Namikon + REASON: - started this tool + MODIFIED: 09 Jun 2009 Akiko + REASON: - more C++ stylish + - missing libs (cstring, cstdlib) + + TODO: + - Better way to get SVN rev than this (2nd number in file) +*/ + + +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + std::string targetdir; + FILE *f; + + if(argc == 2) + { + int i = 0; + while(argv[1][i] != '\0') { i++; }; + if(argv[1][i-1] == '/') + { + targetdir = strcat(argv[1], ".svn/entries"); + } + else + { + targetdir = strcat(argv[1], "/.svn/entries"); + } + } + else + { + targetdir = ".svn/entries"; + } + + + if ((f = fopen(targetdir.c_str(), "r")) != NULL) { + char line[255]; + int rev; + bool firstnrfound = false; + + do + { + fgets (line, 255, f); + rev = atoi(line); + if(rev > 0 && firstnrfound == false) + { + firstnrfound = true; + rev = 0; + } + } while (rev == 0); + + fclose(f); + + std::cout << rev << std::endl; + } + else + { + std::cout << "0" << std::endl; + } + return(0); +} diff --git a/TinNS/Source/GameServer/Accounts.cxx b/TinNS/Source/GameServer/Accounts.cxx index 062599b..c3d66ef 100644 --- a/TinNS/Source/GameServer/Accounts.cxx +++ b/TinNS/Source/GameServer/Accounts.cxx @@ -1,419 +1,419 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -/* -NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE: -a_priv: -0 = unregistered user -1 = Registered user -30 = volunteer -50 = GM -100 = Admin - -a_status: -0 = Offline -1 = Online -2 = Banned -*/ - -/** Static members **/ -RegEx* PAccount::mUsernameRegexFilter = NULL; -RegEx* PAccount::mPasswordRegexFilter = NULL; - -bool PAccount::SetUsernameRegexFilter(const char* RegexStr) -{ - if(mUsernameRegexFilter) - { - delete mUsernameRegexFilter; - mUsernameRegexFilter = NULL; - } - - if(RegexStr) - { - try { - mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); - } - catch (...) { - return false; - } - } - return true; -} - -bool PAccount::SetPasswordRegexFilter(const char* RegexStr) -{ - if(mPasswordRegexFilter) - { - delete mPasswordRegexFilter; - mPasswordRegexFilter = NULL; - } - - if(RegexStr) - { - try { - mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); - } - catch (...) { - return false; - } - } - return true; -} - -bool PAccount::IsUsernameWellFormed(const char *Username) -{ - if(mUsernameRegexFilter) - { - return mUsernameRegexFilter->Search(Username); - } - else - return true; -} - -bool PAccount::IsPasswordWellFormed(const char *Password) -{ - if(mPasswordRegexFilter) - { - return mPasswordRegexFilter->Search(Password); - } - else - return true; -} - -/** Instance members **/ -PAccount::PAccount() -{ - mID = 0; - mLevel = PAL_BANNED; - mStatus = PAS_OFFLINE; - mBannedUntil = 0; -} - -PAccount::PAccount(const uint32_t AccountId) -{ - char query[256]; - mID = 0; - snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId); - LoadFromQuery(query); -} - -PAccount::PAccount(const char *Username) -{ - char query[256]; - mID = 0; - if(IsUsernameWellFormed(Username)) { - char escUsername[256]; - MySQL->EscapeString(Username, escUsername, 256); - snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername); - LoadFromQuery(query); - } -} - -bool PAccount::LoadFromQuery(char* query) -{ - MYSQL_ROW row = 0; - MYSQL_RES *result = 0; - - bool FinalResult = false; - - result = MySQL->InfoResQuery(query); - if(result == NULL) - { - Console->Print(RED, BLACK, "Failed to load AccountData from SQL"); - MySQL->ShowInfoSQLError(); - return false; - } - - if((row = mysql_fetch_row(result))) - { - mID = atoi(row[a_id]); - mName = row[a_username]; - mPassword = row[a_password]; - - mBannedUntil = atoi(row[a_bandate]); - if(mBannedUntil > time(NULL)) - { - mStatus = PAS_BANNED; - mLevel = PAL_BANNED; - } - else - { - mStatus = PAS_OFFLINE; - mLevel = atoi(row[a_priv]); - } - - FinalResult = true; - } - else - { -Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load..."); - } - - MySQL->FreeInfoSQLResult(result); - return FinalResult; -} - -bool PAccount::SetName(const std::string &Username) -{ - if(IsUsernameWellFormed(Username.c_str())) - { - mName = Username; - return true; - } - else - { - return false; - } -} - -bool PAccount::SetPassword(const std::string &Password) -{ - if(IsPasswordWellFormed(Password.c_str())) - { - mPassword = Password; - return true; - } - else - { - return false; - } -} - -bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key) -{ - char Pass[128]; - - if(DecodePassword(PasswordData, PassLen, Key, Pass)) - { - return SetPassword((std::string)Pass); - } - else - { - Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); - return false; - } -} - -bool PAccount::SetLevel(int newLevel) -{ - if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN)) - { - mLevel = newLevel; - return true; - } - else - { - return false; - } -} - -std::string PAccount::GetLevelString() const -{ - switch(mLevel) - { - case PAL_BANNED : return "banned"; - case PAL_UNREGPLAYER : return "unregplayer"; - case PAL_REGPLAYER : return "regplayer"; - case PAL_VOLUNTEER : return "volunteer"; - case PAL_GM : return "gm"; - case PAL_ADMIN : return "admin"; - } - - return "custom"; -} - -bool PAccount::SetStatus(PAccountStatus Status) -{ - mStatus = Status; - return true; -} - -bool PAccount::SetBannedUntilTime(std::time_t BannedUntil) -{ - if ((BannedUntil == 0) || (BannedUntil > std::time(NULL))) - { - mBannedUntil = BannedUntil; - return true; - } - else - { - return false; - } -} - -bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword) -{ - ClearPassword[0] = 0; - - if(PassLen < 128) - { - if(Key[0]>7) // TODO: >7 correct? - { - for(int i=0; i>1] = (char)(((PasswordData[i]&0xf0)>>4) - +((PasswordData[i+1]&0x0f)<<4)-Key[0]); - ClearPassword[PassLen>>1]=0; - } - else - { - for(int i=0; iPrint(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); - return false; - } -} - -bool PAccount::Authenticate(const char *Password) const -{ - if(mID == 0) // User doesn't exist and that hasn't been checked ! - { - Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str()); - return false; - } - - return(mPassword == Password); -} - -bool PAccount::Create() -{ - if(Save(true)) { - mID = MySQL->GetLastInfoInsertId(); - return true; - } - else - { - return false; - } -} - -bool PAccount::Save(bool CreateMode) -{ - char escUsername[256]; - char escPassword[256]; - MySQL->EscapeString(mName.c_str(), escUsername, 256); - MySQL->EscapeString(mPassword.c_str(), escPassword, 256); - - std::string Query; - Query = CreateMode ? "INSERT INTO" : "UPDATE"; - Query += "accounts SET "; - Query += Ssprintf(" accounts SET a_username='%s', a_password = '%s'", escUsername, escPassword); - Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil); - if(!CreateMode ) - { - Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID); - } - - if(MySQL->InfoQuery(Query.c_str())) - { - Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID); - MySQL->ShowInfoSQLError(); - return false; - } - return true; -} - -uint32_t PAccount::GetCharIdBySlot(const uint32_t SlotId) -{ - char query[256]; - uint32_t CharId = 0; - - MYSQL_ROW row = 0; - MYSQL_RES *result = 0; - - snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d AND c_slot = %d LIMIT 1;", mID, SlotId); - - result = MySQL->GameResQuery(query); - if(result == NULL) - { - Console->Print(RED, BLACK, "Failed to load CharacterData from SQL"); - MySQL->ShowGameSQLError(); - return 0; - } - - if((row = mysql_fetch_row(result))) - { - CharId = atoi(row[0]); - } - - MySQL->FreeGameSQLResult(result); - - /*** Temporary workaround to cope with DB where c_slot is not set ***/ - if(!CharId) - { - snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d ORDER BY c_slot ASC, c_id ASC LIMIT %d, 1;", mID, SlotId); - - result = MySQL->GameResQuery(query); - if(result == NULL) - { - Console->Print(RED, BLACK, "Failed to load CharacterData from SQL"); - MySQL->ShowGameSQLError(); - return 0; - } - - if((row = mysql_fetch_row(result))) - { - CharId = atoi(row[0]); - } - - MySQL->FreeGameSQLResult(result); - } - /*** End of workaround ***/ - - return CharId; -} - - -std::string PAccount::GetBannedTime() const -{ - const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"}; - - std::time_t timediff = mBannedUntil - std::time(NULL); - if(timediff <=0) - { - return "0 more seconds. Please relog"; - } - - long counter; - int type; - - if(timediff > 86400) // days - { - counter = timediff / 86400; - type = 3; - } - else if(timediff > 3600) // hours - { - counter = timediff / 3600; - type = 2; - } - else if(timediff > 60) // Minutes - { - counter = timediff / 60; - type = 1; - } - else // Seconds - { - counter = timediff; - type = 0; - } - - return Ssprintf("%d more %s", counter, unit[type]); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +/* +NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE: +a_priv: +0 = unregistered user +1 = Registered user +30 = volunteer +50 = GM +100 = Admin + +a_status: +0 = Offline +1 = Online +2 = Banned +*/ + +/** Static members **/ +RegEx* PAccount::mUsernameRegexFilter = NULL; +RegEx* PAccount::mPasswordRegexFilter = NULL; + +bool PAccount::SetUsernameRegexFilter(const char* RegexStr) +{ + if(mUsernameRegexFilter) + { + delete mUsernameRegexFilter; + mUsernameRegexFilter = NULL; + } + + if(RegexStr) + { + try { + mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); + } + catch (...) { + return false; + } + } + return true; +} + +bool PAccount::SetPasswordRegexFilter(const char* RegexStr) +{ + if(mPasswordRegexFilter) + { + delete mPasswordRegexFilter; + mPasswordRegexFilter = NULL; + } + + if(RegexStr) + { + try { + mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); + } + catch (...) { + return false; + } + } + return true; +} + +bool PAccount::IsUsernameWellFormed(const char *Username) +{ + if(mUsernameRegexFilter) + { + return mUsernameRegexFilter->Search(Username); + } + else + return true; +} + +bool PAccount::IsPasswordWellFormed(const char *Password) +{ + if(mPasswordRegexFilter) + { + return mPasswordRegexFilter->Search(Password); + } + else + return true; +} + +/** Instance members **/ +PAccount::PAccount() +{ + mID = 0; + mLevel = PAL_BANNED; + mStatus = PAS_OFFLINE; + mBannedUntil = 0; +} + +PAccount::PAccount(const uint32_t AccountId) +{ + char query[256]; + mID = 0; + snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId); + LoadFromQuery(query); +} + +PAccount::PAccount(const char *Username) +{ + char query[256]; + mID = 0; + if(IsUsernameWellFormed(Username)) { + char escUsername[256]; + MySQL->EscapeString(Username, escUsername, 256); + snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername); + LoadFromQuery(query); + } +} + +bool PAccount::LoadFromQuery(char* query) +{ + MYSQL_ROW row = 0; + MYSQL_RES *result = 0; + + bool FinalResult = false; + + result = MySQL->InfoResQuery(query); + if(result == NULL) + { + Console->Print(RED, BLACK, "Failed to load AccountData from SQL"); + MySQL->ShowInfoSQLError(); + return false; + } + + if((row = mysql_fetch_row(result))) + { + mID = atoi(row[a_id]); + mName = row[a_username]; + mPassword = row[a_password]; + + mBannedUntil = atoi(row[a_bandate]); + if(mBannedUntil > time(NULL)) + { + mStatus = PAS_BANNED; + mLevel = PAL_BANNED; + } + else + { + mStatus = PAS_OFFLINE; + mLevel = atoi(row[a_priv]); + } + + FinalResult = true; + } + else + { +Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load..."); + } + + MySQL->FreeInfoSQLResult(result); + return FinalResult; +} + +bool PAccount::SetName(const std::string &Username) +{ + if(IsUsernameWellFormed(Username.c_str())) + { + mName = Username; + return true; + } + else + { + return false; + } +} + +bool PAccount::SetPassword(const std::string &Password) +{ + if(IsPasswordWellFormed(Password.c_str())) + { + mPassword = Password; + return true; + } + else + { + return false; + } +} + +bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key) +{ + char Pass[128]; + + if(DecodePassword(PasswordData, PassLen, Key, Pass)) + { + return SetPassword((std::string)Pass); + } + else + { + Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); + return false; + } +} + +bool PAccount::SetLevel(int newLevel) +{ + if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN)) + { + mLevel = newLevel; + return true; + } + else + { + return false; + } +} + +std::string PAccount::GetLevelString() const +{ + switch(mLevel) + { + case PAL_BANNED : return "banned"; + case PAL_UNREGPLAYER : return "unregplayer"; + case PAL_REGPLAYER : return "regplayer"; + case PAL_VOLUNTEER : return "volunteer"; + case PAL_GM : return "gm"; + case PAL_ADMIN : return "admin"; + } + + return "custom"; +} + +bool PAccount::SetStatus(PAccountStatus Status) +{ + mStatus = Status; + return true; +} + +bool PAccount::SetBannedUntilTime(std::time_t BannedUntil) +{ + if ((BannedUntil == 0) || (BannedUntil > std::time(NULL))) + { + mBannedUntil = BannedUntil; + return true; + } + else + { + return false; + } +} + +bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword) +{ + ClearPassword[0] = 0; + + if(PassLen < 128) + { + if(Key[0]>7) // TODO: >7 correct? + { + for(int i=0; i>1] = (char)(((PasswordData[i]&0xf0)>>4) + +((PasswordData[i+1]&0x0f)<<4)-Key[0]); + ClearPassword[PassLen>>1]=0; + } + else + { + for(int i=0; iPrint(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); + return false; + } +} + +bool PAccount::Authenticate(const char *Password) const +{ + if(mID == 0) // User doesn't exist and that hasn't been checked ! + { + Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str()); + return false; + } + + return(mPassword == Password); +} + +bool PAccount::Create() +{ + if(Save(true)) { + mID = MySQL->GetLastInfoInsertId(); + return true; + } + else + { + return false; + } +} + +bool PAccount::Save(bool CreateMode) +{ + char escUsername[256]; + char escPassword[256]; + MySQL->EscapeString(mName.c_str(), escUsername, 256); + MySQL->EscapeString(mPassword.c_str(), escPassword, 256); + + std::string Query; + Query = CreateMode ? "INSERT INTO" : "UPDATE"; + Query += "accounts SET "; + Query += Ssprintf(" accounts SET a_username='%s', a_password = '%s'", escUsername, escPassword); + Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil); + if(!CreateMode ) + { + Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID); + } + + if(MySQL->InfoQuery(Query.c_str())) + { + Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID); + MySQL->ShowInfoSQLError(); + return false; + } + return true; +} + +uint32_t PAccount::GetCharIdBySlot(const uint32_t SlotId) +{ + char query[256]; + uint32_t CharId = 0; + + MYSQL_ROW row = 0; + MYSQL_RES *result = 0; + + snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d AND c_slot = %d LIMIT 1;", mID, SlotId); + + result = MySQL->GameResQuery(query); + if(result == NULL) + { + Console->Print(RED, BLACK, "Failed to load CharacterData from SQL"); + MySQL->ShowGameSQLError(); + return 0; + } + + if((row = mysql_fetch_row(result))) + { + CharId = atoi(row[0]); + } + + MySQL->FreeGameSQLResult(result); + + /*** Temporary workaround to cope with DB where c_slot is not set ***/ + if(!CharId) + { + snprintf(query, 256, "SELECT c_id FROM characters WHERE a_id = %d ORDER BY c_slot ASC, c_id ASC LIMIT %d, 1;", mID, SlotId); + + result = MySQL->GameResQuery(query); + if(result == NULL) + { + Console->Print(RED, BLACK, "Failed to load CharacterData from SQL"); + MySQL->ShowGameSQLError(); + return 0; + } + + if((row = mysql_fetch_row(result))) + { + CharId = atoi(row[0]); + } + + MySQL->FreeGameSQLResult(result); + } + /*** End of workaround ***/ + + return CharId; +} + + +std::string PAccount::GetBannedTime() const +{ + const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"}; + + std::time_t timediff = mBannedUntil - std::time(NULL); + if(timediff <=0) + { + return "0 more seconds. Please relog"; + } + + long counter; + int type; + + if(timediff > 86400) // days + { + counter = timediff / 86400; + type = 3; + } + else if(timediff > 3600) // hours + { + counter = timediff / 3600; + type = 2; + } + else if(timediff > 60) // Minutes + { + counter = timediff / 60; + type = 1; + } + else // Seconds + { + counter = timediff; + type = 0; + } + + return Ssprintf("%d more %s", counter, unit[type]); +} diff --git a/TinNS/Source/GameServer/Accounts.hxx b/TinNS/Source/GameServer/Accounts.hxx index 7301c1e..1c0c0e3 100644 --- a/TinNS/Source/GameServer/Accounts.hxx +++ b/TinNS/Source/GameServer/Accounts.hxx @@ -1,101 +1,101 @@ -#pragma once - -#include -#include -#include - -class RegEx; - -/* -0 = unregistered user -1 = Registered user -30 = volunteer -50 = GM -100 = Admin -*/ - -// New way of AccountLevel handling: -// Every level is possible, the following values are only edge values. We need a bit control about that -#define PAL_BANNED -1 -#define PAL_UNREGPLAYER 0 -#define PAL_REGPLAYER 1 -#define PAL_VOLUNTEER 30 // Special Rank: 50/50 -#define PAL_GM 50 // Special Rank: 120/120 -#define PAL_ADMIN 100 // Special Rank: 127/127 - -// Max number of char slots per account -#define MAX_CHARS_PER_ACCOUNT 4 - -/* -0 = Offline -1 = Online -2 = Banned -*/ - -enum PAccountStatus -{ - PAS_OFFLINE = 0, - PAS_ONLINE = 1, - PAS_BANNED = 2 -}; - -class PAccount { - private : - // SQL Layout - enum { - a_id, - a_username, - a_password, - a_priv, - a_status, - a_bandate - }; - - // static members - static RegEx* mUsernameRegexFilter; - static RegEx* mPasswordRegexFilter; - - // instance members - uint32_t mID; - std::string mName; - std::string mPassword; - int mLevel; - PAccountStatus mStatus; - time_t mBannedUntil; - - bool LoadFromQuery(char* query); - bool DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword); - - public : - PAccount(); - PAccount(const uint32_t AccountId); - PAccount(const char *Username); - - static bool SetUsernameRegexFilter(const char* RegexStr); - static bool SetPasswordRegexFilter(const char* RegexStr); - static bool IsUsernameWellFormed(const char *Username); - static bool IsPasswordWellFormed(const char *Password); - - inline uint32_t GetID() const { return mID; } - bool SetName(const std::string &Pass); - inline const std::string &GetName() const { return mName; } - bool SetPassword(const std::string &Pass); - bool SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t *Key); - inline const std::string &GetPassword() const { return mPassword; } - bool SetLevel(int newLevel); - inline int GetLevel() const { return mLevel; } - std::string GetLevelString() const; - bool SetStatus(PAccountStatus Status); - inline PAccountStatus GetStatus() const { return mStatus; } - bool SetBannedUntilTime(time_t BannedUntil); - inline bool IsBanned() const { return (mBannedUntil > std::time(NULL)); } - std::string GetBannedTime() const; - - bool Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key); - bool Authenticate(const char *Password) const; - - bool Create(); - bool Save(bool CreateMode = false); - - uint32_t GetCharIdBySlot(const uint32_t SlotId); -}; +#pragma once + +#include +#include +#include + +class RegEx; + +/* +0 = unregistered user +1 = Registered user +30 = volunteer +50 = GM +100 = Admin +*/ + +// New way of AccountLevel handling: +// Every level is possible, the following values are only edge values. We need a bit control about that +#define PAL_BANNED -1 +#define PAL_UNREGPLAYER 0 +#define PAL_REGPLAYER 1 +#define PAL_VOLUNTEER 30 // Special Rank: 50/50 +#define PAL_GM 50 // Special Rank: 120/120 +#define PAL_ADMIN 100 // Special Rank: 127/127 + +// Max number of char slots per account +#define MAX_CHARS_PER_ACCOUNT 4 + +/* +0 = Offline +1 = Online +2 = Banned +*/ + +enum PAccountStatus +{ + PAS_OFFLINE = 0, + PAS_ONLINE = 1, + PAS_BANNED = 2 +}; + +class PAccount { + private : + // SQL Layout + enum { + a_id, + a_username, + a_password, + a_priv, + a_status, + a_bandate + }; + + // static members + static RegEx* mUsernameRegexFilter; + static RegEx* mPasswordRegexFilter; + + // instance members + uint32_t mID; + std::string mName; + std::string mPassword; + int mLevel; + PAccountStatus mStatus; + time_t mBannedUntil; + + bool LoadFromQuery(char* query); + bool DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword); + + public : + PAccount(); + PAccount(const uint32_t AccountId); + PAccount(const char *Username); + + static bool SetUsernameRegexFilter(const char* RegexStr); + static bool SetPasswordRegexFilter(const char* RegexStr); + static bool IsUsernameWellFormed(const char *Username); + static bool IsPasswordWellFormed(const char *Password); + + inline uint32_t GetID() const { return mID; } + bool SetName(const std::string &Pass); + inline const std::string &GetName() const { return mName; } + bool SetPassword(const std::string &Pass); + bool SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t *Key); + inline const std::string &GetPassword() const { return mPassword; } + bool SetLevel(int newLevel); + inline int GetLevel() const { return mLevel; } + std::string GetLevelString() const; + bool SetStatus(PAccountStatus Status); + inline PAccountStatus GetStatus() const { return mStatus; } + bool SetBannedUntilTime(time_t BannedUntil); + inline bool IsBanned() const { return (mBannedUntil > std::time(NULL)); } + std::string GetBannedTime() const; + + bool Authenticate(const uint8_t* PasswordData, int PassLen, const uint8_t *Key); + bool Authenticate(const char *Password) const; + + bool Create(); + bool Save(bool CreateMode = false); + + uint32_t GetCharIdBySlot(const uint32_t SlotId); +}; diff --git a/TinNS/Source/GameServer/Appartements.cxx b/TinNS/Source/GameServer/Appartements.cxx index 062ecc3..7c0f45a 100644 --- a/TinNS/Source/GameServer/Appartements.cxx +++ b/TinNS/Source/GameServer/Appartements.cxx @@ -1,220 +1,220 @@ -#include -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -PAppartements::PAppartements() -{ -} - -//PAppartements::~PAppartements() {}; - -uint32_t PAppartements::CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID) -{ - typedef std::vector< std::pair > PAppVector; // - - PAppVector CandidateApts; - CandidateApts.reserve(32); - uint16_t j; - int AppType; - - for (std::map::const_iterator i=GameDefs->Appartements()->ConstIteratorBegin(); i!=GameDefs->Appartements()->ConstIteratorEnd(); i++) - { - if (i->second->GetFaction() == nFactionID) - { - for (j = 0; j < i->second->GetPlaceCount(); j++) - { - AppType = i->second->GetID(); - if ((AppType < 220) || (AppType >= 250)) - { -if (gDevDebug) Console->Print("Added potential Apt of type %d in place %d", AppType, i->second->GetPlace(j)); - CandidateApts.push_back(std::make_pair(AppType, i->second->GetPlace(j))); - } - } - } - } - - if(CandidateApts.size()) - { - j = GetRandom(CandidateApts.size()-1); -if (gDevDebug) Console->Print("Apt n� %d chosen in %d for faction %d", j+1, CandidateApts.size(), nFactionID); - -if (gDevDebug) Console->Print("Choosed Apt of type %d in place %d", CandidateApts[j].first, CandidateApts[j].second); - - char escPassword[256]; - MySQL->EscapeString(nPassword.c_str(), escPassword, 256); - char query[256]; - snprintf(query, 256, "INSERT INTO apartments (apt_id,apt_location,apt_type,apt_password, apt_owner) VALUES (NULL,'%d','%d','%s','%d');", CandidateApts[j].second, CandidateApts[j].first, escPassword, nCharID); - if ( MySQL->GameQuery(query) ) - { - Console->Print(RED, BLACK, "PAppartements::CreateBaseAppartement could not add some appartement entry in the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return 0; - } - return (MySQL->GetLastGameInsertId()); - } - else - return 0; -} - -void PAppartements::DeleteCharAppartements(uint32_t nCharID) -{ - char query[256]; - snprintf(query, 256, "DELETE FROM apartments WHERE (apt_owner='%u');", nCharID); - if ( MySQL->GameQuery(query) ) - { - Console->Print(RED, BLACK, "PAppartements::DeleteCharAppartements could not delete some char %d appartement(s) entry from the database", nCharID); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - } - else -if (gDevDebug) Console->Print(YELLOW, BLACK, "PAppartements::DeleteCharAppartements does not delete appartements content yet"); -} - -bool PAppartements::CanFreelyEnter(PChar* nChar, uint32_t nLocation) -{ - uint32_t OwnerID = GetAptOwner(nLocation); - return (OwnerID == nChar->GetID()); - - // here we could manage Clan appartements access too. -} - -int PAppartements::GetAptID(unsigned int AptLoc, const uint8_t *pass) -{ - int type; - MYSQL_RES *result; - MYSQL_ROW row; - char query[255]; - - if(!strcmp((const char*)pass, "Exit")) - return 1; - - char escPassword[255]; - MySQL->EscapeString((char*)pass, escPassword, 255); - snprintf(query, 255, "SELECT apt_id FROM apartments WHERE apt_location = %i AND apt_password = '%s'", AptLoc, escPassword); - result = MySQL->GameResQuery(query); - - if(!result) - { - Console->Print("%s Cannot get AppartmentID; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - MySQL->ShowGameSQLError(); - return 0; - } - - if(mysql_num_rows(result) == 0) - { - MySQL->FreeGameSQLResult(result); - return 0; - } - else - { - row = mysql_fetch_row(result); - type = atoi(row[0]); - MySQL->FreeGameSQLResult(result); - } - - return (type + PWorlds::mAptBaseWorldId); -} - -int PAppartements::GetAptType(int AptID) -{ - int type; - MYSQL_RES *result; - MYSQL_ROW row; - char query[255]; - - snprintf(query, 225, "SELECT apt_type FROM apartments WHERE apt_id = %i", AptID - PWorlds::mAptBaseWorldId); - result = MySQL->GameResQuery(query); - - if(!result) - { - Console->Print("%s Cannot get AppartmentType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - MySQL->ShowGameSQLError(); - return 0; - } - - if(mysql_num_rows(result) == 0) - { - MySQL->FreeGameSQLResult(result); - return 0; - } - else - { - row = mysql_fetch_row(result); - type = atoi(row[0]); - MySQL->FreeGameSQLResult(result); - } - - return type; -} - -int PAppartements::GetAptOwner(int loc) -{ - int owner; - MYSQL_RES *result; - MYSQL_ROW row; - char query[255]; - - snprintf (query, 255, "SELECT apt_owner FROM apartments WHERE apt_id = %i", loc - PWorlds::mAptBaseWorldId); - - result = MySQL->GameResQuery(query); - if(!result) - { - Console->Print("%s Cannot get AppartmentOwner; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - MySQL->ShowGameSQLError(); - return 0; - } - - if(mysql_num_rows(result) == 0) - { - MySQL->FreeGameSQLResult(result); - return 0; - } - else - { - row = mysql_fetch_row(result); - owner = atoi(row[0]); - MySQL->FreeGameSQLResult(result); - } - - return owner; -} - -int PAppartements::GetAptLocation(int loc) -{ - int Location; - MYSQL_RES *result; - MYSQL_ROW row; - char query[255]; - - if((uint32_t)loc > PWorlds::mAptBaseWorldId) - loc = loc - PWorlds::mAptBaseWorldId; - - snprintf (query, 255, "SELECT apt_location FROM apartments WHERE apt_id = %i", loc); - -//Console->Print("Q: %s", query); - result = MySQL->GameResQuery(query); - if(!result) - { - Console->Print("%s Cannot get AppartmentLocation; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - MySQL->ShowGameSQLError(); - return 0; - } - - if(mysql_num_rows(result) == 0) - { - MySQL->FreeGameSQLResult(result); - return 0; - } - else - { - row = mysql_fetch_row(result); - Location = atoi(row[0]); - MySQL->FreeGameSQLResult(result); - } - - return Location; -} +#include +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +PAppartements::PAppartements() +{ +} + +//PAppartements::~PAppartements() {}; + +uint32_t PAppartements::CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID) +{ + typedef std::vector< std::pair > PAppVector; // + + PAppVector CandidateApts; + CandidateApts.reserve(32); + uint16_t j; + int AppType; + + for (std::map::const_iterator i=GameDefs->Appartements()->ConstIteratorBegin(); i!=GameDefs->Appartements()->ConstIteratorEnd(); i++) + { + if (i->second->GetFaction() == nFactionID) + { + for (j = 0; j < i->second->GetPlaceCount(); j++) + { + AppType = i->second->GetID(); + if ((AppType < 220) || (AppType >= 250)) + { +if (gDevDebug) Console->Print("Added potential Apt of type %d in place %d", AppType, i->second->GetPlace(j)); + CandidateApts.push_back(std::make_pair(AppType, i->second->GetPlace(j))); + } + } + } + } + + if(CandidateApts.size()) + { + j = GetRandom(CandidateApts.size()-1); +if (gDevDebug) Console->Print("Apt n� %d chosen in %d for faction %d", j+1, CandidateApts.size(), nFactionID); + +if (gDevDebug) Console->Print("Choosed Apt of type %d in place %d", CandidateApts[j].first, CandidateApts[j].second); + + char escPassword[256]; + MySQL->EscapeString(nPassword.c_str(), escPassword, 256); + char query[256]; + snprintf(query, 256, "INSERT INTO apartments (apt_id,apt_location,apt_type,apt_password, apt_owner) VALUES (NULL,'%d','%d','%s','%d');", CandidateApts[j].second, CandidateApts[j].first, escPassword, nCharID); + if ( MySQL->GameQuery(query) ) + { + Console->Print(RED, BLACK, "PAppartements::CreateBaseAppartement could not add some appartement entry in the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return 0; + } + return (MySQL->GetLastGameInsertId()); + } + else + return 0; +} + +void PAppartements::DeleteCharAppartements(uint32_t nCharID) +{ + char query[256]; + snprintf(query, 256, "DELETE FROM apartments WHERE (apt_owner='%u');", nCharID); + if ( MySQL->GameQuery(query) ) + { + Console->Print(RED, BLACK, "PAppartements::DeleteCharAppartements could not delete some char %d appartement(s) entry from the database", nCharID); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + } + else +if (gDevDebug) Console->Print(YELLOW, BLACK, "PAppartements::DeleteCharAppartements does not delete appartements content yet"); +} + +bool PAppartements::CanFreelyEnter(PChar* nChar, uint32_t nLocation) +{ + uint32_t OwnerID = GetAptOwner(nLocation); + return (OwnerID == nChar->GetID()); + + // here we could manage Clan appartements access too. +} + +int PAppartements::GetAptID(unsigned int AptLoc, const uint8_t *pass) +{ + int type; + MYSQL_RES *result; + MYSQL_ROW row; + char query[255]; + + if(!strcmp((const char*)pass, "Exit")) + return 1; + + char escPassword[255]; + MySQL->EscapeString((char*)pass, escPassword, 255); + snprintf(query, 255, "SELECT apt_id FROM apartments WHERE apt_location = %i AND apt_password = '%s'", AptLoc, escPassword); + result = MySQL->GameResQuery(query); + + if(!result) + { + Console->Print("%s Cannot get AppartmentID; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + MySQL->ShowGameSQLError(); + return 0; + } + + if(mysql_num_rows(result) == 0) + { + MySQL->FreeGameSQLResult(result); + return 0; + } + else + { + row = mysql_fetch_row(result); + type = atoi(row[0]); + MySQL->FreeGameSQLResult(result); + } + + return (type + PWorlds::mAptBaseWorldId); +} + +int PAppartements::GetAptType(int AptID) +{ + int type; + MYSQL_RES *result; + MYSQL_ROW row; + char query[255]; + + snprintf(query, 225, "SELECT apt_type FROM apartments WHERE apt_id = %i", AptID - PWorlds::mAptBaseWorldId); + result = MySQL->GameResQuery(query); + + if(!result) + { + Console->Print("%s Cannot get AppartmentType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + MySQL->ShowGameSQLError(); + return 0; + } + + if(mysql_num_rows(result) == 0) + { + MySQL->FreeGameSQLResult(result); + return 0; + } + else + { + row = mysql_fetch_row(result); + type = atoi(row[0]); + MySQL->FreeGameSQLResult(result); + } + + return type; +} + +int PAppartements::GetAptOwner(int loc) +{ + int owner; + MYSQL_RES *result; + MYSQL_ROW row; + char query[255]; + + snprintf (query, 255, "SELECT apt_owner FROM apartments WHERE apt_id = %i", loc - PWorlds::mAptBaseWorldId); + + result = MySQL->GameResQuery(query); + if(!result) + { + Console->Print("%s Cannot get AppartmentOwner; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + MySQL->ShowGameSQLError(); + return 0; + } + + if(mysql_num_rows(result) == 0) + { + MySQL->FreeGameSQLResult(result); + return 0; + } + else + { + row = mysql_fetch_row(result); + owner = atoi(row[0]); + MySQL->FreeGameSQLResult(result); + } + + return owner; +} + +int PAppartements::GetAptLocation(int loc) +{ + int Location; + MYSQL_RES *result; + MYSQL_ROW row; + char query[255]; + + if((uint32_t)loc > PWorlds::mAptBaseWorldId) + loc = loc - PWorlds::mAptBaseWorldId; + + snprintf (query, 255, "SELECT apt_location FROM apartments WHERE apt_id = %i", loc); + +//Console->Print("Q: %s", query); + result = MySQL->GameResQuery(query); + if(!result) + { + Console->Print("%s Cannot get AppartmentLocation; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + MySQL->ShowGameSQLError(); + return 0; + } + + if(mysql_num_rows(result) == 0) + { + MySQL->FreeGameSQLResult(result); + return 0; + } + else + { + row = mysql_fetch_row(result); + Location = atoi(row[0]); + MySQL->FreeGameSQLResult(result); + } + + return Location; +} diff --git a/TinNS/Source/GameServer/Appartements.hxx b/TinNS/Source/GameServer/Appartements.hxx index 9643be0..9ea301b 100644 --- a/TinNS/Source/GameServer/Appartements.hxx +++ b/TinNS/Source/GameServer/Appartements.hxx @@ -1,20 +1,20 @@ -#pragma once - -#include -#include - -class PChar; - -class PAppartements { -public: - PAppartements(); - //~PAppartements(); - - uint32_t CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID); - void DeleteCharAppartements(uint32_t nCharID); - bool CanFreelyEnter(PChar* nChar, uint32_t nLocation); - int GetAptID(unsigned int AptLoc, const uint8_t *pass); - int GetAptType(int AptID); - int GetAptOwner(int loc); - int GetAptLocation(int loc); -}; +#pragma once + +#include +#include + +class PChar; + +class PAppartements { +public: + PAppartements(); + //~PAppartements(); + + uint32_t CreateBaseAppartement(uint32_t nCharID, std::string nPassword, uint8_t nFactionID); + void DeleteCharAppartements(uint32_t nCharID); + bool CanFreelyEnter(PChar* nChar, uint32_t nLocation); + int GetAptID(unsigned int AptLoc, const uint8_t *pass); + int GetAptType(int AptID); + int GetAptOwner(int loc); + int GetAptLocation(int loc); +}; diff --git a/TinNS/Source/GameServer/BuddyList.cxx b/TinNS/Source/GameServer/BuddyList.cxx index 54f32f4..79ac545 100644 --- a/TinNS/Source/GameServer/BuddyList.cxx +++ b/TinNS/Source/GameServer/BuddyList.cxx @@ -1,169 +1,169 @@ -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -PBuddyList::PBuddyList(uint32_t nOwnerCharID) -{ - mOwnerCharID = nOwnerCharID; - mListMaxSize = mListSize = 0; - mCharIDList = NULL; -} - -PBuddyList::~PBuddyList() -{ - - if (mCharIDList) - delete[] mCharIDList; -} - -bool PBuddyList::AddChar(uint32_t nBuddyCharID) -{ - char query[256]; - - if ((FindEntry(nBuddyCharID) >= mListSize) && (mListSize < 255)) - { - if (mListSize == mListMaxSize) - { - IncreaseMaxSize(); - } - mCharIDList[mListSize++] = nBuddyCharID; - - snprintf(query, 256, "INSERT INTO buddy_list (bud_id,bud_charid,bud_buddyid) VALUES (NULL,'%u','%u');", mOwnerCharID, nBuddyCharID); - if ( MySQL->GameQuery(query) ) - { - Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylisdt entry in the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return false; - } - - return true; - } - else - return false; -} - -bool PBuddyList::RemoveChar(uint32_t nBuddyCharID) -{ - char query[256]; - uint8_t rEntry, i; - - if ((rEntry = FindEntry(nBuddyCharID)) < mListSize) - { - --mListSize; - for (i = rEntry; i < mListSize; i++) - { - mCharIDList[i] = mCharIDList[i+1]; - } - // Remove from DB here - snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID); - if ( MySQL->GameQuery(query) ) - { - Console->Print(RED, BLACK, "PBuddyList::AddChar could not delete some buddylist entry from the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return false; - } - - return true; - } - else - return false; -} - -bool PBuddyList::SQLLoad() -{ - char query[256]; - MYSQL_RES *result; - MYSQL_ROW row; - uint8_t EntriesNum; - - snprintf(query, 256, "SELECT * FROM buddy_list WHERE (bud_charid='%u')", mOwnerCharID); - result = MySQL->GameResQuery(query); - if(result == NULL) - { - Console->Print(RED, BLACK, "PBuddyList::SQLLoad could not load buddylist entry from the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return false; - } - //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Loading buddylist for char %d", mOwnerCharID); - mListSize = 0; - if((EntriesNum = mysql_num_rows(result))) - { - IncreaseMaxSize(EntriesNum); - - while((row = mysql_fetch_row(result))) - { - mCharIDList[mListSize++] = atoi(row[bud_buddyid]); - //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Buddylist entry %d : char %d", mListSize, mCharIDList[mListSize-1]); - } - } - MySQL->FreeGameSQLResult(result); - return true; -} - -void PBuddyList::IncreaseMaxSize(uint8_t nNewMax) -{ - uint16_t tmpSize; - - if (!nNewMax) - { - tmpSize = mListMaxSize + BUDDYLIST_ALLOC_SIZE; - } - else if (nNewMax > mListMaxSize) - { - tmpSize = nNewMax / BUDDYLIST_ALLOC_SIZE; - if (nNewMax % BUDDYLIST_ALLOC_SIZE) - ++tmpSize; - tmpSize *= BUDDYLIST_ALLOC_SIZE; - } - else - return; - - mListMaxSize = (tmpSize < 256) ? tmpSize : 255; - - uint32_t* tmpList = new uint32_t[mListMaxSize]; - if (mCharIDList) - { - if (mListSize) - { - memcpy(tmpList, mCharIDList, sizeof(uint32_t) * mListSize); - } - - delete[] mCharIDList; - } - mCharIDList = tmpList; -} - -uint8_t PBuddyList::FindEntry(uint32_t CharID) -{ - uint8_t i = 255; - - if (mCharIDList) - { - for (i = 0; i < mListSize; i++) - { - if (mCharIDList[i] == CharID) - break; - } - } - - return i; -} - -bool PBuddyList::IsInBuddy(uint32_t CharID) -{ - if (mCharIDList) - { - for (uint8_t i = 0; i < mListSize; i++) - { - if (mCharIDList[i] == CharID) - return true; - } - } - return false; -} +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +PBuddyList::PBuddyList(uint32_t nOwnerCharID) +{ + mOwnerCharID = nOwnerCharID; + mListMaxSize = mListSize = 0; + mCharIDList = NULL; +} + +PBuddyList::~PBuddyList() +{ + + if (mCharIDList) + delete[] mCharIDList; +} + +bool PBuddyList::AddChar(uint32_t nBuddyCharID) +{ + char query[256]; + + if ((FindEntry(nBuddyCharID) >= mListSize) && (mListSize < 255)) + { + if (mListSize == mListMaxSize) + { + IncreaseMaxSize(); + } + mCharIDList[mListSize++] = nBuddyCharID; + + snprintf(query, 256, "INSERT INTO buddy_list (bud_id,bud_charid,bud_buddyid) VALUES (NULL,'%u','%u');", mOwnerCharID, nBuddyCharID); + if ( MySQL->GameQuery(query) ) + { + Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylisdt entry in the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return false; + } + + return true; + } + else + return false; +} + +bool PBuddyList::RemoveChar(uint32_t nBuddyCharID) +{ + char query[256]; + uint8_t rEntry, i; + + if ((rEntry = FindEntry(nBuddyCharID)) < mListSize) + { + --mListSize; + for (i = rEntry; i < mListSize; i++) + { + mCharIDList[i] = mCharIDList[i+1]; + } + // Remove from DB here + snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID); + if ( MySQL->GameQuery(query) ) + { + Console->Print(RED, BLACK, "PBuddyList::AddChar could not delete some buddylist entry from the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return false; + } + + return true; + } + else + return false; +} + +bool PBuddyList::SQLLoad() +{ + char query[256]; + MYSQL_RES *result; + MYSQL_ROW row; + uint8_t EntriesNum; + + snprintf(query, 256, "SELECT * FROM buddy_list WHERE (bud_charid='%u')", mOwnerCharID); + result = MySQL->GameResQuery(query); + if(result == NULL) + { + Console->Print(RED, BLACK, "PBuddyList::SQLLoad could not load buddylist entry from the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return false; + } + //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Loading buddylist for char %d", mOwnerCharID); + mListSize = 0; + if((EntriesNum = mysql_num_rows(result))) + { + IncreaseMaxSize(EntriesNum); + + while((row = mysql_fetch_row(result))) + { + mCharIDList[mListSize++] = atoi(row[bud_buddyid]); + //Console->Print(GREEN, BLACK, "PBuddyList::SQLLoad Buddylist entry %d : char %d", mListSize, mCharIDList[mListSize-1]); + } + } + MySQL->FreeGameSQLResult(result); + return true; +} + +void PBuddyList::IncreaseMaxSize(uint8_t nNewMax) +{ + uint16_t tmpSize; + + if (!nNewMax) + { + tmpSize = mListMaxSize + BUDDYLIST_ALLOC_SIZE; + } + else if (nNewMax > mListMaxSize) + { + tmpSize = nNewMax / BUDDYLIST_ALLOC_SIZE; + if (nNewMax % BUDDYLIST_ALLOC_SIZE) + ++tmpSize; + tmpSize *= BUDDYLIST_ALLOC_SIZE; + } + else + return; + + mListMaxSize = (tmpSize < 256) ? tmpSize : 255; + + uint32_t* tmpList = new uint32_t[mListMaxSize]; + if (mCharIDList) + { + if (mListSize) + { + memcpy(tmpList, mCharIDList, sizeof(uint32_t) * mListSize); + } + + delete[] mCharIDList; + } + mCharIDList = tmpList; +} + +uint8_t PBuddyList::FindEntry(uint32_t CharID) +{ + uint8_t i = 255; + + if (mCharIDList) + { + for (i = 0; i < mListSize; i++) + { + if (mCharIDList[i] == CharID) + break; + } + } + + return i; +} + +bool PBuddyList::IsInBuddy(uint32_t CharID) +{ + if (mCharIDList) + { + for (uint8_t i = 0; i < mListSize; i++) + { + if (mCharIDList[i] == CharID) + return true; + } + } + return false; +} diff --git a/TinNS/Source/GameServer/BuddyList.hxx b/TinNS/Source/GameServer/BuddyList.hxx index 257c23d..21455bd 100644 --- a/TinNS/Source/GameServer/BuddyList.hxx +++ b/TinNS/Source/GameServer/BuddyList.hxx @@ -1,35 +1,35 @@ -#pragma once - -#include - -#define BUDDYLIST_ALLOC_SIZE 4 // atomicity of list entries allocation - -class PBuddyList { - private: - enum { // buddy_list DB Table fields - bud_id = 0, - bud_charid, - bud_buddyid - }; - - uint32_t mOwnerCharID; - uint8_t mListMaxSize; - uint8_t mListSize; - uint32_t* mCharIDList; - - void IncreaseMaxSize(uint8_t nNewMax = 0); - uint8_t FindEntry(uint32_t CharID); - - public: - PBuddyList(uint32_t nOwnerCharID); - ~PBuddyList(); - bool AddChar(uint32_t nBuddyCharID); - bool RemoveChar(uint32_t nBuddyCharID); - inline uint8_t Count() { return mListSize; } - uint16_t GetListDataSize() { return (sizeof(uint32_t) * mListSize); } - const void* GetListData() { return (const void*)mCharIDList; } - bool SQLLoad(); - - bool IsInBuddy(uint32_t CharID); -// bool SQLSave(); -}; +#pragma once + +#include + +#define BUDDYLIST_ALLOC_SIZE 4 // atomicity of list entries allocation + +class PBuddyList { + private: + enum { // buddy_list DB Table fields + bud_id = 0, + bud_charid, + bud_buddyid + }; + + uint32_t mOwnerCharID; + uint8_t mListMaxSize; + uint8_t mListSize; + uint32_t* mCharIDList; + + void IncreaseMaxSize(uint8_t nNewMax = 0); + uint8_t FindEntry(uint32_t CharID); + + public: + PBuddyList(uint32_t nOwnerCharID); + ~PBuddyList(); + bool AddChar(uint32_t nBuddyCharID); + bool RemoveChar(uint32_t nBuddyCharID); + inline uint8_t Count() { return mListSize; } + uint16_t GetListDataSize() { return (sizeof(uint32_t) * mListSize); } + const void* GetListData() { return (const void*)mCharIDList; } + bool SQLLoad(); + + bool IsInBuddy(uint32_t CharID); +// bool SQLSave(); +}; diff --git a/TinNS/Source/GameServer/Chars.cxx b/TinNS/Source/GameServer/Chars.cxx index cd9f727..f247f8a 100644 --- a/TinNS/Source/GameServer/Chars.cxx +++ b/TinNS/Source/GameServer/Chars.cxx @@ -1,1337 +1,1337 @@ -#include -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -// PCharCoordinates -void PCharCoordinates::SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef ) -{ - if (( nCoef < 0 ) || ( nCoef > 1 ) ) - { - Console->Print( RED, BLACK, "[Error] PCharCoordinates::Interpolate : Invalid nCoef value: %f", nCoef ); - nCoef = 0; - } - float rCoef = 1 - nCoef; - - mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY ); - mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ ); - mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX ); - mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD ); - if ( abs( Pos1.mLR - Pos2.mLR ) < 90 ) - { - mLR = ( uint8_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR ); - } - else - { - mLR = ( uint8_t )(( uint16_t )( rCoef * ( 180.0 + ( float )Pos1.mLR ) + nCoef * Pos2.mLR ) % 180 ); - } -} - -uint16_t mY; // Y-Position in world -uint16_t mZ; // Z-Position in world -uint16_t mX; // X-Position in world -uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) -uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179]) -uint8_t mAct; // Last user action state - -void PCharCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint8_t nLR ) -{ - mY = nY; - mZ = nZ; - mX = nX; - mUD = nUD; - if ( mUD < 0x2a ) - { - mUD = 0x2a; - } - else if ( mUD > 0xd6 ) - { - mUD = 0xd6; - } - mLR = nLR % 180; -} - - -// SQL Layout -enum -{ - c_id, - c_name, - c_str_lvl, - c_str_pts, - c_int_lvl, - c_int_pts, - c_dex_lvl, - c_dex_pts, - c_con_lvl, - c_con_pts, - c_psi_lvl, - c_psi_pts, - a_id, - c_class, - c_profession, - c_sex, - c_location, - c_mc, - c_hc, - c_tra, - c_pc, - c_rc, - c_tc, - c_vhc, - c_agl, - c_rep, - c_rec, - c_rcl, - c_atl, - c_end, - c_for, - c_fir, - c_enr, - c_xrr, - c_por, - c_hlt, - c_hck, - c_brt, - c_psu, - c_wep, - c_cst, - c_res, - c_imp, - c_ppu, - c_apu, - c_mst, - c_ppw, - c_psr, - c_wpw, - c_apt, - c_cash, - c_head, - c_torso, - c_legs, - c_str_xp, - c_int_xp, - c_dex_xp, - c_psi_xp, - c_con_xp, - c_pos_x, - c_pos_y, - c_pos_z, - c_angle_ud, - c_angle_lr, - c_faction, - c_slot, - c_online, - c_clan, - c_soullight -}; - -RegEx* PChar::mCharnameRegexFilter = NULL; - -PChar::PChar() -{ - mID = 0; - mAccount = 0; - mGender = 0; - mClass = 0; - mProfession = 1; - mFaction = 1; - //mModel = 0; - //mType = 0; - mRealHead = 0; // Base Skin elements, in complement of (computed) mType - mRealTorso = 0; // " Head shouldn't be changeable, except in case of surgery !!! - mRealLegs = 0; // " - mSkin = 0; // Current Skin elements - mHead = 0; // " - mTorso = 0; // " - mLegs = 0; // " - mHeadColor = mTorsoColor = mLegsColor = 0; // " - mHeadDarkness = mTorsoDarkness = mLegsDarkness = 0; // " - - mBodyEffect = 0; - mBodyEffectDensity = 0; - mQuickBeltActiveSlot = INV_WORN_QB_NONE; - - mLookingAt = 0; - mLookAtTimestamp = 0; - mLastUsedWorldObjectId = 0; - - mSpeedOverride = 255; // means no override. Value 0 can be used to forbid any move. - - mLocationLeased = false; // temp until char on-demand load/unload - mLocation = 0; - mStartApt = 0; - mPrimaryApt = 0; - mCash = 0; - - mSeatInUseType = seat_none; - mSeatInUseObjectId = 0; - mSeatInUseSeatId = 0; - mVhcAccessRequestList = NULL; - - mContainerInExclusiveUse = NULL; - - mIsOnline = false; - mDirtyFlag = false; - - mShunned = false; - mJailed = false; - - mDialogNPC = 0; - mCurrentDialogNode = 0; - - Skill = new PSkillHandler(); - mBuddyList = NULL; - mGenrepList = NULL; - - // Required for initial OOC Broadcast welcome message. - //Gets overwritten as soon as the first PingPacket arrives - mActiveChatChannels = 262144; - mClanLevel = 0; - mClanID = 0; -} - -PChar::~PChar() -{ - // Addition; Set char's online status to OFFLINE - char sqlqry[50]; - snprintf(sqlqry, 50, "UPDATE characters SET c_online = 0 WHERE c_id = %d", mID); - MySQL->GameQuery(sqlqry); - - delete Skill; - delete mBuddyList; - delete mGenrepList; - delete mVhcAccessRequestList; - - if ( mContainerInExclusiveUse ) - { - mContainerInExclusiveUse->EndUse( mID ); - Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still had exclusive use of container. Now freed." ); - } - - if ( mSeatInUseType != seat_none ) - { - Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still using seat %d of vhc or chair %d.", mSeatInUseSeatId, mSeatInUseObjectId ); - } -} - -bool PChar::SetCharnameRegexFilter( const char* RegexStr ) -{ - if ( mCharnameRegexFilter ) - { - delete mCharnameRegexFilter; - mCharnameRegexFilter = NULL; - } - - if ( RegexStr ) - { - try - { - mCharnameRegexFilter = new RegEx( RegexStr, PCRE_CASELESS ); - } - catch ( ... ) - { - return false; - } - } - return true; -} - -bool PChar::IsCharnameWellFormed( const char *Charname ) -{ - if ( mCharnameRegexFilter ) - { - return mCharnameRegexFilter->Search( Charname ); - } - else - return true; -} - -void PChar::SetProfession( uint32_t Profession ) -{ - const PDefCharKind *def = GameDefs->CharKinds()->GetDef( Profession ); - if ( def == NULL ) - { - Console->Print( RED, BLACK, "Char %d: Invalid profession %d", mID, Profession ); - mProfession = 10; - mClass = 0; - } - else - { - mProfession = Profession; - mClass = def->GetType(); - } - SetDirtyFlag(); -} - -uint32_t PChar::GetSkinFromCharType( uint32_t nType ) -{ - const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType ); - if ( nDefCharacter ) - { - return (( uint32_t )( nDefCharacter->GetModel() ) ); - } - else - return 0; -} - -inline uint32_t PChar::GetBaseModel() -{ - return GetSkinFromCharType( GetType() ); -} - -void PChar::SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs ) -{ - mRealHead = nHead; - mRealTorso = nTorso; - mRealLegs = nLegs; - SetDirtyFlag(); - ResetCurrentLook(); -} - -void PChar::GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ) -{ - nSkin = GetBaseModel(); - nHead = mRealHead; - nTorso = mRealTorso; - nLegs = mRealLegs; -} - -void PChar::SetCurrentLookFromCharType( uint32_t nType ) -{ - int iHead, iTorso, iLegs; - uint32_t nSkin, nHead, nTorso, nLegs; - uint8_t nColor, nBrightness; - - const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType ); - if ( nDefCharacter ) - { - nSkin = ( uint32_t ) nDefCharacter->GetModel(); - iHead = nDefCharacter->GetHead(); - iTorso = nDefCharacter->GetTorso(); - iLegs = nDefCharacter->GetLegs(); - nColor = ( uint8_t )( 0xff & nDefCharacter->GetColor() ); - nBrightness = ( uint8_t )( 0xff & nDefCharacter->GetBrightness() ); - - - if (( iHead < 0 ) || ( iTorso < 0 ) || ( iLegs < 0 ) ) - { - nHead = nTorso = nLegs = 0; - } - else - { - nHead = iHead % 10; - nTorso = iTorso % 10; - nLegs = iLegs % 10; - } - - SetCurrentLook( nSkin, nHead, nTorso, nLegs ); - SetCurrentBodyColor( nColor, nColor, nColor, nBrightness, nBrightness, nBrightness ); - } -} - -void PChar::SetCurrentLook( uint32_t nSkin, uint32_t nHead, uint32_t nTorso, uint32_t nLegs ) -{ - mSkin = nSkin; - mHead = nHead; - mTorso = nTorso; - mLegs = nLegs; - // Ingame skin update will be done automagically in the normal update flow - // A flag could also be set somewhere (preferably in Char si that we don't have to care if ingame or not) - // to request quicker ingame update -} - -void PChar::ResetCurrentLook() -{ - SetCurrentLook( GetSkinFromCharType( GetType() ), mRealHead, mRealTorso, mRealLegs ); -} - -// GetCurrentLook will later have to take Power Armors and GM overrides into account -void PChar::GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ) -{ - nSkin = mSkin; - nHead = mHead; - nTorso = mTorso; - nLegs = mLegs; -} - -void PChar::SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness, uint8_t nTorsoDarkness, uint8_t nLegsDarkness ) -{ - mHeadColor = nHeadColor; - mTorsoColor = nTorsoColor; - mLegsColor = nLegsColor; - mHeadDarkness = nHeadDarkness; - mTorsoDarkness = nTorsoDarkness; - mLegsDarkness = nLegsDarkness; -} - -void PChar::GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness ) -{ - nHeadColor = mHeadColor; - nTorsoColor = mTorsoColor; - nLegsColor = mLegsColor; - nHeadDarkness = mHeadDarkness; - nTorsoDarkness = mTorsoDarkness; - nLegsDarkness = mLegsDarkness; -} - -void PChar::SetBaseSkills() -{ - const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession ); - //Console->Print(YELLOW, BLACK, "PChar::SetBaseSkills() Profession: %d",def->GetIndex()); - if ( def == NULL ) - { - Console->Print( RED, BLACK, "PChar::SetBaseSkills: GetCharKindDef=NULL" ); - return; - } - Skill->SetMainSkill( MS_INT, def->GetSkillInfo( MS_INT ).mStart ); - Skill->SetMainSkill( MS_CON, def->GetSkillInfo( MS_CON ).mStart ); - Skill->SetMainSkill( MS_DEX, def->GetSkillInfo( MS_DEX ).mStart ); - Skill->SetMainSkill( MS_STR, def->GetSkillInfo( MS_STR ).mStart ); - Skill->SetMainSkill( MS_PSI, def->GetSkillInfo( MS_PSI ).mStart ); - // management of SP needed ? NC Client seem to calculate what remains ... - // or put SP setting after subskill setting ? - /* Skill->SetSP(MS_INT, (short) ??? )); - Skill->SetSP(MS_CON, ((short) ??? )); - Skill->SetSP(MS_DEX, (short) ??? )); - Skill->SetSP(MS_STR, (short) ??? )); - Skill->SetSP(MS_PSI, ((short) ??? )); */ - // what about XPs ? - /* Skill->SetXP(MS_INT, ??? )); - Skill->SetXP(MS_CON, ??? )); - Skill->SetXP(MS_DEX, ??? )); - Skill->SetXP(MS_STR, ??? )); - Skill->SetXP(MS_PSI, ??? )); */ - Console->Print( YELLOW, BLACK, "PChar::SetBaseSkills() not fully functionnal - unused skill points will be lost" ); -} - -void PChar::SetBaseSubskills( uint8_t NSZNb, const char* NonZeroSubskills ) -{ - int i; - - if ( NSZNb == 0 ) - return; - - for ( i = 0; i < NSZNb; i++ ) - { - Skill->SetSubSkill(( SUB_SKILLS ) NonZeroSubskills[2 * i], ( int ) NonZeroSubskills[2 * i +1] ); - } -} - -void PChar::SetBaseInventory() -{ - uint8_t i; - uint32_t BaseItemID; - const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession ); - - //mCash = 5000; - mCash = def->GetStartMoney(); - - for ( i = 0; i < 8 ; i++ ) - { - BaseItemID = def->GetStartInventory( i ); - if ( BaseItemID ) - { - if ( gDevDebug ) Console->Print( GREEN, BLACK, "Adding item %d to base inventory", BaseItemID ); - PItem* NewItem = new PItem( BaseItemID ); - if ( NewItem->GetItemID() ) - { - NewItem->MakeItemStandard( 120, 180 ); // global quality range - mInventory.AddItem( NewItem ); - } - else - { - Console->Print( RED, BLACK, "Invalid item ID %d in base inventory for profession %d", BaseItemID, mProfession ); - } - } - } -} - -void PChar::LoadClanLevel() -{ - MYSQL_RES *result; - char query[200]; - - snprintf(query, 200, "SELECT cll_level FROM clanlevels WHERE cll_charid = %d AND cll_clanid = %d", mID, mClanID); - result = MySQL->GameResQuery( query ); - if ( result == NULL ) - { - mClanID = 0; - Console->Print( RED, BLACK, "PChar::GetClanLevel could not load ClanLevel from the database" ); - Console->Print( "Query was:" ); - Console->Print( "%s", query ); - MySQL->ShowGameSQLError(); - return; - } - else if(mysql_num_rows(result) == 0) - { - mClanID = 0; - Console->Print( RED, BLACK, "PChar::GetClanLevel No level entry found for clan!" ); - return; - } - mClanLevel = atoi(mysql_fetch_row(result)[0]); - if (gDevDebug) Console->Print("Loaded ClanLevel %d for char %d, clan %d", mClanLevel, mID, mClanID); -} - -bool PChar::SQLLoad( int CharID ) -{ - MYSQL_RES *result; - MYSQL_ROW row; - char query[1024]; - - snprintf( query, 1024, "SELECT * FROM characters WHERE c_id = %d LIMIT 1", CharID ); - result = MySQL->GameResQuery( query ); - if ( result == NULL ) - { - Console->Print( RED, BLACK, "PChar::SQLLoad could not load Chardata from the database" ); - Console->Print( "Query was:" ); - Console->Print( "%s", query ); - MySQL->ShowGameSQLError(); - return false; - } - if (( row = mysql_fetch_row( result ) ) ) - { - SetID( CharID ); - SetName( row[c_name] ); - SetAccount( atoi( row[a_id] ) ); - - // Gender - int genvalue = atoi( row[c_sex] ); - if (( genvalue == 0 ) || ( genvalue == 1 ) ) - mGender = static_cast( genvalue ); - else - { - Console->Print( RED, BLACK, "Bad gender value: %d (Char ID %d)", genvalue, mID ); - mGender = 0; - } - - // Profession - int profvalue = atoi( row[c_profession] ); - SetProfession( static_cast( profvalue ) ); - - // Class - //int classvalue = atoi(row[c_class]); - //if(classvalue < 4) - // mClass = static_cast(classvalue); - //else - //{ - // Console->Print(RED, BLACK, "Bad class value: %d (Char ID %d)", classvalue, mID); - // classvalue = 0; - //} - - // Faction - int facvalue = atoi( row[c_faction] ); - if ( GameDefs->Factions()->GetDef( facvalue ) ) - mFaction = static_cast( facvalue ); - else - mFaction = 1; - - /* // Model - int modvalue = atoi(row[c_model]); - mModel = static_cast(modvalue); - mModel = 10; */ - int headvalue = atoi( row[c_head] ); - int torsovalue = atoi( row[c_torso] ); - int legsvalue = atoi( row[c_legs] ); - SetRealLook( static_cast( headvalue ), static_cast( torsovalue ), static_cast( legsvalue ) ); - - // Type - /* - int typevalue = std::atoi(row[c_type]); - mType = static_cast(typevalue); - //mType = 1; */ - - // Location - int locvalue = atoi( row[c_location] ); - mLocation = static_cast( locvalue ); - -//This assumption is not so good ... hardcoding jailed state linked with location ... - if ( mLocation == 550 || mLocation == 551 ) - mJailed = true; - - int posvalue = atoi( row[c_pos_x] ); - Coords.mX = static_cast( posvalue ); - posvalue = atoi( row[c_pos_y] ); - Coords.mY = static_cast( posvalue ); - posvalue = atoi( row[c_pos_z] ); - Coords.mZ = static_cast( posvalue ); - posvalue = atoi( row[c_angle_ud] ); - Coords.mUD = static_cast( posvalue ); - posvalue = atoi( row[c_angle_lr] ); - Coords.mLR = static_cast( posvalue ); - - int primapt = atoi( row[c_apt] ); - mPrimaryApt = static_cast( primapt ); - mStartApt = mPrimaryApt; - - mSoullight = atoi( row[c_soullight] ); - mClanID = atoi( row[c_clan] ); - if(mClanID > 0) - LoadClanLevel(); - - // Cash - float cashvalue = atof( row[c_cash] ); - mCash = static_cast( cashvalue ); - - // --------------------------------------------- - // Loading skills --- MAIN Skills with SP and XP - // --------------------------------------------- - Skill->SetMainSkill( MS_INT, atoi( row[c_int_lvl] ) ); - Skill->SetMainSkill( MS_CON, atoi( row[c_con_lvl] ) ); - Skill->SetMainSkill( MS_DEX, atoi( row[c_dex_lvl] ) ); - Skill->SetMainSkill( MS_STR, atoi( row[c_str_lvl] ) ); - Skill->SetMainSkill( MS_PSI, atoi( row[c_psi_lvl] ) ); - // --------------------------------------------- - Skill->SetSP( MS_INT, ( short )atoi( row[c_int_pts] ) ); - Skill->SetSP( MS_CON, ( short )atoi( row[c_con_pts] ) ); - Skill->SetSP( MS_DEX, ( short )atoi( row[c_dex_pts] ) ); - Skill->SetSP( MS_STR, ( short )atoi( row[c_str_pts] ) ); - Skill->SetSP( MS_PSI, ( short )atoi( row[c_psi_pts] ) ); - // --------------------------------------------- - Skill->SetXP( MS_INT, atof( row[c_int_xp] ) ); - Skill->SetXP( MS_CON, atof( row[c_con_xp] ) ); - Skill->SetXP( MS_DEX, atof( row[c_dex_xp] ) ); - Skill->SetXP( MS_STR, atof( row[c_str_xp] ) ); - Skill->SetXP( MS_PSI, atof( row[c_psi_xp] ) ); - // --------------------------------------------- - // SubSkills - // --------------------------------------------- - Skill->SetSubSkill( SK_MC, atoi( row[c_mc] ) ); - Skill->SetSubSkill( SK_HC, atoi( row[c_hc] ) ); - Skill->SetSubSkill( SK_TRA, atoi( row[c_tra] ) ); - Skill->SetSubSkill( SK_FOR, atoi( row[c_for] ) ); - Skill->SetSubSkill( SK_PC, atoi( row[c_pc] ) ); - Skill->SetSubSkill( SK_RC, atoi( row[c_rc] ) ); - Skill->SetSubSkill( SK_TC, atoi( row[c_tc] ) ); - Skill->SetSubSkill( SK_VHC, atoi( row[c_vhc] ) ); - Skill->SetSubSkill( SK_AGL, atoi( row[c_agl] ) ); - Skill->SetSubSkill( SK_REP, atoi( row[c_rep] ) ); - Skill->SetSubSkill( SK_REC, atoi( row[c_rec] ) ); - Skill->SetSubSkill( SK_RCL, atoi( row[c_rcl] ) ); - Skill->SetSubSkill( SK_ATL, atoi( row[c_atl] ) ); - Skill->SetSubSkill( SK_END, atoi( row[c_end] ) ); - Skill->SetSubSkill( SK_FIR, atoi( row[c_fir] ) ); - Skill->SetSubSkill( SK_ENR, atoi( row[c_enr] ) ); - Skill->SetSubSkill( SK_XRR, atoi( row[c_xrr] ) ); - Skill->SetSubSkill( SK_POR, atoi( row[c_por] ) ); - Skill->SetSubSkill( SK_HLT, atoi( row[c_hlt] ) ); - Skill->SetSubSkill( SK_HCK, atoi( row[c_hck] ) ); - Skill->SetSubSkill( SK_BRT, atoi( row[c_brt] ) ); - Skill->SetSubSkill( SK_PSU, atoi( row[c_psu] ) ); - Skill->SetSubSkill( SK_WEP, atoi( row[c_wep] ) ); - Skill->SetSubSkill( SK_CST, atoi( row[c_cst] ) ); - Skill->SetSubSkill( SK_RES, atoi( row[c_res] ) ); - Skill->SetSubSkill( SK_IMP, atoi( row[c_imp] ) ); - Skill->SetSubSkill( SK_PPU, atoi( row[c_ppu] ) ); - Skill->SetSubSkill( SK_APU, atoi( row[c_apu] ) ); - Skill->SetSubSkill( SK_MST, atoi( row[c_mst] ) ); - Skill->SetSubSkill( SK_PPW, atoi( row[c_ppw] ) ); - Skill->SetSubSkill( SK_PSR, atoi( row[c_psr] ) ); - Skill->SetSubSkill( SK_WPW, atoi( row[c_wpw] ) ); - // -------------------------------------------- - // Inventory - // --------------------------------------------- - mInventory.SetCharId( mID ); - mInventory.SQLLoad(); - - // temp value forcing, not get/saved from DB atm - mCombatRank = ( uint8_t )( random() % 127 ); // bad result there on randomness - mSynaptic = 0; - mIsDead = false; - - mDirectCharID = 0; // until saved/loaded with char - mBuddyList = new PBuddyList( mID ); - if ( !mBuddyList->SQLLoad() ) - { - Console->Print( RED, BLACK, "Char ID %d : Can't load buddy list", mID ); - } - //to add: Chats settings - - mGenrepList = new PGenrepList( mID ); - if ( !mGenrepList->SQLLoad() ) - { - Console->Print( RED, BLACK, "Char ID %d : Can't load genrep list", mID ); - } - - } - MySQL->FreeGameSQLResult( result ); - - // Addition; Set char's online status to ONLINE - char sqlqry[50]; - snprintf(sqlqry, 50, "UPDATE characters SET c_online = 1 WHERE c_id = %d", mID); - MySQL->GameQuery(sqlqry); - - return true; -} - -bool PChar::SQLCreate() // Specific method for creation in order to avoid existence check with each save -{ - std::string query, queryv; - - query = "INSERT INTO characters (c_id"; - queryv = ") VALUES (NULL"; - - query += ",c_name"; - queryv = queryv + ",'" + mName + "'"; - - query += ",a_id"; - queryv += Ssprintf( ",'%u'", mAccount ); - query += ",c_class"; - queryv += Ssprintf( ",'%u'", mClass ); - query += ",c_sex"; - queryv += Ssprintf( ",'%u'", mGender ); - query += ",c_profession"; - queryv += Ssprintf( ",'%u'", mProfession ); - query += ",c_faction"; - queryv += Ssprintf( ",'%u'", mFaction ); - query += ",c_head"; - queryv += Ssprintf( ",'%u'", mRealHead ); - query += ",c_torso"; - queryv += Ssprintf( ",'%u'", mRealTorso ); - query += ",c_legs"; - queryv += Ssprintf( ",'%u'", mRealLegs ); - //query += ",c_model"; - //queryv += Ssprintf(",'%u'", mModel); - //query += ",c_type"; - //queryv += Ssprintf(",'%u'", mType); - query += ",c_location"; - queryv += Ssprintf( ",'%u'", mLocation ); - query += ",c_cash"; - queryv += Ssprintf( ",'%u'", mCash ); - query += ",c_slot"; - queryv += Ssprintf( ",'%u'", mSlot ); - - query = query + queryv + ");"; - - if ( MySQL->GameQuery( query.c_str() ) ) - { - Console->Print( RED, BLACK, "PChar::SQLCreate could not add char %s to database", mName.c_str() ); - Console->Print( "Query was:" ); - Console->Print( "%s", query.c_str() ); - MySQL->ShowGameSQLError(); - return false; - } - else - { - mID = MySQL->GetLastGameInsertId(); -//Console->Print(GREEN, BLACK, "New char %s got ID %d", mName.c_str(), mID); - mDirtyFlag = true; - return true; - } -} - -bool PChar::CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction, - uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot ) -{ - SetName( Name ); - SetGender( Gender ); - SetProfession( Profession ); - SetFaction( Faction ); - SetRealLook( Head, Torso, Legs ); - SetBaseSkills(); - SetBaseSubskills( NZSNb, NonZeroSubskills ); - SetBaseInventory(); - SetAccount( Account ); - SetCharSlot( Slot ); - mLocation = Config->GetOptionInt( "new_char_location" ); - - // This part will have to be rewritten with proper methods - mSoullight = 10; - mCombatRank = ( uint8_t )( random() % 80 ); // bad result there on randomness - mSynaptic = 0; - mIsDead = false; - - mDirectCharID = 0; // until saved/loaded with char - - SetDirtyFlag(); - - if ( SQLCreate() ) // mID isn't defined before that - { - mBuddyList = new PBuddyList( mID ); - mGenrepList = new PGenrepList( mID ); - mStartApt = mPrimaryApt = Appartements->CreateBaseAppartement( mID, mName, mFaction ); - mInventory.SetCharId( mID ); - - if ( mStartApt && SQLSave() && mInventory.SQLSave() ) - { - return true; - } - else - { - Console->Print( YELLOW, BLACK, "New char %s (id %d) : creation aborted", mName.c_str(), mID ); - if ( mID ) - { - SQLDelete(); - if ( mStartApt ) - { - Appartements->DeleteCharAppartements( mID ); - } - } - } - } - return false; -} - -bool PChar::SQLSave() -{ - std::string query; - //std::string ts; - - /* TODO: - - Mostly at creation/load : - c_apt, (or when first GR to primary apt to avoid creation of unused apt?) - (c_slot) - - At save/load : - SoulLight ??? - FactionSymp[] ??? - Chest change: style, brightness, color - Legs change: style, brightness, color - mHealt, mStamina, mMana (not in DB !!!) - How to compute MaxHealth etc. ? - */ - query = "UPDATE characters SET"; - - query += Ssprintf( " c_location='%u'", mLocation ); - query += Ssprintf( ",c_pos_x='%u'", Coords.mX ); - query += Ssprintf( ",c_pos_y='%u'", Coords.mY ); - query += Ssprintf( ",c_pos_z='%u'", Coords.mZ ); - query += Ssprintf( ",c_angle_ud='%u'", Coords.mUD ); - query += Ssprintf( ",c_angle_lr='%u'", Coords.mLR ); - query += Ssprintf( ",c_cash='%u'", mCash ); - query += Ssprintf( ",c_apt='%u'", mPrimaryApt ); - - query += Ssprintf( ",c_head='%u'", mRealHead ); - query += Ssprintf( ",c_torso='%u'", mRealTorso ); - query += Ssprintf( ",c_legs='%u'", mRealLegs ); - - query += Ssprintf( ",c_faction='%u'", mFaction ); - - /* This group of fiels shouldn't change in-game - query = query + ",c_name='" + mName + "'"; - query += Ssprintf(",a_id='%u'", mAccount); - query += Ssprintf(",c_class='%u'", mClass); - query += Ssprintf(",c_sex='%u'", mGender); - query += Ssprintf(",c_profession='%u'", mProfession); - query += Ssprintf(",c_slot='%u'", mSlot); - // query += Ssprintf(",c_model='%u'", mModel); - // query += Ssprintf(",c_type='%u'", mType); - */ - - // --------------------------------------------- - // Saving skills --- MAIN Skills with SP and XP - // --------------------------------------------- - query += Ssprintf( ",c_int_lvl='%u'", Skill->GetMainSkill( MS_INT ) ); - query += Ssprintf( ",c_con_lvl='%u'", Skill->GetMainSkill( MS_CON ) ); - query += Ssprintf( ",c_dex_lvl='%u'", Skill->GetMainSkill( MS_DEX ) ); - query += Ssprintf( ",c_str_lvl='%u'", Skill->GetMainSkill( MS_STR ) ); - query += Ssprintf( ",c_psi_lvl='%u'", Skill->GetMainSkill( MS_PSI ) ); - // --------------------------------------------- - query += Ssprintf( ",c_int_pts='%u'", Skill->GetSP( MS_INT ) ); - query += Ssprintf( ",c_con_pts='%u'", Skill->GetSP( MS_CON ) ); - query += Ssprintf( ",c_dex_pts='%u'", Skill->GetSP( MS_DEX ) ); - query += Ssprintf( ",c_str_pts='%u'", Skill->GetSP( MS_STR ) ); - query += Ssprintf( ",c_psi_pts='%u'", Skill->GetSP( MS_PSI ) ); - // --------------------------------------------- - query += Ssprintf( ",c_int_xp='%u'", Skill->GetXP( MS_INT ) ); - query += Ssprintf( ",c_con_xp='%u'", Skill->GetXP( MS_CON ) ); - query += Ssprintf( ",c_dex_xp='%u'", Skill->GetXP( MS_DEX ) ); - query += Ssprintf( ",c_str_xp='%u'", Skill->GetXP( MS_STR ) ); - query += Ssprintf( ",c_psi_xp='%u'", Skill->GetXP( MS_PSI ) ); - // --------------------------------------------- - // SubSkills - // --------------------------------------------- - query += Ssprintf( ",c_mc='%u'", Skill->GetSubSkill( SK_MC ) ); - query += Ssprintf( ",c_hc='%u'", Skill->GetSubSkill( SK_HC ) ); - query += Ssprintf( ",c_tra='%u'", Skill->GetSubSkill( SK_TRA ) ); - query += Ssprintf( ",c_for='%u'", Skill->GetSubSkill( SK_FOR ) ); - query += Ssprintf( ",c_pc='%u'", Skill->GetSubSkill( SK_PC ) ); - query += Ssprintf( ",c_rc='%u'", Skill->GetSubSkill( SK_RC ) ); - query += Ssprintf( ",c_tc='%u'", Skill->GetSubSkill( SK_TC ) ); - query += Ssprintf( ",c_vhc='%u'", Skill->GetSubSkill( SK_VHC ) ); - query += Ssprintf( ",c_agl='%u'", Skill->GetSubSkill( SK_AGL ) ); - query += Ssprintf( ",c_rep='%u'", Skill->GetSubSkill( SK_REP ) ); - query += Ssprintf( ",c_rec='%u'", Skill->GetSubSkill( SK_REC ) ); - query += Ssprintf( ",c_rcl='%u'", Skill->GetSubSkill( SK_RCL ) ); - query += Ssprintf( ",c_atl='%u'", Skill->GetSubSkill( SK_ATL ) ); - query += Ssprintf( ",c_end='%u'", Skill->GetSubSkill( SK_END ) ); - query += Ssprintf( ",c_fir='%u'", Skill->GetSubSkill( SK_FIR ) ); - query += Ssprintf( ",c_enr='%u'", Skill->GetSubSkill( SK_ENR ) ); - query += Ssprintf( ",c_xrr='%u'", Skill->GetSubSkill( SK_XRR ) ); - query += Ssprintf( ",c_por='%u'", Skill->GetSubSkill( SK_POR ) ); - query += Ssprintf( ",c_htl='%u'", Skill->GetSubSkill( SK_HLT ) ); - query += Ssprintf( ",c_hck='%u'", Skill->GetSubSkill( SK_HCK ) ); - query += Ssprintf( ",c_brt='%u'", Skill->GetSubSkill( SK_BRT ) ); - query += Ssprintf( ",c_psu='%u'", Skill->GetSubSkill( SK_PSU ) ); - query += Ssprintf( ",c_wep='%u'", Skill->GetSubSkill( SK_WEP ) ); - query += Ssprintf( ",c_cst='%u'", Skill->GetSubSkill( SK_CST ) ); - query += Ssprintf( ",c_res='%u'", Skill->GetSubSkill( SK_RES ) ); - query += Ssprintf( ",c_imp='%u'", Skill->GetSubSkill( SK_IMP ) ); - query += Ssprintf( ",c_ppu='%u'", Skill->GetSubSkill( SK_PPU ) ); - query += Ssprintf( ",c_apu='%u'", Skill->GetSubSkill( SK_APU ) ); - query += Ssprintf( ",c_mst='%u'", Skill->GetSubSkill( SK_MST ) ); - query += Ssprintf( ",c_ppw='%u'", Skill->GetSubSkill( SK_PPW ) ); - query += Ssprintf( ",c_psr='%u'", Skill->GetSubSkill( SK_PSR ) ); - query += Ssprintf( ",c_wpw='%u'", Skill->GetSubSkill( SK_WPW ) ); - // --------------------------------------------- - - query += Ssprintf( " WHERE c_id='%u' LIMIT 1;", mID ); - - if ( MySQL->GameQuery( query.c_str() ) ) - { - Console->Print( RED, BLACK, "PChar::SQLSave could not save char %s (%u) to database", mName.c_str(), mID ); - Console->Print( "Query was:" ); - Console->Print( "%s", query.c_str() ); - MySQL->ShowGameSQLError(); - return false; - } - - // Chats settings (?), directs - - mDirtyFlag = false; - return true; -} - -bool PChar::SQLDelete() -{ - return true; -} - -void PChar::SetOnlineStatus( bool IsOnline ) -{ - // Deactivated, until Maxx added c_isonline row to `characters` - //char query[255]; - int onlinestatus = 0; - - if ( IsOnline ) - { - onlinestatus = 0; // Strange ???? - mIsOnline = true; - } - else - { - onlinestatus = 1; // Strange ???? - mIsOnline = false; - } - -// snprintf(query, 255, "UPDATE charlist SET c_isonline = %d WHERE a_id = %d AND c_id = %d", onlinestatus, mAccount, mID); -// if(MySQL->Query(query)) -// { -// Console->Print("Error: Cant set onlinestatus to '%d' for Account: %d, Char: %d", onlinestatus, mAccount, mID); -// MySQL->ShowSQLError(); -// return; -// } - return; -} - -uint8_t PChar::GetCombatRank() -{ - // Override for Special Account Levels - PAccount Acc(mAccount); - if(Acc.GetLevel() == PAL_ADMIN) - return 127; - else if(Acc.GetLevel() >= PAL_GM) - return 120; - else if(Acc.GetLevel() >= PAL_VOLUNTEER) - return 50; - else - return mCombatRank; -} - - -uint8_t PChar::GetMainRank() -{ - // Override for Special Account Levels - PAccount Acc(mAccount); - if(Acc.GetLevel() == PAL_ADMIN) - return 127; - else if(Acc.GetLevel() >= PAL_GM) - return 120; - else if(Acc.GetLevel() >= PAL_VOLUNTEER) - return 50; - else - { - uint16_t total; - total = Skill->GetMainSkill( MS_STR ) + Skill->GetMainSkill( MS_DEX ); - total += Skill->GetMainSkill( MS_CON ) + Skill->GetMainSkill( MS_INT ); - total += Skill->GetMainSkill( MS_PSI ); - return (( uint8_t )( total / 5 ) ); - } -} - -bool PChar::AddGenrep(uint16_t nWorldID, uint16_t nStationID) -{ - return mGenrepList->AddGenrep(nWorldID, nStationID ); -} - -uint16_t PChar::GetGenrepListDataSize() -{ - return mGenrepList->GetListDataSize(); -} - -const void *PChar::GetGenrepListData() -{ - return mGenrepList->GetListData(); -} - -uint8_t PChar::GetGenrepCount() -{ - return mGenrepList->Count(); -} - -uint32_t PChar::AddCash( uint32_t nAmount ) -{ - return SetCash(nAmount + mCash); -} - -uint32_t PChar::TakeCash( uint32_t nAmount ) -{ - if(nAmount > mCash) - { - //Tries to take away more cash that user has, set to zero - return SetCash(0); - } - else - { - return SetCash(mCash-nAmount); - } -} - -uint32_t PChar::SetCash( uint32_t nCash ) -{ - //Console->Print("Trying to set cash to nCash: %d", nCash); - if (( int )nCash > Config->GetOptionInt( "max_cash" ) ) - { - //Console->Print("Newcash would be more than dynamic maxcash, setting to maxcash"); - mCash = ( uint32_t )Config->GetOptionInt( "max_cash" ); - } - else if ( nCash > MAXCASH ) - { - //Console->Print("Newcash would be more than hardcoded maxcash, setting to maxcash"); - mCash = MAXCASH; - } - else - { - //Console->Print("Allright, setting to new value"); - mCash = nCash; - } - //Console->Print("Returning mCash: %d", mCash); - return mCash; -} - - -bool PChar::SetQuickBeltActiveSlot( uint8_t nSlotID ) -{ - if (( nSlotID == INV_WORN_QB_HAND ) || ( nSlotID == INV_WORN_QB_NONE ) ) - { - mQuickBeltActiveSlot = nSlotID; - return true; - } - else if ( nSlotID <= ( INV_WORN_QB_END - INV_WORN_QB_START ) ) - { - PContainer* tWorn = mInventory.GetContainer( INV_LOC_WORN ); - - if ( ! tWorn->IsSlotFree( nSlotID ) ) // => TODO: MUST ALSO CHECK that item is currently usable and can be held in hand - { - mQuickBeltActiveSlot = nSlotID; - return true; - } - else - { - Console->Print( "SetQuickBeltActiveSlot: SlotID %d greater than %d or free (%d)", nSlotID, INV_WORN_QB_END - INV_WORN_QB_START, tWorn->IsSlotFree( nSlotID ) ); - } - } - return false; -} - -PSeatType PChar::GetSeatInUse( uint32_t* nObjectId, uint8_t* nSeatId ) -{ - if ( nObjectId ) - { - *nObjectId = mSeatInUseObjectId; - } - if ( nSeatId ) - { - *nSeatId = mSeatInUseSeatId; - } - - return mSeatInUseType; -} - -void PChar::SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId, uint8_t nSeatId ) -{ - mSeatInUseType = nSeatType; - mSeatInUseObjectId = nObjectId; - mSeatInUseSeatId = nSeatId; -} - -PVhcAccessRequestList* PChar::GetVhcAccessRequestList() -{ - if( ! mVhcAccessRequestList ) - mVhcAccessRequestList = new PVhcAccessRequestList(); - - return mVhcAccessRequestList; -} - -void PChar::SetLookingAt( uint16_t nLocalCharID ) -{ - mLookingAt = nLocalCharID; - mLookAtTimestamp = std::time( NULL ); -} - -uint16_t PChar::GetLookingAt( uint16_t nMaxDelaySec ) -{ - return ((( mLookAtTimestamp + nMaxDelaySec ) >= std::time( NULL ) ) ? mLookingAt : 0 ); -} - -// =================================== - -PChars::PChars() -{ - mLastID = 0; - mLastSave = std::time( NULL ); - - mAutoSavePeriod = Config->GetOptionInt( "auto_save_period" ); - if ( mAutoSavePeriod < 0 ) - { - Console->Print( "%s auto_save_period (%d) must be strict positive.", Console->ColorText( RED, BLACK, "[Error]" ), mAutoSavePeriod ); - mAutoSavePeriod = 0; - } - else if ( mAutoSavePeriod > 3600 ) - { - Console->Print( "%s auto_save_period (%d) too high. Forced to 3600 sec.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod ); - mAutoSavePeriod = 0; - } - - if ( mAutoSavePeriod == 0 ) - { - Console->Print( "%s Auto-save disabled.", Console->ColorText( YELLOW, BLACK, "[Info]" ) ); - } - else if ( mAutoSavePeriod < 60 ) - { - Console->Print( "%s auto_save_period (%d) is low and might lead to high server load.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod ); - } - -} - -PChars::~PChars() -{ - for ( CharMap::iterator i = mChars.begin(); i != mChars.end(); i++ ) - delete i->second; -} - -bool PChars::LoadChar( uint32_t CharID ) -{ - if ( !CharID ) - return false; - - PChar *nChar = new PChar(); - if ( nChar->SQLLoad( CharID ) ) - { - nChar->SetDirtyFlag( false ); - return AddChar( nChar ); - } - else - { - Console->Print( RED, BLACK, "[ERROR] Could not load char id %d from database", CharID ); - return false; - } -} - -bool PChars::AddChar( PChar* nChar ) -{ - if ( !nChar ) - return false; - - mLastID = std::max( mLastID, nChar->GetID() ); - if ( mChars.insert( std::make_pair( nChar->GetID(), nChar ) ).second ) - { - if ( gDevDebug ) - Console->Print( "%s Char: %s (id %d) added", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nChar->GetName().c_str() , nChar->GetID() ); - return true; - } - else - { - Console->Print( RED, BLACK, "[ERROR] Trying to load char twice : %s (id %d)", nChar->GetName().c_str(), nChar->GetID() ); - return false; - } -} - -PChar* PChars::RemoveChar( uint32_t CharID ) -{ - PChar* Result = NULL; - - CharMap::iterator i = mChars.find( CharID ); - if ( i != mChars.end() ) - { - Result = i->second; - mChars.erase( i ); - if ( gDevDebug ) - Console->Print( "%s Char: %s (id %d) removed", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Result->GetName().c_str() , Result->GetID() ); - } - - return Result; -} - -void PChars::SQLSave() -{ - // saves all dirty-flagged chars - int nDirtyChars = 0, nSavedChars = 0; - int nDirtyInv = 0, nSavedInv = 0; - - for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ ) - { - PChar* Char = i->second; - if ( Char->IsDirty() ) - { - ++nDirtyChars; - if ( Char->SQLSave() ) - ++nSavedChars; - } - if ( Char->GetInventory()->IsDirty() ) - { - ++nDirtyInv; - if ( Char->GetInventory()->SQLSave() ) - ++nSavedInv; - } - } - Console->Print( "%s %i chars saved on %i dirty, %i inventories saved on %i dirty", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nSavedChars, nDirtyChars, nSavedInv, nDirtyInv ); - return; -} - -PChar* PChars::GetChar( uint32_t CharID ) const -{ - PChar *Result = 0; - CharMap::const_iterator i = mChars.find( CharID ); - if ( i != mChars.end() ) - Result = i->second; - - return Result; -} - -PChar* PChars::GetChar( const std::string &Name ) const -{ - PChar *Result = 0; - for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ ) - { - if ( !/*std::*/strcasecmp( i->second->GetName().c_str(), Name.c_str() ) ) - { - Result = i->second; - break; - } - } - return Result; -} - -bool PChars::CharExist( const std::string &Name ) const -{ - char query[256]; - int EntriesNb; - MYSQL_RES *result = 0; - - char escUsername[256]; - MySQL->EscapeString( Name.c_str(), escUsername, 256 ); - snprintf( query, 256, "SELECT 1 FROM characters WHERE c_name = '%s' LIMIT 1;", escUsername ); - - result = MySQL->GameResQuery( query ); - if ( result == NULL ) - { - Console->Print( RED, BLACK, "[ERROR] Failed to get CharacterData from SQL" ); - MySQL->ShowGameSQLError(); - return true; - } - - EntriesNb = mysql_num_rows( result ); - MySQL->FreeGameSQLResult( result ); - return( EntriesNb > 0 ); -} - -void PChars::Update() -{ - std::time_t t = std::time( NULL ); // changed to time() to have real time instead of cpu used time - - if ( mAutoSavePeriod && (( t - mLastSave ) >= mAutoSavePeriod ) ) - { - bool NeedSave = false; - for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ ) - { - if ( i->second->IsAnyDirty() ) - { - NeedSave = true; - break; - } - } - - if ( NeedSave ) - { - if ( gDevDebug ) Console->Print( "%s Some characters need autosaving...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - SQLSave(); - if ( gDevDebug ) Console->Print( "%s Autosave done.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - } - mLastSave = t; - } -} - -//MAX_CHARS_PER_ACCOUNT -int PChars::GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize ) -{ - char query[256]; - int EntriesNb = 0; - - MYSQL_ROW row = 0; - MYSQL_RES *result = 0; - - snprintf( query, 256, "SELECT * FROM characters WHERE a_id = %d ORDER BY c_slot ASC", AccountID ); - - result = MySQL->GameResQuery( query ); - if ( result == NULL ) - { - Console->Print( RED, BLACK, "[ERROR] Failed to load CharacterData from SQL" ); - MySQL->ShowGameSQLError(); - return 0; - } - - //EntriesNb = mysql_num_rows(result); - int SlotID; - uint32_t CharID; - PChar* tmpChar = new PChar(); - - while (( row = mysql_fetch_row( result ) ) ) - { - SlotID = atoi( row[c_slot] ); - CharID = atoi( row[c_id] ); - if (( SlotID >= 0 ) && ( SlotID < ArraySize ) ) - { - if ( !CharSlotsArray[SlotID].in_use ) - { - tmpChar->SetID( CharID ); - tmpChar->SetGender( atoi( row[c_sex] ) ); - tmpChar->SetProfession( atoi( row[c_profession] ) ); - - CharSlotsArray[SlotID].CharID = CharID; - CharSlotsArray[SlotID].Type = tmpChar->GetType(); - CharSlotsArray[SlotID].Location = static_cast( atoi( row[c_location] ) ); - CharSlotsArray[SlotID].Head = atoi( row[c_head] ); - CharSlotsArray[SlotID].Torso = atoi( row[c_torso] ); - CharSlotsArray[SlotID].Legs = atoi( row[c_legs] ); - CharSlotsArray[SlotID].Name = row[c_name]; - CharSlotsArray[SlotID].NameLen = CharSlotsArray[SlotID].Name.length() + 1; - - CharSlotsArray[SlotID].in_use = true; - ++EntriesNb; - } - else - { - Console->Print( YELLOW, BLACK, "[Warning]Character %d using slot %d already used by char %d - Ignored", \ - CharID, SlotID, CharSlotsArray[SlotID].CharID ); - } - } - else - { - Console->Print( YELLOW, BLACK, "[Warning]Character %d using invialid slot %d - Ignored", CharID, SlotID ); - } - } - - delete tmpChar; - MySQL->FreeGameSQLResult( result ); - return EntriesNb; -} +#include +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +// PCharCoordinates +void PCharCoordinates::SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef ) +{ + if (( nCoef < 0 ) || ( nCoef > 1 ) ) + { + Console->Print( RED, BLACK, "[Error] PCharCoordinates::Interpolate : Invalid nCoef value: %f", nCoef ); + nCoef = 0; + } + float rCoef = 1 - nCoef; + + mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY ); + mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ ); + mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX ); + mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD ); + if ( abs( Pos1.mLR - Pos2.mLR ) < 90 ) + { + mLR = ( uint8_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR ); + } + else + { + mLR = ( uint8_t )(( uint16_t )( rCoef * ( 180.0 + ( float )Pos1.mLR ) + nCoef * Pos2.mLR ) % 180 ); + } +} + +uint16_t mY; // Y-Position in world +uint16_t mZ; // Z-Position in world +uint16_t mX; // X-Position in world +uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) +uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179]) +uint8_t mAct; // Last user action state + +void PCharCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint8_t nLR ) +{ + mY = nY; + mZ = nZ; + mX = nX; + mUD = nUD; + if ( mUD < 0x2a ) + { + mUD = 0x2a; + } + else if ( mUD > 0xd6 ) + { + mUD = 0xd6; + } + mLR = nLR % 180; +} + + +// SQL Layout +enum +{ + c_id, + c_name, + c_str_lvl, + c_str_pts, + c_int_lvl, + c_int_pts, + c_dex_lvl, + c_dex_pts, + c_con_lvl, + c_con_pts, + c_psi_lvl, + c_psi_pts, + a_id, + c_class, + c_profession, + c_sex, + c_location, + c_mc, + c_hc, + c_tra, + c_pc, + c_rc, + c_tc, + c_vhc, + c_agl, + c_rep, + c_rec, + c_rcl, + c_atl, + c_end, + c_for, + c_fir, + c_enr, + c_xrr, + c_por, + c_hlt, + c_hck, + c_brt, + c_psu, + c_wep, + c_cst, + c_res, + c_imp, + c_ppu, + c_apu, + c_mst, + c_ppw, + c_psr, + c_wpw, + c_apt, + c_cash, + c_head, + c_torso, + c_legs, + c_str_xp, + c_int_xp, + c_dex_xp, + c_psi_xp, + c_con_xp, + c_pos_x, + c_pos_y, + c_pos_z, + c_angle_ud, + c_angle_lr, + c_faction, + c_slot, + c_online, + c_clan, + c_soullight +}; + +RegEx* PChar::mCharnameRegexFilter = NULL; + +PChar::PChar() +{ + mID = 0; + mAccount = 0; + mGender = 0; + mClass = 0; + mProfession = 1; + mFaction = 1; + //mModel = 0; + //mType = 0; + mRealHead = 0; // Base Skin elements, in complement of (computed) mType + mRealTorso = 0; // " Head shouldn't be changeable, except in case of surgery !!! + mRealLegs = 0; // " + mSkin = 0; // Current Skin elements + mHead = 0; // " + mTorso = 0; // " + mLegs = 0; // " + mHeadColor = mTorsoColor = mLegsColor = 0; // " + mHeadDarkness = mTorsoDarkness = mLegsDarkness = 0; // " + + mBodyEffect = 0; + mBodyEffectDensity = 0; + mQuickBeltActiveSlot = INV_WORN_QB_NONE; + + mLookingAt = 0; + mLookAtTimestamp = 0; + mLastUsedWorldObjectId = 0; + + mSpeedOverride = 255; // means no override. Value 0 can be used to forbid any move. + + mLocationLeased = false; // temp until char on-demand load/unload + mLocation = 0; + mStartApt = 0; + mPrimaryApt = 0; + mCash = 0; + + mSeatInUseType = seat_none; + mSeatInUseObjectId = 0; + mSeatInUseSeatId = 0; + mVhcAccessRequestList = NULL; + + mContainerInExclusiveUse = NULL; + + mIsOnline = false; + mDirtyFlag = false; + + mShunned = false; + mJailed = false; + + mDialogNPC = 0; + mCurrentDialogNode = 0; + + Skill = new PSkillHandler(); + mBuddyList = NULL; + mGenrepList = NULL; + + // Required for initial OOC Broadcast welcome message. + //Gets overwritten as soon as the first PingPacket arrives + mActiveChatChannels = 262144; + mClanLevel = 0; + mClanID = 0; +} + +PChar::~PChar() +{ + // Addition; Set char's online status to OFFLINE + char sqlqry[50]; + snprintf(sqlqry, 50, "UPDATE characters SET c_online = 0 WHERE c_id = %d", mID); + MySQL->GameQuery(sqlqry); + + delete Skill; + delete mBuddyList; + delete mGenrepList; + delete mVhcAccessRequestList; + + if ( mContainerInExclusiveUse ) + { + mContainerInExclusiveUse->EndUse( mID ); + Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still had exclusive use of container. Now freed." ); + } + + if ( mSeatInUseType != seat_none ) + { + Console->Print( RED, BLACK, "Warning: PChar::~PChar : Char still using seat %d of vhc or chair %d.", mSeatInUseSeatId, mSeatInUseObjectId ); + } +} + +bool PChar::SetCharnameRegexFilter( const char* RegexStr ) +{ + if ( mCharnameRegexFilter ) + { + delete mCharnameRegexFilter; + mCharnameRegexFilter = NULL; + } + + if ( RegexStr ) + { + try + { + mCharnameRegexFilter = new RegEx( RegexStr, PCRE_CASELESS ); + } + catch ( ... ) + { + return false; + } + } + return true; +} + +bool PChar::IsCharnameWellFormed( const char *Charname ) +{ + if ( mCharnameRegexFilter ) + { + return mCharnameRegexFilter->Search( Charname ); + } + else + return true; +} + +void PChar::SetProfession( uint32_t Profession ) +{ + const PDefCharKind *def = GameDefs->CharKinds()->GetDef( Profession ); + if ( def == NULL ) + { + Console->Print( RED, BLACK, "Char %d: Invalid profession %d", mID, Profession ); + mProfession = 10; + mClass = 0; + } + else + { + mProfession = Profession; + mClass = def->GetType(); + } + SetDirtyFlag(); +} + +uint32_t PChar::GetSkinFromCharType( uint32_t nType ) +{ + const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType ); + if ( nDefCharacter ) + { + return (( uint32_t )( nDefCharacter->GetModel() ) ); + } + else + return 0; +} + +inline uint32_t PChar::GetBaseModel() +{ + return GetSkinFromCharType( GetType() ); +} + +void PChar::SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs ) +{ + mRealHead = nHead; + mRealTorso = nTorso; + mRealLegs = nLegs; + SetDirtyFlag(); + ResetCurrentLook(); +} + +void PChar::GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ) +{ + nSkin = GetBaseModel(); + nHead = mRealHead; + nTorso = mRealTorso; + nLegs = mRealLegs; +} + +void PChar::SetCurrentLookFromCharType( uint32_t nType ) +{ + int iHead, iTorso, iLegs; + uint32_t nSkin, nHead, nTorso, nLegs; + uint8_t nColor, nBrightness; + + const PDefCharacter* nDefCharacter = GameDefs->Chars()->GetDef( nType ); + if ( nDefCharacter ) + { + nSkin = ( uint32_t ) nDefCharacter->GetModel(); + iHead = nDefCharacter->GetHead(); + iTorso = nDefCharacter->GetTorso(); + iLegs = nDefCharacter->GetLegs(); + nColor = ( uint8_t )( 0xff & nDefCharacter->GetColor() ); + nBrightness = ( uint8_t )( 0xff & nDefCharacter->GetBrightness() ); + + + if (( iHead < 0 ) || ( iTorso < 0 ) || ( iLegs < 0 ) ) + { + nHead = nTorso = nLegs = 0; + } + else + { + nHead = iHead % 10; + nTorso = iTorso % 10; + nLegs = iLegs % 10; + } + + SetCurrentLook( nSkin, nHead, nTorso, nLegs ); + SetCurrentBodyColor( nColor, nColor, nColor, nBrightness, nBrightness, nBrightness ); + } +} + +void PChar::SetCurrentLook( uint32_t nSkin, uint32_t nHead, uint32_t nTorso, uint32_t nLegs ) +{ + mSkin = nSkin; + mHead = nHead; + mTorso = nTorso; + mLegs = nLegs; + // Ingame skin update will be done automagically in the normal update flow + // A flag could also be set somewhere (preferably in Char si that we don't have to care if ingame or not) + // to request quicker ingame update +} + +void PChar::ResetCurrentLook() +{ + SetCurrentLook( GetSkinFromCharType( GetType() ), mRealHead, mRealTorso, mRealLegs ); +} + +// GetCurrentLook will later have to take Power Armors and GM overrides into account +void PChar::GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ) +{ + nSkin = mSkin; + nHead = mHead; + nTorso = mTorso; + nLegs = mLegs; +} + +void PChar::SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness, uint8_t nTorsoDarkness, uint8_t nLegsDarkness ) +{ + mHeadColor = nHeadColor; + mTorsoColor = nTorsoColor; + mLegsColor = nLegsColor; + mHeadDarkness = nHeadDarkness; + mTorsoDarkness = nTorsoDarkness; + mLegsDarkness = nLegsDarkness; +} + +void PChar::GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness ) +{ + nHeadColor = mHeadColor; + nTorsoColor = mTorsoColor; + nLegsColor = mLegsColor; + nHeadDarkness = mHeadDarkness; + nTorsoDarkness = mTorsoDarkness; + nLegsDarkness = mLegsDarkness; +} + +void PChar::SetBaseSkills() +{ + const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession ); + //Console->Print(YELLOW, BLACK, "PChar::SetBaseSkills() Profession: %d",def->GetIndex()); + if ( def == NULL ) + { + Console->Print( RED, BLACK, "PChar::SetBaseSkills: GetCharKindDef=NULL" ); + return; + } + Skill->SetMainSkill( MS_INT, def->GetSkillInfo( MS_INT ).mStart ); + Skill->SetMainSkill( MS_CON, def->GetSkillInfo( MS_CON ).mStart ); + Skill->SetMainSkill( MS_DEX, def->GetSkillInfo( MS_DEX ).mStart ); + Skill->SetMainSkill( MS_STR, def->GetSkillInfo( MS_STR ).mStart ); + Skill->SetMainSkill( MS_PSI, def->GetSkillInfo( MS_PSI ).mStart ); + // management of SP needed ? NC Client seem to calculate what remains ... + // or put SP setting after subskill setting ? + /* Skill->SetSP(MS_INT, (short) ??? )); + Skill->SetSP(MS_CON, ((short) ??? )); + Skill->SetSP(MS_DEX, (short) ??? )); + Skill->SetSP(MS_STR, (short) ??? )); + Skill->SetSP(MS_PSI, ((short) ??? )); */ + // what about XPs ? + /* Skill->SetXP(MS_INT, ??? )); + Skill->SetXP(MS_CON, ??? )); + Skill->SetXP(MS_DEX, ??? )); + Skill->SetXP(MS_STR, ??? )); + Skill->SetXP(MS_PSI, ??? )); */ + Console->Print( YELLOW, BLACK, "PChar::SetBaseSkills() not fully functionnal - unused skill points will be lost" ); +} + +void PChar::SetBaseSubskills( uint8_t NSZNb, const char* NonZeroSubskills ) +{ + int i; + + if ( NSZNb == 0 ) + return; + + for ( i = 0; i < NSZNb; i++ ) + { + Skill->SetSubSkill(( SUB_SKILLS ) NonZeroSubskills[2 * i], ( int ) NonZeroSubskills[2 * i +1] ); + } +} + +void PChar::SetBaseInventory() +{ + uint8_t i; + uint32_t BaseItemID; + const PDefCharKind *def = GameDefs->CharKinds()->GetDef( mProfession ); + + //mCash = 5000; + mCash = def->GetStartMoney(); + + for ( i = 0; i < 8 ; i++ ) + { + BaseItemID = def->GetStartInventory( i ); + if ( BaseItemID ) + { + if ( gDevDebug ) Console->Print( GREEN, BLACK, "Adding item %d to base inventory", BaseItemID ); + PItem* NewItem = new PItem( BaseItemID ); + if ( NewItem->GetItemID() ) + { + NewItem->MakeItemStandard( 120, 180 ); // global quality range + mInventory.AddItem( NewItem ); + } + else + { + Console->Print( RED, BLACK, "Invalid item ID %d in base inventory for profession %d", BaseItemID, mProfession ); + } + } + } +} + +void PChar::LoadClanLevel() +{ + MYSQL_RES *result; + char query[200]; + + snprintf(query, 200, "SELECT cll_level FROM clanlevels WHERE cll_charid = %d AND cll_clanid = %d", mID, mClanID); + result = MySQL->GameResQuery( query ); + if ( result == NULL ) + { + mClanID = 0; + Console->Print( RED, BLACK, "PChar::GetClanLevel could not load ClanLevel from the database" ); + Console->Print( "Query was:" ); + Console->Print( "%s", query ); + MySQL->ShowGameSQLError(); + return; + } + else if(mysql_num_rows(result) == 0) + { + mClanID = 0; + Console->Print( RED, BLACK, "PChar::GetClanLevel No level entry found for clan!" ); + return; + } + mClanLevel = atoi(mysql_fetch_row(result)[0]); + if (gDevDebug) Console->Print("Loaded ClanLevel %d for char %d, clan %d", mClanLevel, mID, mClanID); +} + +bool PChar::SQLLoad( int CharID ) +{ + MYSQL_RES *result; + MYSQL_ROW row; + char query[1024]; + + snprintf( query, 1024, "SELECT * FROM characters WHERE c_id = %d LIMIT 1", CharID ); + result = MySQL->GameResQuery( query ); + if ( result == NULL ) + { + Console->Print( RED, BLACK, "PChar::SQLLoad could not load Chardata from the database" ); + Console->Print( "Query was:" ); + Console->Print( "%s", query ); + MySQL->ShowGameSQLError(); + return false; + } + if (( row = mysql_fetch_row( result ) ) ) + { + SetID( CharID ); + SetName( row[c_name] ); + SetAccount( atoi( row[a_id] ) ); + + // Gender + int genvalue = atoi( row[c_sex] ); + if (( genvalue == 0 ) || ( genvalue == 1 ) ) + mGender = static_cast( genvalue ); + else + { + Console->Print( RED, BLACK, "Bad gender value: %d (Char ID %d)", genvalue, mID ); + mGender = 0; + } + + // Profession + int profvalue = atoi( row[c_profession] ); + SetProfession( static_cast( profvalue ) ); + + // Class + //int classvalue = atoi(row[c_class]); + //if(classvalue < 4) + // mClass = static_cast(classvalue); + //else + //{ + // Console->Print(RED, BLACK, "Bad class value: %d (Char ID %d)", classvalue, mID); + // classvalue = 0; + //} + + // Faction + int facvalue = atoi( row[c_faction] ); + if ( GameDefs->Factions()->GetDef( facvalue ) ) + mFaction = static_cast( facvalue ); + else + mFaction = 1; + + /* // Model + int modvalue = atoi(row[c_model]); + mModel = static_cast(modvalue); + mModel = 10; */ + int headvalue = atoi( row[c_head] ); + int torsovalue = atoi( row[c_torso] ); + int legsvalue = atoi( row[c_legs] ); + SetRealLook( static_cast( headvalue ), static_cast( torsovalue ), static_cast( legsvalue ) ); + + // Type + /* + int typevalue = std::atoi(row[c_type]); + mType = static_cast(typevalue); + //mType = 1; */ + + // Location + int locvalue = atoi( row[c_location] ); + mLocation = static_cast( locvalue ); + +//This assumption is not so good ... hardcoding jailed state linked with location ... + if ( mLocation == 550 || mLocation == 551 ) + mJailed = true; + + int posvalue = atoi( row[c_pos_x] ); + Coords.mX = static_cast( posvalue ); + posvalue = atoi( row[c_pos_y] ); + Coords.mY = static_cast( posvalue ); + posvalue = atoi( row[c_pos_z] ); + Coords.mZ = static_cast( posvalue ); + posvalue = atoi( row[c_angle_ud] ); + Coords.mUD = static_cast( posvalue ); + posvalue = atoi( row[c_angle_lr] ); + Coords.mLR = static_cast( posvalue ); + + int primapt = atoi( row[c_apt] ); + mPrimaryApt = static_cast( primapt ); + mStartApt = mPrimaryApt; + + mSoullight = atoi( row[c_soullight] ); + mClanID = atoi( row[c_clan] ); + if(mClanID > 0) + LoadClanLevel(); + + // Cash + float cashvalue = atof( row[c_cash] ); + mCash = static_cast( cashvalue ); + + // --------------------------------------------- + // Loading skills --- MAIN Skills with SP and XP + // --------------------------------------------- + Skill->SetMainSkill( MS_INT, atoi( row[c_int_lvl] ) ); + Skill->SetMainSkill( MS_CON, atoi( row[c_con_lvl] ) ); + Skill->SetMainSkill( MS_DEX, atoi( row[c_dex_lvl] ) ); + Skill->SetMainSkill( MS_STR, atoi( row[c_str_lvl] ) ); + Skill->SetMainSkill( MS_PSI, atoi( row[c_psi_lvl] ) ); + // --------------------------------------------- + Skill->SetSP( MS_INT, ( short )atoi( row[c_int_pts] ) ); + Skill->SetSP( MS_CON, ( short )atoi( row[c_con_pts] ) ); + Skill->SetSP( MS_DEX, ( short )atoi( row[c_dex_pts] ) ); + Skill->SetSP( MS_STR, ( short )atoi( row[c_str_pts] ) ); + Skill->SetSP( MS_PSI, ( short )atoi( row[c_psi_pts] ) ); + // --------------------------------------------- + Skill->SetXP( MS_INT, atof( row[c_int_xp] ) ); + Skill->SetXP( MS_CON, atof( row[c_con_xp] ) ); + Skill->SetXP( MS_DEX, atof( row[c_dex_xp] ) ); + Skill->SetXP( MS_STR, atof( row[c_str_xp] ) ); + Skill->SetXP( MS_PSI, atof( row[c_psi_xp] ) ); + // --------------------------------------------- + // SubSkills + // --------------------------------------------- + Skill->SetSubSkill( SK_MC, atoi( row[c_mc] ) ); + Skill->SetSubSkill( SK_HC, atoi( row[c_hc] ) ); + Skill->SetSubSkill( SK_TRA, atoi( row[c_tra] ) ); + Skill->SetSubSkill( SK_FOR, atoi( row[c_for] ) ); + Skill->SetSubSkill( SK_PC, atoi( row[c_pc] ) ); + Skill->SetSubSkill( SK_RC, atoi( row[c_rc] ) ); + Skill->SetSubSkill( SK_TC, atoi( row[c_tc] ) ); + Skill->SetSubSkill( SK_VHC, atoi( row[c_vhc] ) ); + Skill->SetSubSkill( SK_AGL, atoi( row[c_agl] ) ); + Skill->SetSubSkill( SK_REP, atoi( row[c_rep] ) ); + Skill->SetSubSkill( SK_REC, atoi( row[c_rec] ) ); + Skill->SetSubSkill( SK_RCL, atoi( row[c_rcl] ) ); + Skill->SetSubSkill( SK_ATL, atoi( row[c_atl] ) ); + Skill->SetSubSkill( SK_END, atoi( row[c_end] ) ); + Skill->SetSubSkill( SK_FIR, atoi( row[c_fir] ) ); + Skill->SetSubSkill( SK_ENR, atoi( row[c_enr] ) ); + Skill->SetSubSkill( SK_XRR, atoi( row[c_xrr] ) ); + Skill->SetSubSkill( SK_POR, atoi( row[c_por] ) ); + Skill->SetSubSkill( SK_HLT, atoi( row[c_hlt] ) ); + Skill->SetSubSkill( SK_HCK, atoi( row[c_hck] ) ); + Skill->SetSubSkill( SK_BRT, atoi( row[c_brt] ) ); + Skill->SetSubSkill( SK_PSU, atoi( row[c_psu] ) ); + Skill->SetSubSkill( SK_WEP, atoi( row[c_wep] ) ); + Skill->SetSubSkill( SK_CST, atoi( row[c_cst] ) ); + Skill->SetSubSkill( SK_RES, atoi( row[c_res] ) ); + Skill->SetSubSkill( SK_IMP, atoi( row[c_imp] ) ); + Skill->SetSubSkill( SK_PPU, atoi( row[c_ppu] ) ); + Skill->SetSubSkill( SK_APU, atoi( row[c_apu] ) ); + Skill->SetSubSkill( SK_MST, atoi( row[c_mst] ) ); + Skill->SetSubSkill( SK_PPW, atoi( row[c_ppw] ) ); + Skill->SetSubSkill( SK_PSR, atoi( row[c_psr] ) ); + Skill->SetSubSkill( SK_WPW, atoi( row[c_wpw] ) ); + // -------------------------------------------- + // Inventory + // --------------------------------------------- + mInventory.SetCharId( mID ); + mInventory.SQLLoad(); + + // temp value forcing, not get/saved from DB atm + mCombatRank = ( uint8_t )( random() % 127 ); // bad result there on randomness + mSynaptic = 0; + mIsDead = false; + + mDirectCharID = 0; // until saved/loaded with char + mBuddyList = new PBuddyList( mID ); + if ( !mBuddyList->SQLLoad() ) + { + Console->Print( RED, BLACK, "Char ID %d : Can't load buddy list", mID ); + } + //to add: Chats settings + + mGenrepList = new PGenrepList( mID ); + if ( !mGenrepList->SQLLoad() ) + { + Console->Print( RED, BLACK, "Char ID %d : Can't load genrep list", mID ); + } + + } + MySQL->FreeGameSQLResult( result ); + + // Addition; Set char's online status to ONLINE + char sqlqry[50]; + snprintf(sqlqry, 50, "UPDATE characters SET c_online = 1 WHERE c_id = %d", mID); + MySQL->GameQuery(sqlqry); + + return true; +} + +bool PChar::SQLCreate() // Specific method for creation in order to avoid existence check with each save +{ + std::string query, queryv; + + query = "INSERT INTO characters (c_id"; + queryv = ") VALUES (NULL"; + + query += ",c_name"; + queryv = queryv + ",'" + mName + "'"; + + query += ",a_id"; + queryv += Ssprintf( ",'%u'", mAccount ); + query += ",c_class"; + queryv += Ssprintf( ",'%u'", mClass ); + query += ",c_sex"; + queryv += Ssprintf( ",'%u'", mGender ); + query += ",c_profession"; + queryv += Ssprintf( ",'%u'", mProfession ); + query += ",c_faction"; + queryv += Ssprintf( ",'%u'", mFaction ); + query += ",c_head"; + queryv += Ssprintf( ",'%u'", mRealHead ); + query += ",c_torso"; + queryv += Ssprintf( ",'%u'", mRealTorso ); + query += ",c_legs"; + queryv += Ssprintf( ",'%u'", mRealLegs ); + //query += ",c_model"; + //queryv += Ssprintf(",'%u'", mModel); + //query += ",c_type"; + //queryv += Ssprintf(",'%u'", mType); + query += ",c_location"; + queryv += Ssprintf( ",'%u'", mLocation ); + query += ",c_cash"; + queryv += Ssprintf( ",'%u'", mCash ); + query += ",c_slot"; + queryv += Ssprintf( ",'%u'", mSlot ); + + query = query + queryv + ");"; + + if ( MySQL->GameQuery( query.c_str() ) ) + { + Console->Print( RED, BLACK, "PChar::SQLCreate could not add char %s to database", mName.c_str() ); + Console->Print( "Query was:" ); + Console->Print( "%s", query.c_str() ); + MySQL->ShowGameSQLError(); + return false; + } + else + { + mID = MySQL->GetLastGameInsertId(); +//Console->Print(GREEN, BLACK, "New char %s got ID %d", mName.c_str(), mID); + mDirtyFlag = true; + return true; + } +} + +bool PChar::CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction, + uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot ) +{ + SetName( Name ); + SetGender( Gender ); + SetProfession( Profession ); + SetFaction( Faction ); + SetRealLook( Head, Torso, Legs ); + SetBaseSkills(); + SetBaseSubskills( NZSNb, NonZeroSubskills ); + SetBaseInventory(); + SetAccount( Account ); + SetCharSlot( Slot ); + mLocation = Config->GetOptionInt( "new_char_location" ); + + // This part will have to be rewritten with proper methods + mSoullight = 10; + mCombatRank = ( uint8_t )( random() % 80 ); // bad result there on randomness + mSynaptic = 0; + mIsDead = false; + + mDirectCharID = 0; // until saved/loaded with char + + SetDirtyFlag(); + + if ( SQLCreate() ) // mID isn't defined before that + { + mBuddyList = new PBuddyList( mID ); + mGenrepList = new PGenrepList( mID ); + mStartApt = mPrimaryApt = Appartements->CreateBaseAppartement( mID, mName, mFaction ); + mInventory.SetCharId( mID ); + + if ( mStartApt && SQLSave() && mInventory.SQLSave() ) + { + return true; + } + else + { + Console->Print( YELLOW, BLACK, "New char %s (id %d) : creation aborted", mName.c_str(), mID ); + if ( mID ) + { + SQLDelete(); + if ( mStartApt ) + { + Appartements->DeleteCharAppartements( mID ); + } + } + } + } + return false; +} + +bool PChar::SQLSave() +{ + std::string query; + //std::string ts; + + /* TODO: + - Mostly at creation/load : + c_apt, (or when first GR to primary apt to avoid creation of unused apt?) + (c_slot) + - At save/load : + SoulLight ??? + FactionSymp[] ??? + Chest change: style, brightness, color + Legs change: style, brightness, color + mHealt, mStamina, mMana (not in DB !!!) + How to compute MaxHealth etc. ? + */ + query = "UPDATE characters SET"; + + query += Ssprintf( " c_location='%u'", mLocation ); + query += Ssprintf( ",c_pos_x='%u'", Coords.mX ); + query += Ssprintf( ",c_pos_y='%u'", Coords.mY ); + query += Ssprintf( ",c_pos_z='%u'", Coords.mZ ); + query += Ssprintf( ",c_angle_ud='%u'", Coords.mUD ); + query += Ssprintf( ",c_angle_lr='%u'", Coords.mLR ); + query += Ssprintf( ",c_cash='%u'", mCash ); + query += Ssprintf( ",c_apt='%u'", mPrimaryApt ); + + query += Ssprintf( ",c_head='%u'", mRealHead ); + query += Ssprintf( ",c_torso='%u'", mRealTorso ); + query += Ssprintf( ",c_legs='%u'", mRealLegs ); + + query += Ssprintf( ",c_faction='%u'", mFaction ); + + /* This group of fiels shouldn't change in-game + query = query + ",c_name='" + mName + "'"; + query += Ssprintf(",a_id='%u'", mAccount); + query += Ssprintf(",c_class='%u'", mClass); + query += Ssprintf(",c_sex='%u'", mGender); + query += Ssprintf(",c_profession='%u'", mProfession); + query += Ssprintf(",c_slot='%u'", mSlot); + // query += Ssprintf(",c_model='%u'", mModel); + // query += Ssprintf(",c_type='%u'", mType); + */ + + // --------------------------------------------- + // Saving skills --- MAIN Skills with SP and XP + // --------------------------------------------- + query += Ssprintf( ",c_int_lvl='%u'", Skill->GetMainSkill( MS_INT ) ); + query += Ssprintf( ",c_con_lvl='%u'", Skill->GetMainSkill( MS_CON ) ); + query += Ssprintf( ",c_dex_lvl='%u'", Skill->GetMainSkill( MS_DEX ) ); + query += Ssprintf( ",c_str_lvl='%u'", Skill->GetMainSkill( MS_STR ) ); + query += Ssprintf( ",c_psi_lvl='%u'", Skill->GetMainSkill( MS_PSI ) ); + // --------------------------------------------- + query += Ssprintf( ",c_int_pts='%u'", Skill->GetSP( MS_INT ) ); + query += Ssprintf( ",c_con_pts='%u'", Skill->GetSP( MS_CON ) ); + query += Ssprintf( ",c_dex_pts='%u'", Skill->GetSP( MS_DEX ) ); + query += Ssprintf( ",c_str_pts='%u'", Skill->GetSP( MS_STR ) ); + query += Ssprintf( ",c_psi_pts='%u'", Skill->GetSP( MS_PSI ) ); + // --------------------------------------------- + query += Ssprintf( ",c_int_xp='%u'", Skill->GetXP( MS_INT ) ); + query += Ssprintf( ",c_con_xp='%u'", Skill->GetXP( MS_CON ) ); + query += Ssprintf( ",c_dex_xp='%u'", Skill->GetXP( MS_DEX ) ); + query += Ssprintf( ",c_str_xp='%u'", Skill->GetXP( MS_STR ) ); + query += Ssprintf( ",c_psi_xp='%u'", Skill->GetXP( MS_PSI ) ); + // --------------------------------------------- + // SubSkills + // --------------------------------------------- + query += Ssprintf( ",c_mc='%u'", Skill->GetSubSkill( SK_MC ) ); + query += Ssprintf( ",c_hc='%u'", Skill->GetSubSkill( SK_HC ) ); + query += Ssprintf( ",c_tra='%u'", Skill->GetSubSkill( SK_TRA ) ); + query += Ssprintf( ",c_for='%u'", Skill->GetSubSkill( SK_FOR ) ); + query += Ssprintf( ",c_pc='%u'", Skill->GetSubSkill( SK_PC ) ); + query += Ssprintf( ",c_rc='%u'", Skill->GetSubSkill( SK_RC ) ); + query += Ssprintf( ",c_tc='%u'", Skill->GetSubSkill( SK_TC ) ); + query += Ssprintf( ",c_vhc='%u'", Skill->GetSubSkill( SK_VHC ) ); + query += Ssprintf( ",c_agl='%u'", Skill->GetSubSkill( SK_AGL ) ); + query += Ssprintf( ",c_rep='%u'", Skill->GetSubSkill( SK_REP ) ); + query += Ssprintf( ",c_rec='%u'", Skill->GetSubSkill( SK_REC ) ); + query += Ssprintf( ",c_rcl='%u'", Skill->GetSubSkill( SK_RCL ) ); + query += Ssprintf( ",c_atl='%u'", Skill->GetSubSkill( SK_ATL ) ); + query += Ssprintf( ",c_end='%u'", Skill->GetSubSkill( SK_END ) ); + query += Ssprintf( ",c_fir='%u'", Skill->GetSubSkill( SK_FIR ) ); + query += Ssprintf( ",c_enr='%u'", Skill->GetSubSkill( SK_ENR ) ); + query += Ssprintf( ",c_xrr='%u'", Skill->GetSubSkill( SK_XRR ) ); + query += Ssprintf( ",c_por='%u'", Skill->GetSubSkill( SK_POR ) ); + query += Ssprintf( ",c_htl='%u'", Skill->GetSubSkill( SK_HLT ) ); + query += Ssprintf( ",c_hck='%u'", Skill->GetSubSkill( SK_HCK ) ); + query += Ssprintf( ",c_brt='%u'", Skill->GetSubSkill( SK_BRT ) ); + query += Ssprintf( ",c_psu='%u'", Skill->GetSubSkill( SK_PSU ) ); + query += Ssprintf( ",c_wep='%u'", Skill->GetSubSkill( SK_WEP ) ); + query += Ssprintf( ",c_cst='%u'", Skill->GetSubSkill( SK_CST ) ); + query += Ssprintf( ",c_res='%u'", Skill->GetSubSkill( SK_RES ) ); + query += Ssprintf( ",c_imp='%u'", Skill->GetSubSkill( SK_IMP ) ); + query += Ssprintf( ",c_ppu='%u'", Skill->GetSubSkill( SK_PPU ) ); + query += Ssprintf( ",c_apu='%u'", Skill->GetSubSkill( SK_APU ) ); + query += Ssprintf( ",c_mst='%u'", Skill->GetSubSkill( SK_MST ) ); + query += Ssprintf( ",c_ppw='%u'", Skill->GetSubSkill( SK_PPW ) ); + query += Ssprintf( ",c_psr='%u'", Skill->GetSubSkill( SK_PSR ) ); + query += Ssprintf( ",c_wpw='%u'", Skill->GetSubSkill( SK_WPW ) ); + // --------------------------------------------- + + query += Ssprintf( " WHERE c_id='%u' LIMIT 1;", mID ); + + if ( MySQL->GameQuery( query.c_str() ) ) + { + Console->Print( RED, BLACK, "PChar::SQLSave could not save char %s (%u) to database", mName.c_str(), mID ); + Console->Print( "Query was:" ); + Console->Print( "%s", query.c_str() ); + MySQL->ShowGameSQLError(); + return false; + } + + // Chats settings (?), directs + + mDirtyFlag = false; + return true; +} + +bool PChar::SQLDelete() +{ + return true; +} + +void PChar::SetOnlineStatus( bool IsOnline ) +{ + // Deactivated, until Maxx added c_isonline row to `characters` + //char query[255]; + int onlinestatus = 0; + + if ( IsOnline ) + { + onlinestatus = 0; // Strange ???? + mIsOnline = true; + } + else + { + onlinestatus = 1; // Strange ???? + mIsOnline = false; + } + +// snprintf(query, 255, "UPDATE charlist SET c_isonline = %d WHERE a_id = %d AND c_id = %d", onlinestatus, mAccount, mID); +// if(MySQL->Query(query)) +// { +// Console->Print("Error: Cant set onlinestatus to '%d' for Account: %d, Char: %d", onlinestatus, mAccount, mID); +// MySQL->ShowSQLError(); +// return; +// } + return; +} + +uint8_t PChar::GetCombatRank() +{ + // Override for Special Account Levels + PAccount Acc(mAccount); + if(Acc.GetLevel() == PAL_ADMIN) + return 127; + else if(Acc.GetLevel() >= PAL_GM) + return 120; + else if(Acc.GetLevel() >= PAL_VOLUNTEER) + return 50; + else + return mCombatRank; +} + + +uint8_t PChar::GetMainRank() +{ + // Override for Special Account Levels + PAccount Acc(mAccount); + if(Acc.GetLevel() == PAL_ADMIN) + return 127; + else if(Acc.GetLevel() >= PAL_GM) + return 120; + else if(Acc.GetLevel() >= PAL_VOLUNTEER) + return 50; + else + { + uint16_t total; + total = Skill->GetMainSkill( MS_STR ) + Skill->GetMainSkill( MS_DEX ); + total += Skill->GetMainSkill( MS_CON ) + Skill->GetMainSkill( MS_INT ); + total += Skill->GetMainSkill( MS_PSI ); + return (( uint8_t )( total / 5 ) ); + } +} + +bool PChar::AddGenrep(uint16_t nWorldID, uint16_t nStationID) +{ + return mGenrepList->AddGenrep(nWorldID, nStationID ); +} + +uint16_t PChar::GetGenrepListDataSize() +{ + return mGenrepList->GetListDataSize(); +} + +const void *PChar::GetGenrepListData() +{ + return mGenrepList->GetListData(); +} + +uint8_t PChar::GetGenrepCount() +{ + return mGenrepList->Count(); +} + +uint32_t PChar::AddCash( uint32_t nAmount ) +{ + return SetCash(nAmount + mCash); +} + +uint32_t PChar::TakeCash( uint32_t nAmount ) +{ + if(nAmount > mCash) + { + //Tries to take away more cash that user has, set to zero + return SetCash(0); + } + else + { + return SetCash(mCash-nAmount); + } +} + +uint32_t PChar::SetCash( uint32_t nCash ) +{ + //Console->Print("Trying to set cash to nCash: %d", nCash); + if (( int )nCash > Config->GetOptionInt( "max_cash" ) ) + { + //Console->Print("Newcash would be more than dynamic maxcash, setting to maxcash"); + mCash = ( uint32_t )Config->GetOptionInt( "max_cash" ); + } + else if ( nCash > MAXCASH ) + { + //Console->Print("Newcash would be more than hardcoded maxcash, setting to maxcash"); + mCash = MAXCASH; + } + else + { + //Console->Print("Allright, setting to new value"); + mCash = nCash; + } + //Console->Print("Returning mCash: %d", mCash); + return mCash; +} + + +bool PChar::SetQuickBeltActiveSlot( uint8_t nSlotID ) +{ + if (( nSlotID == INV_WORN_QB_HAND ) || ( nSlotID == INV_WORN_QB_NONE ) ) + { + mQuickBeltActiveSlot = nSlotID; + return true; + } + else if ( nSlotID <= ( INV_WORN_QB_END - INV_WORN_QB_START ) ) + { + PContainer* tWorn = mInventory.GetContainer( INV_LOC_WORN ); + + if ( ! tWorn->IsSlotFree( nSlotID ) ) // => TODO: MUST ALSO CHECK that item is currently usable and can be held in hand + { + mQuickBeltActiveSlot = nSlotID; + return true; + } + else + { + Console->Print( "SetQuickBeltActiveSlot: SlotID %d greater than %d or free (%d)", nSlotID, INV_WORN_QB_END - INV_WORN_QB_START, tWorn->IsSlotFree( nSlotID ) ); + } + } + return false; +} + +PSeatType PChar::GetSeatInUse( uint32_t* nObjectId, uint8_t* nSeatId ) +{ + if ( nObjectId ) + { + *nObjectId = mSeatInUseObjectId; + } + if ( nSeatId ) + { + *nSeatId = mSeatInUseSeatId; + } + + return mSeatInUseType; +} + +void PChar::SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId, uint8_t nSeatId ) +{ + mSeatInUseType = nSeatType; + mSeatInUseObjectId = nObjectId; + mSeatInUseSeatId = nSeatId; +} + +PVhcAccessRequestList* PChar::GetVhcAccessRequestList() +{ + if( ! mVhcAccessRequestList ) + mVhcAccessRequestList = new PVhcAccessRequestList(); + + return mVhcAccessRequestList; +} + +void PChar::SetLookingAt( uint16_t nLocalCharID ) +{ + mLookingAt = nLocalCharID; + mLookAtTimestamp = std::time( NULL ); +} + +uint16_t PChar::GetLookingAt( uint16_t nMaxDelaySec ) +{ + return ((( mLookAtTimestamp + nMaxDelaySec ) >= std::time( NULL ) ) ? mLookingAt : 0 ); +} + +// =================================== + +PChars::PChars() +{ + mLastID = 0; + mLastSave = std::time( NULL ); + + mAutoSavePeriod = Config->GetOptionInt( "auto_save_period" ); + if ( mAutoSavePeriod < 0 ) + { + Console->Print( "%s auto_save_period (%d) must be strict positive.", Console->ColorText( RED, BLACK, "[Error]" ), mAutoSavePeriod ); + mAutoSavePeriod = 0; + } + else if ( mAutoSavePeriod > 3600 ) + { + Console->Print( "%s auto_save_period (%d) too high. Forced to 3600 sec.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod ); + mAutoSavePeriod = 0; + } + + if ( mAutoSavePeriod == 0 ) + { + Console->Print( "%s Auto-save disabled.", Console->ColorText( YELLOW, BLACK, "[Info]" ) ); + } + else if ( mAutoSavePeriod < 60 ) + { + Console->Print( "%s auto_save_period (%d) is low and might lead to high server load.", Console->ColorText( YELLOW, BLACK, "[Warning]" ), mAutoSavePeriod ); + } + +} + +PChars::~PChars() +{ + for ( CharMap::iterator i = mChars.begin(); i != mChars.end(); i++ ) + delete i->second; +} + +bool PChars::LoadChar( uint32_t CharID ) +{ + if ( !CharID ) + return false; + + PChar *nChar = new PChar(); + if ( nChar->SQLLoad( CharID ) ) + { + nChar->SetDirtyFlag( false ); + return AddChar( nChar ); + } + else + { + Console->Print( RED, BLACK, "[ERROR] Could not load char id %d from database", CharID ); + return false; + } +} + +bool PChars::AddChar( PChar* nChar ) +{ + if ( !nChar ) + return false; + + mLastID = std::max( mLastID, nChar->GetID() ); + if ( mChars.insert( std::make_pair( nChar->GetID(), nChar ) ).second ) + { + if ( gDevDebug ) + Console->Print( "%s Char: %s (id %d) added", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nChar->GetName().c_str() , nChar->GetID() ); + return true; + } + else + { + Console->Print( RED, BLACK, "[ERROR] Trying to load char twice : %s (id %d)", nChar->GetName().c_str(), nChar->GetID() ); + return false; + } +} + +PChar* PChars::RemoveChar( uint32_t CharID ) +{ + PChar* Result = NULL; + + CharMap::iterator i = mChars.find( CharID ); + if ( i != mChars.end() ) + { + Result = i->second; + mChars.erase( i ); + if ( gDevDebug ) + Console->Print( "%s Char: %s (id %d) removed", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Result->GetName().c_str() , Result->GetID() ); + } + + return Result; +} + +void PChars::SQLSave() +{ + // saves all dirty-flagged chars + int nDirtyChars = 0, nSavedChars = 0; + int nDirtyInv = 0, nSavedInv = 0; + + for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ ) + { + PChar* Char = i->second; + if ( Char->IsDirty() ) + { + ++nDirtyChars; + if ( Char->SQLSave() ) + ++nSavedChars; + } + if ( Char->GetInventory()->IsDirty() ) + { + ++nDirtyInv; + if ( Char->GetInventory()->SQLSave() ) + ++nSavedInv; + } + } + Console->Print( "%s %i chars saved on %i dirty, %i inventories saved on %i dirty", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nSavedChars, nDirtyChars, nSavedInv, nDirtyInv ); + return; +} + +PChar* PChars::GetChar( uint32_t CharID ) const +{ + PChar *Result = 0; + CharMap::const_iterator i = mChars.find( CharID ); + if ( i != mChars.end() ) + Result = i->second; + + return Result; +} + +PChar* PChars::GetChar( const std::string &Name ) const +{ + PChar *Result = 0; + for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ ) + { + if ( !/*std::*/strcasecmp( i->second->GetName().c_str(), Name.c_str() ) ) + { + Result = i->second; + break; + } + } + return Result; +} + +bool PChars::CharExist( const std::string &Name ) const +{ + char query[256]; + int EntriesNb; + MYSQL_RES *result = 0; + + char escUsername[256]; + MySQL->EscapeString( Name.c_str(), escUsername, 256 ); + snprintf( query, 256, "SELECT 1 FROM characters WHERE c_name = '%s' LIMIT 1;", escUsername ); + + result = MySQL->GameResQuery( query ); + if ( result == NULL ) + { + Console->Print( RED, BLACK, "[ERROR] Failed to get CharacterData from SQL" ); + MySQL->ShowGameSQLError(); + return true; + } + + EntriesNb = mysql_num_rows( result ); + MySQL->FreeGameSQLResult( result ); + return( EntriesNb > 0 ); +} + +void PChars::Update() +{ + std::time_t t = std::time( NULL ); // changed to time() to have real time instead of cpu used time + + if ( mAutoSavePeriod && (( t - mLastSave ) >= mAutoSavePeriod ) ) + { + bool NeedSave = false; + for ( CharMap::const_iterator i = mChars.begin(); i != mChars.end(); i++ ) + { + if ( i->second->IsAnyDirty() ) + { + NeedSave = true; + break; + } + } + + if ( NeedSave ) + { + if ( gDevDebug ) Console->Print( "%s Some characters need autosaving...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + SQLSave(); + if ( gDevDebug ) Console->Print( "%s Autosave done.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + } + mLastSave = t; + } +} + +//MAX_CHARS_PER_ACCOUNT +int PChars::GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize ) +{ + char query[256]; + int EntriesNb = 0; + + MYSQL_ROW row = 0; + MYSQL_RES *result = 0; + + snprintf( query, 256, "SELECT * FROM characters WHERE a_id = %d ORDER BY c_slot ASC", AccountID ); + + result = MySQL->GameResQuery( query ); + if ( result == NULL ) + { + Console->Print( RED, BLACK, "[ERROR] Failed to load CharacterData from SQL" ); + MySQL->ShowGameSQLError(); + return 0; + } + + //EntriesNb = mysql_num_rows(result); + int SlotID; + uint32_t CharID; + PChar* tmpChar = new PChar(); + + while (( row = mysql_fetch_row( result ) ) ) + { + SlotID = atoi( row[c_slot] ); + CharID = atoi( row[c_id] ); + if (( SlotID >= 0 ) && ( SlotID < ArraySize ) ) + { + if ( !CharSlotsArray[SlotID].in_use ) + { + tmpChar->SetID( CharID ); + tmpChar->SetGender( atoi( row[c_sex] ) ); + tmpChar->SetProfession( atoi( row[c_profession] ) ); + + CharSlotsArray[SlotID].CharID = CharID; + CharSlotsArray[SlotID].Type = tmpChar->GetType(); + CharSlotsArray[SlotID].Location = static_cast( atoi( row[c_location] ) ); + CharSlotsArray[SlotID].Head = atoi( row[c_head] ); + CharSlotsArray[SlotID].Torso = atoi( row[c_torso] ); + CharSlotsArray[SlotID].Legs = atoi( row[c_legs] ); + CharSlotsArray[SlotID].Name = row[c_name]; + CharSlotsArray[SlotID].NameLen = CharSlotsArray[SlotID].Name.length() + 1; + + CharSlotsArray[SlotID].in_use = true; + ++EntriesNb; + } + else + { + Console->Print( YELLOW, BLACK, "[Warning]Character %d using slot %d already used by char %d - Ignored", \ + CharID, SlotID, CharSlotsArray[SlotID].CharID ); + } + } + else + { + Console->Print( YELLOW, BLACK, "[Warning]Character %d using invialid slot %d - Ignored", CharID, SlotID ); + } + } + + delete tmpChar; + MySQL->FreeGameSQLResult( result ); + return EntriesNb; +} diff --git a/TinNS/Source/GameServer/Chars.hxx b/TinNS/Source/GameServer/Chars.hxx index b2b3030..bb964b6 100644 --- a/TinNS/Source/GameServer/Chars.hxx +++ b/TinNS/Source/GameServer/Chars.hxx @@ -1,335 +1,335 @@ -#pragma once - -#include -#include -#include -#include "GameServer/Inventory.hxx" // FIXME: class design fault - -#define MAXCASH 1000000000 - -class PGenrepList; -class PSkillHandler; -class PVhcAccessRequestList; - -enum PSeatType { - seat_none = 0, - seat_chair, - seat_subway, - seat_vhc -}; - -class PCharCoordinates { - public: - uint16_t mY; // Y-Position in world // Y increases when going East - uint16_t mZ; // Z-Position in world // Z increases when going up - uint16_t mX; // X-Position in world // X increases when going South - uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) - uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179]) - uint8_t mAct; // Last user action state - uint8_t mUnknown;// sometime sent by client with value != 0 (usual case) - // mAct: - // 0x00 NC has no focus (player alt+tab'ed out) - // 0x04 Char on ground/dead 00000100 - // 0x20 Char does nothing 00100000 - // 0x22 kneeing 00100010 - // 0x28 left step 00101000 - // 0x30 right step 00110000 - // 0x40 walking (not running) 01000000 // Seems to mean Running ? - to be verfied, with default walk/run mode !!! - // 0x60 forward 01100000 - // 0xA0 backward 10100000 - // bits: BFWRL.K. - - uint8_t mJumpingState; - - //inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0;} - void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD = 0x80, uint8_t nLR = 0 ); - void SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef ); - - //Temp - uint16_t minPos[3]; - uint16_t maxPos[3]; - inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0; for(int i=0; i<3; ++i) { minPos[i] = 0xffff; maxPos[i] = 0; } } -}; - -class PChar -{ - private : - // static members - static RegEx* mCharnameRegexFilter; - - // instance members - uint32_t mID; - uint32_t mAccount; - uint8_t mSlot; - std::string mName; - uint32_t mGender; - uint32_t mClass; - //uint32_t mType; // Removed that and only keep GetType() - uint32_t mProfession; - uint32_t mFaction; - uint32_t mRealHead; // Base Skin elements, in complement of (computed) mType - uint32_t mRealTorso; // " Head shouldn't be changeable, except in case of surgery !!! - uint32_t mRealLegs; // " - uint32_t mSkin; // Current Skin elements. *** Not saved in DB atm *** - uint32_t mHead; // " - uint32_t mTorso; // " - uint32_t mLegs; // " - uint8_t mHeadColor; // " - uint8_t mTorsoColor; // " - uint8_t mLegsColor; // " - uint8_t mHeadDarkness; // " // 0=Bright, 255=dark - uint8_t mTorsoDarkness; // " - uint8_t mLegsDarkness; // " - // Skin scale factor setting remain to discover, provided they are somewhere for player chars ... - - bool mLocationLeased; // temp until char on-demand load/unload - uint32_t mLocation; - uint32_t mCash; - uint32_t mStartApt; // set same as PrimaryApt atm - uint32_t mPrimaryApt; - - // not saved in DB atm - PSeatType mSeatInUseType; - uint32_t mSeatInUseObjectId; - uint8_t mSeatInUseSeatId; - PVhcAccessRequestList* mVhcAccessRequestList; - - PContainer* mContainerInExclusiveUse; - - uint16_t mHealth; - uint16_t mMana; - uint16_t mStamina; - - int8_t mSoullight; - uint8_t mCombatRank; // *** Not got/saved from DB atm *** - uint8_t mSynaptic; // *** Not got/saved from DB atm *** - bool mIsDead; // *** Not got/saved from DB atm *** - - // Only one body effect supported atm. Should be extended later to multiple effects - uint8_t mBodyEffect; // *** Not got/saved from DB atm *** - uint8_t mBodyEffectDensity; // *** Not got/saved from DB atm *** - - uint8_t mSpeedOverride; // a hack to control move speed. Not saved in DB - - uint32_t mDirectCharID; // for Direct Chat // *** Not got/saved from DB atm *** - PBuddyList* mBuddyList; // For Buddy list Chat - uint32_t mActiveChatChannels; // Active chat channels flags // *** Not got/saved from DB atm *** - - PGenrepList* mGenrepList; // Character's GR list - - uint8_t mQuickBeltActiveSlot; // QB SlotID of item "in hand", or INV_WORN_QB_HAND or INV_WORN_QB_NONE - - uint16_t mLookingAt; // Zone charID of currently targeted player - std::time_t mLookAtTimestamp; // Lifetimer of lookat var - uint32_t mLastUsedWorldObjectId; // Last world object clicked on - - uint8_t mClanLevel; // 1-15 - uint16_t mClanID; - - bool mIsOnline; - bool mDirtyFlag; - - bool mShunned; - bool mJailed; - - uint32_t mDialogNPC; // NPCID the player talks to - uint16_t mCurrentDialogNode; // Node in .lua file we're at right now - - class PInventory mInventory; - - protected : - friend class PChars; - inline void SetID( uint32_t ID ) { mID = ID; } - inline void SetAccount( uint32_t Account ) { mAccount = Account; } - inline void SetCharSlot( uint8_t Slot ) { if ( Slot < 4 ) mSlot = Slot;} // TODO: set max slot according to server config - inline void SetName( const std::string &Name ) { mName = Name; } - inline void SetGender( uint32_t Gender ) { mGender = Gender; } - void SetProfession( uint32_t Profession ); - //inline void SetClass(uint32_t nClass) { mClass = nClass; } // mClass is defined by setting Profession - //inline void SetType(uint32_t Type) { mType = Type; } // Removed. Type is computed from Gender & Profession (??? is it not Gender + Class ???) - inline void SetFaction( uint32_t Faction ) { mFaction = Faction; } - //inline void SetModel(uint32_t Model) { mModel = Model; } // Inhibited for the moment. Base model is deduced from from Gender & Class (Profession) - void SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs ); - void SetBaseSkills(); - void SetBaseSubskills( uint8_t NZSNb, const char* NonZeroSubskills ); - void SetBaseInventory(); - - bool SQLCreate(); - - public : - PChar(); - ~PChar(); - - static bool SetCharnameRegexFilter( const char* RegexStr ); - static bool IsCharnameWellFormed( const char *Username ); - - PSkillHandler *Skill; - PCharCoordinates Coords; - - void SetCurrentLook( uint32_t nSkin, uint32_t nHead = 0, uint32_t nTorso = 0, uint32_t nLegs = 0 ); - void SetCurrentLookFromCharType( uint32_t nType ); - void ResetCurrentLook(); - - void SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness = 0, uint8_t nTorsoDarkness = 0, uint8_t nLegsDarkness = 0 ); - inline void SetBodyEffect( uint8_t nEffect, uint8_t nDensity = 0 ) { mBodyEffect = nEffect; mBodyEffectDensity = nDensity; } - inline void SetSpeedOverride( uint8_t nSpeed = 255 ) { mSpeedOverride = nSpeed; } - - void SetLookingAt( uint16_t nLocalCharID ); - uint16_t GetLookingAt( uint16_t nMaxDelaySec = 1 ); - inline void SetLastUsedObject ( uint32_t nRawItemId ) { mLastUsedWorldObjectId = nRawItemId; } - inline uint32_t GetLastUsedObject () const { return mLastUsedWorldObjectId; } - - inline PInventory* GetInventory() { return &mInventory; } - inline uint32_t GetID() const { return mID; } - inline uint32_t GetAccount() const { return mAccount; } - inline const std::string &GetName() const { return mName; } - inline uint32_t GetGender() const { return mGender; } - inline uint32_t GetClass() const { return mClass; } - inline uint32_t GetType() const { return 2 * mClass + mGender; } - uint32_t GetSkinFromCharType( uint32_t nType ); - void GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ); - void GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ); - inline void GetBodyEffect( uint8_t &nEffect, uint8_t &nDensity ) { nEffect = mBodyEffect; nDensity = mBodyEffectDensity; } - - inline uint8_t GetQuickBeltActiveSlot() { return mQuickBeltActiveSlot; } - bool SetQuickBeltActiveSlot( uint8_t nSlotID ); - - void GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness ); - inline uint8_t GetSpeedOverride() { return mSpeedOverride; } - inline uint32_t GetBaseModel(); - inline uint32_t GetProfession() const { return mProfession; } - inline uint16_t GetMaxHealth() { return mHealth; } - inline uint16_t GetMaxMana() { return mMana; } - inline uint16_t GetMaxStamina() { return mStamina; } - inline uint16_t GetHealth() { return mHealth; } - inline uint16_t GetMana() { return mMana; } - inline uint16_t GetStamina() { return mStamina; } - inline uint32_t GetFaction() const { return mFaction; } - inline uint32_t GetLocation() const { return mLocation; } - - inline uint32_t GetCash() const { return mCash; } - uint32_t SetCash( uint32_t nCash ); // Does return the new cashvalue, NO udpmessage is sent out!! - uint32_t AddCash( uint32_t nAmount ); - uint32_t TakeCash( uint32_t nAmount ); - - inline uint32_t GetBaseApartment() const { return mPrimaryApt; } - - inline void SetJail( bool val ) { mJailed = val; }; - inline void SetShun( bool val ) { mShunned = val; }; - - inline bool IsJailed() { return mJailed; }; - inline bool IsShunned() { return mShunned; }; - - inline void SetDialogNPC( uint32_t nNPC ) { mDialogNPC = nNPC; }; - inline uint32_t GetDialogNPC() const { return mDialogNPC; }; - - inline void SetDialogNode( uint16_t nNode ) { mCurrentDialogNode = nNode; }; - inline uint16_t GetDialogNode() const { return mCurrentDialogNode; }; - - inline uint8_t GetClanLevel() const { return mClanLevel; }; - inline uint16_t GetClan() const { return mClanID; }; - void LoadClanLevel(); - - inline int8_t GetSoullight() const { return mSoullight; } - uint8_t GetMainRank(); - uint8_t GetCombatRank(); - inline uint8_t GetSynaptic() const { return mSynaptic; } - inline bool IsDead() const { return mIsDead; } - - inline bool SetDirectChat( uint32_t nBuddyCharID ) { mDirectCharID = nBuddyCharID; return true; } - inline uint32_t GetDirectChat() { return mDirectCharID; } - inline void SetActiveChannels( uint32_t nChannels ) { mActiveChatChannels = nChannels; } - inline uint32_t GetActiveChannels() { return mActiveChatChannels; } - - inline bool AddBuddy( uint32_t nBuddyCharID ) { return mBuddyList->AddChar( nBuddyCharID ); } - inline bool RemoveBuddy( uint32_t nBuddyCharID ) { return mBuddyList->RemoveChar( nBuddyCharID ); } - inline uint16_t GetBuddyListDataSize() { return mBuddyList->GetListDataSize(); } - inline const void* GetBuddyListData() { return mBuddyList->GetListData(); } - inline uint8_t GetBuddyCount() { return mBuddyList->Count(); } - inline bool IsBuddy( uint32_t CharID ) { return mBuddyList->IsInBuddy( CharID ); }; - - bool AddGenrep(uint16_t nWorldID, uint16_t nStationID); - uint16_t GetGenrepListDataSize(); - const void *GetGenrepListData(); - uint8_t GetGenrepCount(); - - inline bool IsDirty() const { return mDirtyFlag; } - inline bool IsAnyDirty() const { return mDirtyFlag || mInventory.IsDirty(); } - inline bool IsOnline() { return mIsOnline; } - void SetOnlineStatus( bool IsOnline ); - - bool CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction, - uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot ); - bool SQLLoad( int CharID ); - bool SQLSave(); - inline bool SQLSaveFull() { return SQLSave() && mInventory.SQLSave(); } - bool SQLDelete(); // not implemented yet - - inline void SetLocation( uint32_t Location ) { mLocation = Location; } - inline void SetDirtyFlag( bool Dirty = true ) { mDirtyFlag = Dirty; } - - // temp until char on-demand load/unload - inline void SetLocationLeased( bool nState = true ) { mLocationLeased = nState; } - inline bool GetLocationLeased() { return mLocationLeased; } - - PSeatType GetSeatInUse( uint32_t* nObjectId = NULL, uint8_t* nSeatId = NULL ); - void SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId = 0, uint8_t nSeatId = 0 ); - - PVhcAccessRequestList* GetVhcAccessRequestList(); - - inline PContainer* GetContainerInExclusiveUse() { return mContainerInExclusiveUse; } - inline void SetContainerInExclusiveUse( PContainer* nContainer ) { mContainerInExclusiveUse = nContainer; } -}; - -struct PCharProfile -{ - uint32_t CharID; - uint16_t Type; - uint16_t Color0; - uint16_t Unknown1; - uint8_t Head; - uint8_t Torso; - uint8_t Legs; - uint32_t Location; - uint8_t NameLen; - uint8_t Unknown3; - uint8_t Unknown4; - uint8_t Unknown5; - uint8_t Unknown6; - uint8_t Unknown7; - uint8_t Unknown8; - uint8_t Unknown9; - uint8_t Unknown10; - uint8_t Unknown11; - uint8_t Unknown12; - std::string Name; - bool in_use; -}; - -class PChars -{ - private : - typedef std::map CharMap; - CharMap mChars; - uint32_t mLastID; - - std::time_t mAutoSavePeriod; - std::time_t mLastSave; - - public : - PChars(); - ~PChars(); - - bool LoadChar( uint32_t CharID ); - bool AddChar( PChar* nChar ); - PChar* RemoveChar( uint32_t CharID ); - - PChar* GetChar( uint32_t CharID ) const; - PChar* GetChar( const std::string &Name ) const; - bool CharExist( const std::string &Name ) const; - - void SQLSave(); - void Update(); - - int GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize ); // return effective entries nb -}; +#pragma once + +#include +#include +#include +#include "GameServer/Inventory.hxx" // FIXME: class design fault + +#define MAXCASH 1000000000 + +class PGenrepList; +class PSkillHandler; +class PVhcAccessRequestList; + +enum PSeatType { + seat_none = 0, + seat_chair, + seat_subway, + seat_vhc +}; + +class PCharCoordinates { + public: + uint16_t mY; // Y-Position in world // Y increases when going East + uint16_t mZ; // Z-Position in world // Z increases when going up + uint16_t mX; // X-Position in world // X increases when going South + uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) + uint8_t mLR; // Compass direction (S..E..N..W..S [0-45-90-135-179]) + uint8_t mAct; // Last user action state + uint8_t mUnknown;// sometime sent by client with value != 0 (usual case) + // mAct: + // 0x00 NC has no focus (player alt+tab'ed out) + // 0x04 Char on ground/dead 00000100 + // 0x20 Char does nothing 00100000 + // 0x22 kneeing 00100010 + // 0x28 left step 00101000 + // 0x30 right step 00110000 + // 0x40 walking (not running) 01000000 // Seems to mean Running ? - to be verfied, with default walk/run mode !!! + // 0x60 forward 01100000 + // 0xA0 backward 10100000 + // bits: BFWRL.K. + + uint8_t mJumpingState; + + //inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0;} + void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD = 0x80, uint8_t nLR = 0 ); + void SetInterpolate( PCharCoordinates& Pos1, PCharCoordinates& Pos2, float nCoef ); + + //Temp + uint16_t minPos[3]; + uint16_t maxPos[3]; + inline PCharCoordinates() { mX = mY = mZ = mUD = mLR = mAct = mUnknown = mJumpingState = 0; for(int i=0; i<3; ++i) { minPos[i] = 0xffff; maxPos[i] = 0; } } +}; + +class PChar +{ + private : + // static members + static RegEx* mCharnameRegexFilter; + + // instance members + uint32_t mID; + uint32_t mAccount; + uint8_t mSlot; + std::string mName; + uint32_t mGender; + uint32_t mClass; + //uint32_t mType; // Removed that and only keep GetType() + uint32_t mProfession; + uint32_t mFaction; + uint32_t mRealHead; // Base Skin elements, in complement of (computed) mType + uint32_t mRealTorso; // " Head shouldn't be changeable, except in case of surgery !!! + uint32_t mRealLegs; // " + uint32_t mSkin; // Current Skin elements. *** Not saved in DB atm *** + uint32_t mHead; // " + uint32_t mTorso; // " + uint32_t mLegs; // " + uint8_t mHeadColor; // " + uint8_t mTorsoColor; // " + uint8_t mLegsColor; // " + uint8_t mHeadDarkness; // " // 0=Bright, 255=dark + uint8_t mTorsoDarkness; // " + uint8_t mLegsDarkness; // " + // Skin scale factor setting remain to discover, provided they are somewhere for player chars ... + + bool mLocationLeased; // temp until char on-demand load/unload + uint32_t mLocation; + uint32_t mCash; + uint32_t mStartApt; // set same as PrimaryApt atm + uint32_t mPrimaryApt; + + // not saved in DB atm + PSeatType mSeatInUseType; + uint32_t mSeatInUseObjectId; + uint8_t mSeatInUseSeatId; + PVhcAccessRequestList* mVhcAccessRequestList; + + PContainer* mContainerInExclusiveUse; + + uint16_t mHealth; + uint16_t mMana; + uint16_t mStamina; + + int8_t mSoullight; + uint8_t mCombatRank; // *** Not got/saved from DB atm *** + uint8_t mSynaptic; // *** Not got/saved from DB atm *** + bool mIsDead; // *** Not got/saved from DB atm *** + + // Only one body effect supported atm. Should be extended later to multiple effects + uint8_t mBodyEffect; // *** Not got/saved from DB atm *** + uint8_t mBodyEffectDensity; // *** Not got/saved from DB atm *** + + uint8_t mSpeedOverride; // a hack to control move speed. Not saved in DB + + uint32_t mDirectCharID; // for Direct Chat // *** Not got/saved from DB atm *** + PBuddyList* mBuddyList; // For Buddy list Chat + uint32_t mActiveChatChannels; // Active chat channels flags // *** Not got/saved from DB atm *** + + PGenrepList* mGenrepList; // Character's GR list + + uint8_t mQuickBeltActiveSlot; // QB SlotID of item "in hand", or INV_WORN_QB_HAND or INV_WORN_QB_NONE + + uint16_t mLookingAt; // Zone charID of currently targeted player + std::time_t mLookAtTimestamp; // Lifetimer of lookat var + uint32_t mLastUsedWorldObjectId; // Last world object clicked on + + uint8_t mClanLevel; // 1-15 + uint16_t mClanID; + + bool mIsOnline; + bool mDirtyFlag; + + bool mShunned; + bool mJailed; + + uint32_t mDialogNPC; // NPCID the player talks to + uint16_t mCurrentDialogNode; // Node in .lua file we're at right now + + class PInventory mInventory; + + protected : + friend class PChars; + inline void SetID( uint32_t ID ) { mID = ID; } + inline void SetAccount( uint32_t Account ) { mAccount = Account; } + inline void SetCharSlot( uint8_t Slot ) { if ( Slot < 4 ) mSlot = Slot;} // TODO: set max slot according to server config + inline void SetName( const std::string &Name ) { mName = Name; } + inline void SetGender( uint32_t Gender ) { mGender = Gender; } + void SetProfession( uint32_t Profession ); + //inline void SetClass(uint32_t nClass) { mClass = nClass; } // mClass is defined by setting Profession + //inline void SetType(uint32_t Type) { mType = Type; } // Removed. Type is computed from Gender & Profession (??? is it not Gender + Class ???) + inline void SetFaction( uint32_t Faction ) { mFaction = Faction; } + //inline void SetModel(uint32_t Model) { mModel = Model; } // Inhibited for the moment. Base model is deduced from from Gender & Class (Profession) + void SetRealLook( uint32_t nHead, uint32_t nTorso, uint32_t nLegs ); + void SetBaseSkills(); + void SetBaseSubskills( uint8_t NZSNb, const char* NonZeroSubskills ); + void SetBaseInventory(); + + bool SQLCreate(); + + public : + PChar(); + ~PChar(); + + static bool SetCharnameRegexFilter( const char* RegexStr ); + static bool IsCharnameWellFormed( const char *Username ); + + PSkillHandler *Skill; + PCharCoordinates Coords; + + void SetCurrentLook( uint32_t nSkin, uint32_t nHead = 0, uint32_t nTorso = 0, uint32_t nLegs = 0 ); + void SetCurrentLookFromCharType( uint32_t nType ); + void ResetCurrentLook(); + + void SetCurrentBodyColor( uint8_t nHeadColor, uint8_t nTorsoColor, uint8_t nLegsColor, uint8_t nHeadDarkness = 0, uint8_t nTorsoDarkness = 0, uint8_t nLegsDarkness = 0 ); + inline void SetBodyEffect( uint8_t nEffect, uint8_t nDensity = 0 ) { mBodyEffect = nEffect; mBodyEffectDensity = nDensity; } + inline void SetSpeedOverride( uint8_t nSpeed = 255 ) { mSpeedOverride = nSpeed; } + + void SetLookingAt( uint16_t nLocalCharID ); + uint16_t GetLookingAt( uint16_t nMaxDelaySec = 1 ); + inline void SetLastUsedObject ( uint32_t nRawItemId ) { mLastUsedWorldObjectId = nRawItemId; } + inline uint32_t GetLastUsedObject () const { return mLastUsedWorldObjectId; } + + inline PInventory* GetInventory() { return &mInventory; } + inline uint32_t GetID() const { return mID; } + inline uint32_t GetAccount() const { return mAccount; } + inline const std::string &GetName() const { return mName; } + inline uint32_t GetGender() const { return mGender; } + inline uint32_t GetClass() const { return mClass; } + inline uint32_t GetType() const { return 2 * mClass + mGender; } + uint32_t GetSkinFromCharType( uint32_t nType ); + void GetRealLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ); + void GetCurrentLook( uint32_t &nSkin, uint32_t &nHead, uint32_t &nTorso, uint32_t &nLegs ); + inline void GetBodyEffect( uint8_t &nEffect, uint8_t &nDensity ) { nEffect = mBodyEffect; nDensity = mBodyEffectDensity; } + + inline uint8_t GetQuickBeltActiveSlot() { return mQuickBeltActiveSlot; } + bool SetQuickBeltActiveSlot( uint8_t nSlotID ); + + void GetCurrentBodyColor( uint8_t &nHeadColor, uint8_t &nTorsoColor, uint8_t &nLegsColor, uint8_t &nHeadDarkness, uint8_t &nTorsoDarkness, uint8_t &nLegsDarkness ); + inline uint8_t GetSpeedOverride() { return mSpeedOverride; } + inline uint32_t GetBaseModel(); + inline uint32_t GetProfession() const { return mProfession; } + inline uint16_t GetMaxHealth() { return mHealth; } + inline uint16_t GetMaxMana() { return mMana; } + inline uint16_t GetMaxStamina() { return mStamina; } + inline uint16_t GetHealth() { return mHealth; } + inline uint16_t GetMana() { return mMana; } + inline uint16_t GetStamina() { return mStamina; } + inline uint32_t GetFaction() const { return mFaction; } + inline uint32_t GetLocation() const { return mLocation; } + + inline uint32_t GetCash() const { return mCash; } + uint32_t SetCash( uint32_t nCash ); // Does return the new cashvalue, NO udpmessage is sent out!! + uint32_t AddCash( uint32_t nAmount ); + uint32_t TakeCash( uint32_t nAmount ); + + inline uint32_t GetBaseApartment() const { return mPrimaryApt; } + + inline void SetJail( bool val ) { mJailed = val; }; + inline void SetShun( bool val ) { mShunned = val; }; + + inline bool IsJailed() { return mJailed; }; + inline bool IsShunned() { return mShunned; }; + + inline void SetDialogNPC( uint32_t nNPC ) { mDialogNPC = nNPC; }; + inline uint32_t GetDialogNPC() const { return mDialogNPC; }; + + inline void SetDialogNode( uint16_t nNode ) { mCurrentDialogNode = nNode; }; + inline uint16_t GetDialogNode() const { return mCurrentDialogNode; }; + + inline uint8_t GetClanLevel() const { return mClanLevel; }; + inline uint16_t GetClan() const { return mClanID; }; + void LoadClanLevel(); + + inline int8_t GetSoullight() const { return mSoullight; } + uint8_t GetMainRank(); + uint8_t GetCombatRank(); + inline uint8_t GetSynaptic() const { return mSynaptic; } + inline bool IsDead() const { return mIsDead; } + + inline bool SetDirectChat( uint32_t nBuddyCharID ) { mDirectCharID = nBuddyCharID; return true; } + inline uint32_t GetDirectChat() { return mDirectCharID; } + inline void SetActiveChannels( uint32_t nChannels ) { mActiveChatChannels = nChannels; } + inline uint32_t GetActiveChannels() { return mActiveChatChannels; } + + inline bool AddBuddy( uint32_t nBuddyCharID ) { return mBuddyList->AddChar( nBuddyCharID ); } + inline bool RemoveBuddy( uint32_t nBuddyCharID ) { return mBuddyList->RemoveChar( nBuddyCharID ); } + inline uint16_t GetBuddyListDataSize() { return mBuddyList->GetListDataSize(); } + inline const void* GetBuddyListData() { return mBuddyList->GetListData(); } + inline uint8_t GetBuddyCount() { return mBuddyList->Count(); } + inline bool IsBuddy( uint32_t CharID ) { return mBuddyList->IsInBuddy( CharID ); }; + + bool AddGenrep(uint16_t nWorldID, uint16_t nStationID); + uint16_t GetGenrepListDataSize(); + const void *GetGenrepListData(); + uint8_t GetGenrepCount(); + + inline bool IsDirty() const { return mDirtyFlag; } + inline bool IsAnyDirty() const { return mDirtyFlag || mInventory.IsDirty(); } + inline bool IsOnline() { return mIsOnline; } + void SetOnlineStatus( bool IsOnline ); + + bool CreateNewChar( uint32_t Account, const std::string &Name, uint32_t Gender, uint32_t Profession, uint32_t Faction, + uint32_t Head, uint32_t Torso, uint32_t Legs, uint8_t NZSNb, const char *NonZeroSubskills, uint32_t Slot ); + bool SQLLoad( int CharID ); + bool SQLSave(); + inline bool SQLSaveFull() { return SQLSave() && mInventory.SQLSave(); } + bool SQLDelete(); // not implemented yet + + inline void SetLocation( uint32_t Location ) { mLocation = Location; } + inline void SetDirtyFlag( bool Dirty = true ) { mDirtyFlag = Dirty; } + + // temp until char on-demand load/unload + inline void SetLocationLeased( bool nState = true ) { mLocationLeased = nState; } + inline bool GetLocationLeased() { return mLocationLeased; } + + PSeatType GetSeatInUse( uint32_t* nObjectId = NULL, uint8_t* nSeatId = NULL ); + void SetSeatInUse( PSeatType nSeatType, uint32_t nObjectId = 0, uint8_t nSeatId = 0 ); + + PVhcAccessRequestList* GetVhcAccessRequestList(); + + inline PContainer* GetContainerInExclusiveUse() { return mContainerInExclusiveUse; } + inline void SetContainerInExclusiveUse( PContainer* nContainer ) { mContainerInExclusiveUse = nContainer; } +}; + +struct PCharProfile +{ + uint32_t CharID; + uint16_t Type; + uint16_t Color0; + uint16_t Unknown1; + uint8_t Head; + uint8_t Torso; + uint8_t Legs; + uint32_t Location; + uint8_t NameLen; + uint8_t Unknown3; + uint8_t Unknown4; + uint8_t Unknown5; + uint8_t Unknown6; + uint8_t Unknown7; + uint8_t Unknown8; + uint8_t Unknown9; + uint8_t Unknown10; + uint8_t Unknown11; + uint8_t Unknown12; + std::string Name; + bool in_use; +}; + +class PChars +{ + private : + typedef std::map CharMap; + CharMap mChars; + uint32_t mLastID; + + std::time_t mAutoSavePeriod; + std::time_t mLastSave; + + public : + PChars(); + ~PChars(); + + bool LoadChar( uint32_t CharID ); + bool AddChar( PChar* nChar ); + PChar* RemoveChar( uint32_t CharID ); + + PChar* GetChar( uint32_t CharID ) const; + PChar* GetChar( const std::string &Name ) const; + bool CharExist( const std::string &Name ) const; + + void SQLSave(); + void Update(); + + int GetCharProfiles( const uint32_t AccountID, PCharProfile* CharSlotsArray, const uint8_t ArraySize ); // return effective entries nb +}; diff --git a/TinNS/Source/GameServer/Chat.cxx b/TinNS/Source/GameServer/Chat.cxx index 9be8592..dfdd1d9 100644 --- a/TinNS/Source/GameServer/Chat.cxx +++ b/TinNS/Source/GameServer/Chat.cxx @@ -1,1099 +1,1099 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -// TODO:- Add "hooks" to process chatevents everywhere in the source <-- kind of done. you can use the global PChat Instance. -// Check: -// Chat->send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, char* text, bool debugOut=false); -// Example: -// Chat->send(receiverClient, CHAT_DIRECT, Chars->GetChar(authorClient->GetCharID())->GetName().c_str(), text); - -PChat::PChat() -{ -} - -PChat::~PChat() -{ -} - -/* -DONE void sendBuddy(PClient* author, char* text, bool debugOut=false); -DONE void sendLocal(PClient* author, char* text, bool debugOut=false); -NEED CLANDATA void sendClan(PClient* author, char* text, bool debugOut=false); -NEED TEAMDATA void sendTeam(PClient* author, char* text, bool debugOut=false); -DONE void sendDirect(PClient* author, PClient* receiver, char* text, bool debugOut=false); -DONE void sendZone(PClient* author, char* text, bool debugOut=false); -DONE void sendFrak(PClient* author, char* text, bool debugOut=false); -DONE void sendTradeCS(PClient* author, char* text, bool debugOut=false); -DONE void sendTradeMB(PClient* author, char* text, bool debugOut=false); -DONE void sendTradeNC(PClient* author, char* text, bool debugOut=false); -DONE void sendTradeTH(PClient* author, char* text, bool debugOut=false); -DONE void sendTradeWL(PClient* author, char* text, bool debugOut=false); -DONE void sendOOC(PClient* author, char* text, bool debugOut=false); -DONE void sendHelp(PClient* author, char* text, bool debugOut=false); -DONE void sendClanSearch(PClient* author, char* text, bool debugOut=false); -DONE void sendServicesCS(PClient* author, char* text, bool debugOut=false); -DONE void sendServicesMB(PClient* author, char* text, bool debugOut=false); -DONE void sendServicesNC(PClient* author, char* text, bool debugOut=false); -DONE void sendServicesTH(PClient* author, char* text, bool debugOut=false); -DONE void sendServicesWL(PClient* author, char* text, bool debugOut=false); -DONE void sendTeam10(PClient* author, char* text, bool debugOut=false); -DONE void sendTeam30(PClient* author, char* text, bool debugOut=false); -DONE void sendTeam50(PClient* author, char* text, bool debugOut=false); -DONE void sendTeam70(PClient* author, char* text, bool debugOut=false); -DONE void sendAdmin(PClient* author, char* text, bool debugOut=false); -DONE void sendGM(PClient* author, char* text, bool debugOut=false); -*/ - - -void PChat::sendBuddy(PClient* author, const char* text, bool debugOut) -{ - PChar* authorChar = Chars->GetChar(author->GetCharID()); - // send the message to all Buddys in list - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second && authorChar->IsBuddy(it->second->GetCharID()) == true) - { - PClient* receiver = it->second; - //Console->Print("DEBUG: Buddychat - Sending msg to %s", Chars->GetChar(receiver->GetCharID())->GetName().c_str()); - send(receiver, CHAT_BUDDY, authorChar->GetName().c_str(), text, debugOut); - } - } -} - -void PChat::sendConnectedList(PClient* receiver, bool debugOut) -{ - const char* text = "Connected Players are:]"; - send(receiver, CHAT_DIRECT, "[System", text, debugOut); - - int counter = 1; - - // send the list of currently connected players to receiver - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - char counterText[5]; - snprintf(counterText, 5, "%d", counter); - - PChar* receiverChar = Chars->GetChar(it->second->GetCharID()); - send(receiver, CHAT_DIRECT, (receiverChar ? receiverChar->GetName().c_str() : "*"), counterText, debugOut); - - counter++; - } -} - - -void PChat::sendFrak(PClient* author, const char* text, bool debugOut) -{ - // send the message to all clients that have same FactionID - PChar* authorChar = Chars->GetChar(author->GetCharID()); - uint32_t FID = authorChar->GetFaction(); // get LocationID of author - - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - PClient* receiver = it->second; - PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); - if(receiverChar && (receiverChar->GetFaction() == FID)) - { - if(chanEnabled(receiver, C_FRAK) == true) - send(receiver, CHAT_FRAK, authorChar->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendZone(PClient* author, const char* text, bool debugOut) -{ - // send the message to all clients that have same ZoneID - PChar* authorChar = Chars->GetChar(author->GetCharID()); - uint32_t ZID = authorChar->GetLocation(); // get LocationID of author - - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - PClient* receiver = it->second; - PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); - if(receiverChar && (receiverChar->GetLocation() == ZID)) - { - if(chanEnabled(receiver, C_ZONE) == true) - send(receiver, CHAT_ZONE, authorChar->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendLocal(PClient* author, const char* text, bool debugOut) -{ - PChar* authorChar = Chars->GetChar(author->GetCharID()); - uint32_t ZID = authorChar->GetLocation(); // get LocationID of author - - // send the message to all clients that are in Area (Radius = X (needs to be defined somewhere!)) - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - PClient* receiver = it->second; - PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); - if(receiverChar && (receiverChar->GetLocation() == ZID)) - { - uint16_t distance = DistanceApprox((authorChar->Coords).mX, (authorChar->Coords).mY, (authorChar->Coords).mZ, (receiverChar->Coords).mX, (receiverChar->Coords).mY, (receiverChar->Coords).mZ); - if(distance < LOCALCHAT_MAXDISTANCE) - { - //sendLocalchat(receiver, author, text, debugOut); // Doesnt work! - send(receiver, CHAT_LOCAL, authorChar->GetName().c_str(), text, debugOut); - } - } - } - } -} - -void PChat::sendGM(PClient* author, const char* text, bool debugOut) -{ - if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher - { - // send the message to all GameMasters. - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(receiver->GetAccountLevel() >= PAL_GM) // Only send GM chat if RECEIVER is GM or higher - send(receiver, CHAT_GM, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } - } -} - -void PChat::sendGMAdmin(PClient* author, const char* text, bool debugOut) -{ - if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher - { - // send the message to ALL users online - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - send(receiver, CHAT_GMADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } - } -} - -void PChat::sendAdmin(PClient* author, const char* text, bool debugOut) -{ - if(author->GetAccountLevel() >= PAL_ADMIN) // Only send ADMIN> chat when user is an serveradmin - { - // send the message to ALL users online - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - send(receiver, CHAT_ADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } - } -} - -void PChat::sendBroadcast(const char* text, bool debugOut) -{ - // send the message to ALL users online - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - send(receiver, CHAT_ADMIN, "Server", text, debugOut); - } - } -} - -void PChat::sendOOCBroadcast(const char* text, bool debugOut) -{ - // send the message to ALL users online - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_OOC) == true) - send(receiver, CHAT_OOC, "Server", text, debugOut); - } - } -} - -void PChat::sendClan(PClient* author, const char* text, bool debugOut) -{ - /** - NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN - **/ - // send the message to all clients that have same ClanID - PChar* authorChar = Chars->GetChar(author->GetCharID()); - -// int ClanID = authorChar->getClanID(); // get clanID of author - - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) - { - PClient* receiver = it->second; - PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); - if(receiverChar /*&& (receiverChar->getClanID() == ClanID)*/) - { - send(receiver, CHAT_CLAN, authorChar->GetName().c_str(), text, debugOut); - } - } - } - -} - -void PChat::sendTeam(PClient* author, const char* text, bool debugOut) -{ - /** - NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN - **/ - // send the message to all clients that have same TeamID - - PChar* authorChar = Chars->GetChar(author->GetCharID()); - - //int TeamID = authorChar->getTeamID(); // get TeamID of author - - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) - { - PClient* receiver = it->second; - PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); - if(receiverChar /*&& (receiverChar->getTeamID() == TeamID)*/) - { - send(receiver, CHAT_TEAM, authorChar->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut) -{ - bool tmpTargetOnline = false; - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - PClient* receiver = it->second; - PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); - if(receiverChar && (receiver->GetCharID() == destination)) - { - tmpTargetOnline = true; - sendDirect(author, receiver, text, debugOut); - } - } - if(tmpTargetOnline == false) - { - ConnectionTCP *Socket = author->getTCPConn(); - uint8_t DirectTargetNotOnline[] = {0xFE, 0x07, 0x00, 0x83, 0x18, 0x01, 0x81, 0x54, 0x00, 0x00}; - - Socket->write(DirectTargetNotOnline, sizeof(DirectTargetNotOnline)); - Socket->flushSendBuffer(); - } - - if(debugOut == true) - { - if(tmpTargetOnline == false) - Console->Print("[DEBUG] Requested target CharID %d is not online", destination); - else - Console->Print("[DEBUG] CharID %d found and message transmitted!", destination); - } -} - -void PChat::sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut) -{ - PChar* authorChar = Chars->GetChar(author->GetCharID()); - - char *DChatPacket; - unsigned int packetsize = 0, c; - int LenText, LenNick, fpp, d, e, loopout; - - ConnectionTCP *Socket = receiver->getTCPConn(); - - uint8_t BasicDirectPacket[] = {0xFE, 0x20, 0x00, 0x83, 0x17, 0xB7, 0x5F, 0x00, 0x00, 0x0C, 0x04, 0x00}; - - LenText = LenNick = fpp = 0; - - do { - LenText++; - } while(text[LenText] != '\0'); - - do { - LenNick++; - } while(authorChar->GetName().c_str()[LenNick] != '\0'); - - loopout = 0; - - packetsize = sizeof(BasicDirectPacket) + LenText + LenNick; - - if(debugOut == true) { - Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick); - Console->Print("Whole size: %d", packetsize); - } - - DChatPacket = new char [packetsize]; - - // Copy basic packet into final packet - for(c=0;cGetName().c_str()[d]; - fpp++; - } - - // Copy Text into final packet - for(e=0;ePrint("Byte %d: %#x", debugout, DChatPacket[debugout]); - } - } - - // Sending direct chat packet and removing dynamic array - Socket->write(DChatPacket, packetsize); - Socket->flushSendBuffer(); - delete[] DChatPacket; -} - -void PChat::sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut) -{ - return; // IncreaseUDP could cause OOO here. Since this function is doing nothing, we disabled it - char *LocalChatPacket; - int overallsize = 0, LenText = 0; - uint8_t BasicLocal[] = { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1B }; - - // Get size of Text to send - do { - LenText++; - } while(text[LenText] != '\0'); - - // Calculate packetsize - overallsize = sizeof(BasicLocal) + LenText + 1; - - if(debugOut == true) - Console->Print("Whole size: %d", overallsize); - - LocalChatPacket = new char [overallsize]; - - // Copy basic packet into final packet - int fpp = 0; - for(unsigned int c = 0; c < sizeof(BasicLocal); c++) { - LocalChatPacket[fpp] = BasicLocal[c]; - fpp++; - } - - // Copy Text into final packet - for(int e = 0; e < LenText; e++) { - LocalChatPacket[fpp] = text[e]; - fpp++; - } - - // Terminate string - LocalChatPacket[fpp] = 0x00; - - // Add UdpID, SessionID, lenght and local charid - receiver->IncreaseUDP_ID(); - *(uint16_t*)&LocalChatPacket[1] = receiver->GetUDP_ID(); // UDP - *(uint16_t*)&LocalChatPacket[3] = receiver->GetSessionID(); // Session - *(uint8_t*)&LocalChatPacket[5] = overallsize - 6; // Packetlen - *(uint16_t*)&LocalChatPacket[7] = receiver->GetUDP_ID(); // 2nd UDP - *(uint16_t*)&LocalChatPacket[10] = author->GetLocalID(); // Local ID - - // Sending local chat packet and removing dynamic array - ConnectionUDP *Socket = receiver->getUDPConn(); - Socket->write(LocalChatPacket, overallsize); - Socket->flushSendBuffer(); - delete[] LocalChatPacket; -} - -void PChat::sendTradeCS(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TRADECS) == true) - send(receiver, CHAT_TRADECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTradeMB(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TRADEMB) == true) - send(receiver, CHAT_TRADEMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTradeNC(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TRADENC) == true) - send(receiver, CHAT_TRADENC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTradeTH(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TRADETH) == true) - send(receiver, CHAT_TRADETH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTradeWL(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TRADEWL) == true) - send(receiver, CHAT_TRADEWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendOOC(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_OOC) == true) - send(receiver, CHAT_OOC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendHelp(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_HELP) == true) - send(receiver, CHAT_HELP, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendClanSearch(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_CLANSEARCH) == true) - send(receiver, CHAT_CLANSEARCH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendServicesCS(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_SERVICECS) == true) - send(receiver, CHAT_SERVICECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendServicesMB(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_SERVICEMB) == true) - send(receiver, CHAT_SERVICESMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendServicesNC(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_SERVICENC) == true) - send(receiver, CHAT_SERVICESNC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendServicesTH(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_SERVICETH) == true) - send(receiver, CHAT_SERVICESTH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendServicesWL(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_SERVICEWL) == true) - send(receiver, CHAT_SERVICESWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTeam10(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TEAM10) == true) - send(receiver, CHAT_TEAM10, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTeam30(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TEAM30) == true) - send(receiver, CHAT_TEAM30, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTeam50(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TEAM50) == true) - send(receiver, CHAT_TEAM50, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -void PChat::sendTeam70(PClient* author, const char* text, bool debugOut) -{ - for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) - { - if(author != it->second) // if its not the client, that send the message to the server - { - if(it->second) // only send if the client is existing! - { - PClient* receiver = it->second; - if(chanEnabled(receiver, C_TEAM70) == true) - send(receiver, CHAT_TEAM70, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); - } - } - } -} - -bool PChat::chanEnabled(PClient* Client, uint32_t channel) -{ - // Check if player has target channel enabled or disabled - PChar* TargetChar = Chars->GetChar(Client->GetCharID()); - if(!TargetChar) - return false; - - uint32_t actChans = TargetChar->GetActiveChannels(); - uint32_t check = actChans & channel; - - if(check == channel) - return true; - else - return false; -} - -bool PChat::send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut) -{ - char *ChatPacket; - unsigned int packetsize = 0, c; - int LenText, LenNick, fpp, d, e, loopout; - uint8_t TargetChannel[2]; - -//Console->Print("1: %#x", Channel[0]); -//Console->Print("2: %#x", CHAT_BUDDY[0]); - - - if(cmpr(Channel, CHAT_BUDDY) == true) { - TargetChannel[0] = CHAT_BUDDY[0]; - TargetChannel[1] = CHAT_BUDDY[1]; - } else if(cmpr(Channel, CHAT_LOCAL) == true) { - TargetChannel[0] = CHAT_LOCAL[0]; - TargetChannel[1] = CHAT_LOCAL[1]; - } else if(cmpr(Channel, CHAT_CLAN) == true) { - TargetChannel[0] = CHAT_CLAN[0]; - TargetChannel[1] = CHAT_CLAN[1]; - } else if(cmpr(Channel, CHAT_TEAM) == true) { - TargetChannel[0] = CHAT_TEAM[0]; - TargetChannel[1] = CHAT_TEAM[1]; - } else if(cmpr(Channel, CHAT_DIRECT) == true) { - TargetChannel[0] = CHAT_DIRECT[0]; - TargetChannel[1] = CHAT_DIRECT[1]; - } else if(cmpr(Channel, CHAT_ZONE) == true) { - TargetChannel[0] = CHAT_ZONE[0]; - TargetChannel[1] = CHAT_ZONE[1]; - } else if(cmpr(Channel, CHAT_FRAK) == true) { - TargetChannel[0] = CHAT_FRAK[0]; - TargetChannel[1] = CHAT_FRAK[1]; - } else if(cmpr(Channel, CHAT_TRADECS) == true) { - TargetChannel[0] = CHAT_TRADECS[0]; - TargetChannel[1] = CHAT_TRADECS[1]; - } else if(cmpr(Channel, CHAT_TRADEMB) == true) { - TargetChannel[0] = CHAT_TRADEMB[0]; - TargetChannel[1] = CHAT_TRADEMB[1]; - } else if(cmpr(Channel, CHAT_TRADENC) == true) { - TargetChannel[0] = CHAT_TRADENC[0]; - TargetChannel[1] = CHAT_TRADENC[1]; - } else if(cmpr(Channel, CHAT_TRADETH) == true) { - TargetChannel[0] = CHAT_TRADETH[0]; - TargetChannel[1] = CHAT_TRADETH[1]; - } else if(cmpr(Channel, CHAT_TRADEWL) == true) { - TargetChannel[0] = CHAT_TRADEWL[0]; - TargetChannel[1] = CHAT_TRADEWL[1]; - } else if(cmpr(Channel, CHAT_OOC) == true) { - TargetChannel[0] = CHAT_OOC[0]; - TargetChannel[1] = CHAT_OOC[1]; - } else if(cmpr(Channel, CHAT_HELP) == true) { - TargetChannel[0] = CHAT_HELP[0]; - TargetChannel[1] = CHAT_HELP[1]; - } else if(cmpr(Channel, CHAT_CLANSEARCH) == true) { - TargetChannel[0] = CHAT_CLANSEARCH[0]; - TargetChannel[1] = CHAT_CLANSEARCH[1]; - } else if(cmpr(Channel, CHAT_SERVICECS) == true) { - TargetChannel[0] = CHAT_SERVICECS[0]; - TargetChannel[1] = CHAT_SERVICECS[1]; - } else if(cmpr(Channel, CHAT_SERVICESMB) == true) { - TargetChannel[0] = CHAT_SERVICESMB[0]; - TargetChannel[1] = CHAT_SERVICESMB[1]; - } else if(cmpr(Channel, CHAT_SERVICESNC) == true) { - TargetChannel[0] = CHAT_SERVICESNC[0]; - TargetChannel[1] = CHAT_SERVICESNC[1]; - } else if(cmpr(Channel, CHAT_SERVICESTH) == true) { - TargetChannel[0] = CHAT_SERVICESTH[0]; - TargetChannel[1] = CHAT_SERVICESTH[1]; - } else if(cmpr(Channel, CHAT_SERVICESWL) == true) { - TargetChannel[0] = CHAT_SERVICESWL[0]; - TargetChannel[1] = CHAT_SERVICESWL[1]; - } else if(cmpr(Channel, CHAT_TEAM10) == true) { - TargetChannel[0] = CHAT_TEAM10[0]; - TargetChannel[1] = CHAT_TEAM10[1]; - } else if(cmpr(Channel, CHAT_TEAM30) == true) { - TargetChannel[0] = CHAT_TEAM30[0]; - TargetChannel[1] = CHAT_TEAM30[1]; - } else if(cmpr(Channel, CHAT_TEAM50) == true) { - TargetChannel[0] = CHAT_TEAM50[0]; - TargetChannel[1] = CHAT_TEAM50[1]; - } else if(cmpr(Channel, CHAT_TEAM70) == true) { - TargetChannel[0] = CHAT_TEAM70[0]; - TargetChannel[1] = CHAT_TEAM70[1]; - } else if(cmpr(Channel, CHAT_ADMIN) == true) { - TargetChannel[0] = CHAT_ADMIN[0]; - TargetChannel[1] = CHAT_ADMIN[1]; - } else if(cmpr(Channel, CHAT_GMADMIN) == true) { - TargetChannel[0] = CHAT_GMADMIN[0]; - TargetChannel[1] = CHAT_GMADMIN[1]; - } else if(cmpr(Channel, CHAT_GM) == true) { - TargetChannel[0] = CHAT_GM[0]; - TargetChannel[1] = CHAT_GM[1]; - } else { - Console->Print("SendChat error: Channel %#x unknown", Channel); - return false; - } - - ConnectionTCP *Socket = receiver->getTCPConn(); - - uint8_t BasicChatPacket[] = {0xFE, 0x15, 0x00, 0x83, 0x17, 0x90, 0x03, 0x00, 0x00, 0x07, 0x05, 0x0F}; - - LenText = LenNick = fpp = 0; - - do { - LenText++; - } while(text[LenText] != '\0'); - - do { - LenNick++; - } while(AuthorNickName[LenNick] != '\0'); - - if(LenText == 0 || LenNick == 0) { - Console->Print("Error in SendChat, nickname or text is missing"); - return false; - } - - loopout = 0; - - packetsize = sizeof(BasicChatPacket) + LenText + LenNick; - - if(debugOut == true) { - Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick); - Console->Print("Whole size: %d", packetsize); - } - - ChatPacket = new char [packetsize]; - - // Copy basic packet into final packet - for(c=0;cPrint("Byte %d: %#x", debugout, ChatPacket[debugout]); - } - } - - // Sending direct chat packet and removing dynamic array - Socket->write(ChatPacket, packetsize); - Socket->flushSendBuffer(); - delete[] ChatPacket; - - return true; -} - - - -bool PChat::HandleGameChat(PClient *Client, const uint8_t *Packet) -{ - // if player is shunned, ignore all incomming chat and game commands. - // ServerAdmins are not affected by any shuns. (Should never happen anyways...) - if((Client->GetChar()->IsShunned() == true) && (Client->GetAccountLevel() < PAL_ADMIN)) return true; - - int i, j, k; - - uint8_t chattype = *(uint8_t*)&Packet[7]; -// ----------------------------------------------- - if(chattype == 0x1B) { - // Local chat - i = 8; - j = 0; - - char ChatText[255]; - - do { - ChatText[j] = Packet[i]; - i++; - j++; - } while (ChatText[j-1] != 0x00); - - ChatText[j] = '\0'; - if(ChatText[0] == '@' && sizeof(ChatText) > 2) { - GameCommands->HandleGameCommand(ChatText, Client); - } else { - // We know its working, so we dont need console output anymore - //Console->Print("Local Chat: %s", ChatText); - //Console->Print("Client CharName is: %s", Chars->GetChar(Client->GetCharID())->GetName().c_str()); - sendLocal(Client, ChatText, false); - } - -// ----------------------------------------------- - } else if (chattype == 0x3B) { - // Non-Local chat - i = 13; - j = 0; - k = 0; - - char ChatText[255]; - - do { - ChatText[j] = Packet[i]; - i++; - j++; - } while (ChatText[j-1] != 0x00); - - - ChatText[j] = '\0'; - if(ChatText[0] == '@' && sizeof(ChatText) > 2) { - GameCommands->HandleGameCommand(ChatText, Client); - } else { - // Console->Print("CHATLINE: %s HEX: %#X", ChatText, Packet[i-1]); - char Channel[4]; - - for(k = 0; k <= 3; k ++) { - Channel[k] = Packet[k+8]; - } - // Console->Print("Channel no %#x %#x %#x %#x", Channel[0], Channel[1], Channel[2], Channel[3]); - - // First, check if packet is a direct-chat-packet - if(*(uint8_t*)&Packet[8] == 0x04) { - //Console->Print("Direct Chat: %s", ChatText); - sendPlayerDirect(Client, ChatText, *(uint32_t*)&Packet[9], false); - //sendDirect(Client, ChatText, false); - // "DIRECT> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_BUDDY) { - //Console->Print("Buddy Chat: %s", ChatText); - sendBuddy(Client, ChatText, false); - // "BUDDY> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CLAN) { - //Console->Print("Clan Chat: %s", ChatText); - sendClan(Client, ChatText, false); - // "CLAN> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_TEAM) { - //Console->Print("Team Chat: %s", ChatText); - sendTeam(Client, ChatText, false); - // "TEAM> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_ZONE) { - //Console->Print("Custom - Zone Chat: %s", ChatText); - sendZone(Client, ChatText, false); - // "ZONE> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_FRAKTION) { - //Console->Print("Custom - Fraktion Chat: %s", ChatText); - sendFrak(Client, ChatText, false); - // "FRACTION> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_CANYON) { - //Console->Print("Custom - Trade_Canyon Chat: %s", ChatText); - sendTradeCS(Client, ChatText, false); - // "TRADE - CS> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_MB) { - //Console->Print("Custom - Trade_MB Chat: %s", ChatText); - sendTradeMB(Client, ChatText, false); - // "TRADE - MB> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_NC) { - //Console->Print("Custom - Trade_NC Chat: %s", ChatText); - sendTradeNC(Client, ChatText, false); - // "TRADE - NC> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_TH) { - //Console->Print("Custom - Trade_TH Chat: %s", ChatText); - sendTradeTH(Client, ChatText, false); - // "TRADE - TH> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_WASTE) { - //Console->Print("Custom - Trade_Waste Chat: %s", ChatText); - sendTradeWL(Client, ChatText, false); - // "TRADE - WL> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_OOC) { - //Console->Print("Custom - OOC Chat: %s", ChatText); - sendOOC(Client, ChatText, false); - // "OOC> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_PLAYERHELP) { - //Console->Print("Custom - PlayerToPlayerhelp Chat: %s", ChatText); - sendHelp(Client, ChatText, false); - // "HELP> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_CLANSEARCH) { - //Console->Print("Custom - Clansearch Chat: %s", ChatText); - sendClanSearch(Client, ChatText, false); - // "CLANSEARCH> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_CANYON) { - //Console->Print("Custom - Services_Canyon Chat: %s", ChatText); - sendServicesCS(Client, ChatText, false); - // "SKILL - CS> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_MB) { - //Console->Print("Custom - Services_MB Chat: %s", ChatText); - sendServicesMB(Client, ChatText, false); - // "SKILL - MB> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_NC) { - //Console->Print("Custom - Services_NC Chat: %s", ChatText); - sendServicesNC(Client, ChatText, false); - // "SKILL - NC> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_TH) { - //Console->Print("Custom - Services_TH Chat: %s", ChatText); - sendServicesTH(Client, ChatText, false); - // "SKILL - TH> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_WASTE) { - //Console->Print("Custom - Services_Waste Chat: %s", ChatText); - sendServicesWL(Client, ChatText, false); - // "SKILL - WL> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_10) { - //Console->Print("Custom - Team10 Chat: %s", ChatText); - sendTeam10(Client, ChatText, false); - // "TEAMSEARCH 10> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_30) { - //Console->Print("Custom - Team30 Chat: %s", ChatText); - sendTeam30(Client, ChatText, false); - // "EAMSEARCH 30> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_50) { - //Console->Print("Custom - Team50 Chat: %s", ChatText); - sendTeam50(Client, ChatText, false); - // "EAMSEARCH 50> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_70) { - //Console->Print("Custom - Team70 Chat: %s", ChatText); - sendTeam70(Client, ChatText, false); - // "EAMSEARCH 70> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_ADMIN) { - //Console->Print("Admin Chat: %s", ChatText); - sendAdmin(Client, ChatText, false); - // "ADMIN> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_GMADMIN) { - //Console->Print("Admin Chat: %s", ChatText); - sendGMAdmin(Client, ChatText, false); - // "ADMIN> %s: %s", PlayerName, ChatText - } - else if(*(uint32_t*)Channel == CHANNEL_GMCHAT) { - //Console->Print("GameMaster Chat: %s", ChatText); - sendGM(Client, ChatText, false); - // "GM> %s: %s", PlayerName, ChatText - } - else { - Console->Print("Unknown Chat-Channel: %#x", *(uint32_t*)Channel); - }; - } -} -return (true); -} - -bool PChat::cmpr(const uint8_t *Array1, const uint8_t *Array2) { - if(Array1[0] == Array2[0] && Array1[1] == Array2[1]) { - return true; - } else { - return false; - } -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +// TODO:- Add "hooks" to process chatevents everywhere in the source <-- kind of done. you can use the global PChat Instance. +// Check: +// Chat->send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, char* text, bool debugOut=false); +// Example: +// Chat->send(receiverClient, CHAT_DIRECT, Chars->GetChar(authorClient->GetCharID())->GetName().c_str(), text); + +PChat::PChat() +{ +} + +PChat::~PChat() +{ +} + +/* +DONE void sendBuddy(PClient* author, char* text, bool debugOut=false); +DONE void sendLocal(PClient* author, char* text, bool debugOut=false); +NEED CLANDATA void sendClan(PClient* author, char* text, bool debugOut=false); +NEED TEAMDATA void sendTeam(PClient* author, char* text, bool debugOut=false); +DONE void sendDirect(PClient* author, PClient* receiver, char* text, bool debugOut=false); +DONE void sendZone(PClient* author, char* text, bool debugOut=false); +DONE void sendFrak(PClient* author, char* text, bool debugOut=false); +DONE void sendTradeCS(PClient* author, char* text, bool debugOut=false); +DONE void sendTradeMB(PClient* author, char* text, bool debugOut=false); +DONE void sendTradeNC(PClient* author, char* text, bool debugOut=false); +DONE void sendTradeTH(PClient* author, char* text, bool debugOut=false); +DONE void sendTradeWL(PClient* author, char* text, bool debugOut=false); +DONE void sendOOC(PClient* author, char* text, bool debugOut=false); +DONE void sendHelp(PClient* author, char* text, bool debugOut=false); +DONE void sendClanSearch(PClient* author, char* text, bool debugOut=false); +DONE void sendServicesCS(PClient* author, char* text, bool debugOut=false); +DONE void sendServicesMB(PClient* author, char* text, bool debugOut=false); +DONE void sendServicesNC(PClient* author, char* text, bool debugOut=false); +DONE void sendServicesTH(PClient* author, char* text, bool debugOut=false); +DONE void sendServicesWL(PClient* author, char* text, bool debugOut=false); +DONE void sendTeam10(PClient* author, char* text, bool debugOut=false); +DONE void sendTeam30(PClient* author, char* text, bool debugOut=false); +DONE void sendTeam50(PClient* author, char* text, bool debugOut=false); +DONE void sendTeam70(PClient* author, char* text, bool debugOut=false); +DONE void sendAdmin(PClient* author, char* text, bool debugOut=false); +DONE void sendGM(PClient* author, char* text, bool debugOut=false); +*/ + + +void PChat::sendBuddy(PClient* author, const char* text, bool debugOut) +{ + PChar* authorChar = Chars->GetChar(author->GetCharID()); + // send the message to all Buddys in list + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second && authorChar->IsBuddy(it->second->GetCharID()) == true) + { + PClient* receiver = it->second; + //Console->Print("DEBUG: Buddychat - Sending msg to %s", Chars->GetChar(receiver->GetCharID())->GetName().c_str()); + send(receiver, CHAT_BUDDY, authorChar->GetName().c_str(), text, debugOut); + } + } +} + +void PChat::sendConnectedList(PClient* receiver, bool debugOut) +{ + const char* text = "Connected Players are:]"; + send(receiver, CHAT_DIRECT, "[System", text, debugOut); + + int counter = 1; + + // send the list of currently connected players to receiver + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + char counterText[5]; + snprintf(counterText, 5, "%d", counter); + + PChar* receiverChar = Chars->GetChar(it->second->GetCharID()); + send(receiver, CHAT_DIRECT, (receiverChar ? receiverChar->GetName().c_str() : "*"), counterText, debugOut); + + counter++; + } +} + + +void PChat::sendFrak(PClient* author, const char* text, bool debugOut) +{ + // send the message to all clients that have same FactionID + PChar* authorChar = Chars->GetChar(author->GetCharID()); + uint32_t FID = authorChar->GetFaction(); // get LocationID of author + + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + PClient* receiver = it->second; + PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); + if(receiverChar && (receiverChar->GetFaction() == FID)) + { + if(chanEnabled(receiver, C_FRAK) == true) + send(receiver, CHAT_FRAK, authorChar->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendZone(PClient* author, const char* text, bool debugOut) +{ + // send the message to all clients that have same ZoneID + PChar* authorChar = Chars->GetChar(author->GetCharID()); + uint32_t ZID = authorChar->GetLocation(); // get LocationID of author + + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + PClient* receiver = it->second; + PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); + if(receiverChar && (receiverChar->GetLocation() == ZID)) + { + if(chanEnabled(receiver, C_ZONE) == true) + send(receiver, CHAT_ZONE, authorChar->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendLocal(PClient* author, const char* text, bool debugOut) +{ + PChar* authorChar = Chars->GetChar(author->GetCharID()); + uint32_t ZID = authorChar->GetLocation(); // get LocationID of author + + // send the message to all clients that are in Area (Radius = X (needs to be defined somewhere!)) + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + PClient* receiver = it->second; + PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); + if(receiverChar && (receiverChar->GetLocation() == ZID)) + { + uint16_t distance = DistanceApprox((authorChar->Coords).mX, (authorChar->Coords).mY, (authorChar->Coords).mZ, (receiverChar->Coords).mX, (receiverChar->Coords).mY, (receiverChar->Coords).mZ); + if(distance < LOCALCHAT_MAXDISTANCE) + { + //sendLocalchat(receiver, author, text, debugOut); // Doesnt work! + send(receiver, CHAT_LOCAL, authorChar->GetName().c_str(), text, debugOut); + } + } + } + } +} + +void PChat::sendGM(PClient* author, const char* text, bool debugOut) +{ + if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher + { + // send the message to all GameMasters. + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(receiver->GetAccountLevel() >= PAL_GM) // Only send GM chat if RECEIVER is GM or higher + send(receiver, CHAT_GM, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } + } +} + +void PChat::sendGMAdmin(PClient* author, const char* text, bool debugOut) +{ + if(author->GetAccountLevel() >= PAL_GM) // Only send GM> chat when user is an Gamemaster or higher + { + // send the message to ALL users online + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + send(receiver, CHAT_GMADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } + } +} + +void PChat::sendAdmin(PClient* author, const char* text, bool debugOut) +{ + if(author->GetAccountLevel() >= PAL_ADMIN) // Only send ADMIN> chat when user is an serveradmin + { + // send the message to ALL users online + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + send(receiver, CHAT_ADMIN, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } + } +} + +void PChat::sendBroadcast(const char* text, bool debugOut) +{ + // send the message to ALL users online + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + send(receiver, CHAT_ADMIN, "Server", text, debugOut); + } + } +} + +void PChat::sendOOCBroadcast(const char* text, bool debugOut) +{ + // send the message to ALL users online + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_OOC) == true) + send(receiver, CHAT_OOC, "Server", text, debugOut); + } + } +} + +void PChat::sendClan(PClient* author, const char* text, bool debugOut) +{ + /** + NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN + **/ + // send the message to all clients that have same ClanID + PChar* authorChar = Chars->GetChar(author->GetCharID()); + +// int ClanID = authorChar->getClanID(); // get clanID of author + + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) + { + PClient* receiver = it->second; + PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); + if(receiverChar /*&& (receiverChar->getClanID() == ClanID)*/) + { + send(receiver, CHAT_CLAN, authorChar->GetName().c_str(), text, debugOut); + } + } + } + +} + +void PChat::sendTeam(PClient* author, const char* text, bool debugOut) +{ + /** + NOT ABLE TO IMPLEMENT THIS CHATTYPE YET, ITS SUPERGLOBAL TILL THEN + **/ + // send the message to all clients that have same TeamID + + PChar* authorChar = Chars->GetChar(author->GetCharID()); + + //int TeamID = authorChar->getTeamID(); // get TeamID of author + + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) + { + PClient* receiver = it->second; + PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); + if(receiverChar /*&& (receiverChar->getTeamID() == TeamID)*/) + { + send(receiver, CHAT_TEAM, authorChar->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut) +{ + bool tmpTargetOnline = false; + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + PClient* receiver = it->second; + PChar* receiverChar = Chars->GetChar(receiver->GetCharID()); + if(receiverChar && (receiver->GetCharID() == destination)) + { + tmpTargetOnline = true; + sendDirect(author, receiver, text, debugOut); + } + } + if(tmpTargetOnline == false) + { + ConnectionTCP *Socket = author->getTCPConn(); + uint8_t DirectTargetNotOnline[] = {0xFE, 0x07, 0x00, 0x83, 0x18, 0x01, 0x81, 0x54, 0x00, 0x00}; + + Socket->write(DirectTargetNotOnline, sizeof(DirectTargetNotOnline)); + Socket->flushSendBuffer(); + } + + if(debugOut == true) + { + if(tmpTargetOnline == false) + Console->Print("[DEBUG] Requested target CharID %d is not online", destination); + else + Console->Print("[DEBUG] CharID %d found and message transmitted!", destination); + } +} + +void PChat::sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut) +{ + PChar* authorChar = Chars->GetChar(author->GetCharID()); + + char *DChatPacket; + unsigned int packetsize = 0, c; + int LenText, LenNick, fpp, d, e, loopout; + + ConnectionTCP *Socket = receiver->getTCPConn(); + + uint8_t BasicDirectPacket[] = {0xFE, 0x20, 0x00, 0x83, 0x17, 0xB7, 0x5F, 0x00, 0x00, 0x0C, 0x04, 0x00}; + + LenText = LenNick = fpp = 0; + + do { + LenText++; + } while(text[LenText] != '\0'); + + do { + LenNick++; + } while(authorChar->GetName().c_str()[LenNick] != '\0'); + + loopout = 0; + + packetsize = sizeof(BasicDirectPacket) + LenText + LenNick; + + if(debugOut == true) { + Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick); + Console->Print("Whole size: %d", packetsize); + } + + DChatPacket = new char [packetsize]; + + // Copy basic packet into final packet + for(c=0;cGetName().c_str()[d]; + fpp++; + } + + // Copy Text into final packet + for(e=0;ePrint("Byte %d: %#x", debugout, DChatPacket[debugout]); + } + } + + // Sending direct chat packet and removing dynamic array + Socket->write(DChatPacket, packetsize); + Socket->flushSendBuffer(); + delete[] DChatPacket; +} + +void PChat::sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut) +{ + return; // IncreaseUDP could cause OOO here. Since this function is doing nothing, we disabled it + char *LocalChatPacket; + int overallsize = 0, LenText = 0; + uint8_t BasicLocal[] = { 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x1B }; + + // Get size of Text to send + do { + LenText++; + } while(text[LenText] != '\0'); + + // Calculate packetsize + overallsize = sizeof(BasicLocal) + LenText + 1; + + if(debugOut == true) + Console->Print("Whole size: %d", overallsize); + + LocalChatPacket = new char [overallsize]; + + // Copy basic packet into final packet + int fpp = 0; + for(unsigned int c = 0; c < sizeof(BasicLocal); c++) { + LocalChatPacket[fpp] = BasicLocal[c]; + fpp++; + } + + // Copy Text into final packet + for(int e = 0; e < LenText; e++) { + LocalChatPacket[fpp] = text[e]; + fpp++; + } + + // Terminate string + LocalChatPacket[fpp] = 0x00; + + // Add UdpID, SessionID, lenght and local charid + receiver->IncreaseUDP_ID(); + *(uint16_t*)&LocalChatPacket[1] = receiver->GetUDP_ID(); // UDP + *(uint16_t*)&LocalChatPacket[3] = receiver->GetSessionID(); // Session + *(uint8_t*)&LocalChatPacket[5] = overallsize - 6; // Packetlen + *(uint16_t*)&LocalChatPacket[7] = receiver->GetUDP_ID(); // 2nd UDP + *(uint16_t*)&LocalChatPacket[10] = author->GetLocalID(); // Local ID + + // Sending local chat packet and removing dynamic array + ConnectionUDP *Socket = receiver->getUDPConn(); + Socket->write(LocalChatPacket, overallsize); + Socket->flushSendBuffer(); + delete[] LocalChatPacket; +} + +void PChat::sendTradeCS(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TRADECS) == true) + send(receiver, CHAT_TRADECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTradeMB(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TRADEMB) == true) + send(receiver, CHAT_TRADEMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTradeNC(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TRADENC) == true) + send(receiver, CHAT_TRADENC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTradeTH(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TRADETH) == true) + send(receiver, CHAT_TRADETH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTradeWL(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TRADEWL) == true) + send(receiver, CHAT_TRADEWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendOOC(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_OOC) == true) + send(receiver, CHAT_OOC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendHelp(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_HELP) == true) + send(receiver, CHAT_HELP, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendClanSearch(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_CLANSEARCH) == true) + send(receiver, CHAT_CLANSEARCH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendServicesCS(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_SERVICECS) == true) + send(receiver, CHAT_SERVICECS, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendServicesMB(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_SERVICEMB) == true) + send(receiver, CHAT_SERVICESMB, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendServicesNC(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_SERVICENC) == true) + send(receiver, CHAT_SERVICESNC, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendServicesTH(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_SERVICETH) == true) + send(receiver, CHAT_SERVICESTH, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendServicesWL(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_SERVICEWL) == true) + send(receiver, CHAT_SERVICESWL, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTeam10(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TEAM10) == true) + send(receiver, CHAT_TEAM10, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTeam30(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TEAM30) == true) + send(receiver, CHAT_TEAM30, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTeam50(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TEAM50) == true) + send(receiver, CHAT_TEAM50, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +void PChat::sendTeam70(PClient* author, const char* text, bool debugOut) +{ + for(PClientMap::iterator it=ClientManager->getClientListBegin(); it!=ClientManager->getClientListEnd(); it++) + { + if(author != it->second) // if its not the client, that send the message to the server + { + if(it->second) // only send if the client is existing! + { + PClient* receiver = it->second; + if(chanEnabled(receiver, C_TEAM70) == true) + send(receiver, CHAT_TEAM70, Chars->GetChar(author->GetCharID())->GetName().c_str(), text, debugOut); + } + } + } +} + +bool PChat::chanEnabled(PClient* Client, uint32_t channel) +{ + // Check if player has target channel enabled or disabled + PChar* TargetChar = Chars->GetChar(Client->GetCharID()); + if(!TargetChar) + return false; + + uint32_t actChans = TargetChar->GetActiveChannels(); + uint32_t check = actChans & channel; + + if(check == channel) + return true; + else + return false; +} + +bool PChat::send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut) +{ + char *ChatPacket; + unsigned int packetsize = 0, c; + int LenText, LenNick, fpp, d, e, loopout; + uint8_t TargetChannel[2]; + +//Console->Print("1: %#x", Channel[0]); +//Console->Print("2: %#x", CHAT_BUDDY[0]); + + + if(cmpr(Channel, CHAT_BUDDY) == true) { + TargetChannel[0] = CHAT_BUDDY[0]; + TargetChannel[1] = CHAT_BUDDY[1]; + } else if(cmpr(Channel, CHAT_LOCAL) == true) { + TargetChannel[0] = CHAT_LOCAL[0]; + TargetChannel[1] = CHAT_LOCAL[1]; + } else if(cmpr(Channel, CHAT_CLAN) == true) { + TargetChannel[0] = CHAT_CLAN[0]; + TargetChannel[1] = CHAT_CLAN[1]; + } else if(cmpr(Channel, CHAT_TEAM) == true) { + TargetChannel[0] = CHAT_TEAM[0]; + TargetChannel[1] = CHAT_TEAM[1]; + } else if(cmpr(Channel, CHAT_DIRECT) == true) { + TargetChannel[0] = CHAT_DIRECT[0]; + TargetChannel[1] = CHAT_DIRECT[1]; + } else if(cmpr(Channel, CHAT_ZONE) == true) { + TargetChannel[0] = CHAT_ZONE[0]; + TargetChannel[1] = CHAT_ZONE[1]; + } else if(cmpr(Channel, CHAT_FRAK) == true) { + TargetChannel[0] = CHAT_FRAK[0]; + TargetChannel[1] = CHAT_FRAK[1]; + } else if(cmpr(Channel, CHAT_TRADECS) == true) { + TargetChannel[0] = CHAT_TRADECS[0]; + TargetChannel[1] = CHAT_TRADECS[1]; + } else if(cmpr(Channel, CHAT_TRADEMB) == true) { + TargetChannel[0] = CHAT_TRADEMB[0]; + TargetChannel[1] = CHAT_TRADEMB[1]; + } else if(cmpr(Channel, CHAT_TRADENC) == true) { + TargetChannel[0] = CHAT_TRADENC[0]; + TargetChannel[1] = CHAT_TRADENC[1]; + } else if(cmpr(Channel, CHAT_TRADETH) == true) { + TargetChannel[0] = CHAT_TRADETH[0]; + TargetChannel[1] = CHAT_TRADETH[1]; + } else if(cmpr(Channel, CHAT_TRADEWL) == true) { + TargetChannel[0] = CHAT_TRADEWL[0]; + TargetChannel[1] = CHAT_TRADEWL[1]; + } else if(cmpr(Channel, CHAT_OOC) == true) { + TargetChannel[0] = CHAT_OOC[0]; + TargetChannel[1] = CHAT_OOC[1]; + } else if(cmpr(Channel, CHAT_HELP) == true) { + TargetChannel[0] = CHAT_HELP[0]; + TargetChannel[1] = CHAT_HELP[1]; + } else if(cmpr(Channel, CHAT_CLANSEARCH) == true) { + TargetChannel[0] = CHAT_CLANSEARCH[0]; + TargetChannel[1] = CHAT_CLANSEARCH[1]; + } else if(cmpr(Channel, CHAT_SERVICECS) == true) { + TargetChannel[0] = CHAT_SERVICECS[0]; + TargetChannel[1] = CHAT_SERVICECS[1]; + } else if(cmpr(Channel, CHAT_SERVICESMB) == true) { + TargetChannel[0] = CHAT_SERVICESMB[0]; + TargetChannel[1] = CHAT_SERVICESMB[1]; + } else if(cmpr(Channel, CHAT_SERVICESNC) == true) { + TargetChannel[0] = CHAT_SERVICESNC[0]; + TargetChannel[1] = CHAT_SERVICESNC[1]; + } else if(cmpr(Channel, CHAT_SERVICESTH) == true) { + TargetChannel[0] = CHAT_SERVICESTH[0]; + TargetChannel[1] = CHAT_SERVICESTH[1]; + } else if(cmpr(Channel, CHAT_SERVICESWL) == true) { + TargetChannel[0] = CHAT_SERVICESWL[0]; + TargetChannel[1] = CHAT_SERVICESWL[1]; + } else if(cmpr(Channel, CHAT_TEAM10) == true) { + TargetChannel[0] = CHAT_TEAM10[0]; + TargetChannel[1] = CHAT_TEAM10[1]; + } else if(cmpr(Channel, CHAT_TEAM30) == true) { + TargetChannel[0] = CHAT_TEAM30[0]; + TargetChannel[1] = CHAT_TEAM30[1]; + } else if(cmpr(Channel, CHAT_TEAM50) == true) { + TargetChannel[0] = CHAT_TEAM50[0]; + TargetChannel[1] = CHAT_TEAM50[1]; + } else if(cmpr(Channel, CHAT_TEAM70) == true) { + TargetChannel[0] = CHAT_TEAM70[0]; + TargetChannel[1] = CHAT_TEAM70[1]; + } else if(cmpr(Channel, CHAT_ADMIN) == true) { + TargetChannel[0] = CHAT_ADMIN[0]; + TargetChannel[1] = CHAT_ADMIN[1]; + } else if(cmpr(Channel, CHAT_GMADMIN) == true) { + TargetChannel[0] = CHAT_GMADMIN[0]; + TargetChannel[1] = CHAT_GMADMIN[1]; + } else if(cmpr(Channel, CHAT_GM) == true) { + TargetChannel[0] = CHAT_GM[0]; + TargetChannel[1] = CHAT_GM[1]; + } else { + Console->Print("SendChat error: Channel %#x unknown", Channel); + return false; + } + + ConnectionTCP *Socket = receiver->getTCPConn(); + + uint8_t BasicChatPacket[] = {0xFE, 0x15, 0x00, 0x83, 0x17, 0x90, 0x03, 0x00, 0x00, 0x07, 0x05, 0x0F}; + + LenText = LenNick = fpp = 0; + + do { + LenText++; + } while(text[LenText] != '\0'); + + do { + LenNick++; + } while(AuthorNickName[LenNick] != '\0'); + + if(LenText == 0 || LenNick == 0) { + Console->Print("Error in SendChat, nickname or text is missing"); + return false; + } + + loopout = 0; + + packetsize = sizeof(BasicChatPacket) + LenText + LenNick; + + if(debugOut == true) { + Console->Print("Sizeof(TextToSend): %d || Sizeof(Nick): %d", LenText, LenNick); + Console->Print("Whole size: %d", packetsize); + } + + ChatPacket = new char [packetsize]; + + // Copy basic packet into final packet + for(c=0;cPrint("Byte %d: %#x", debugout, ChatPacket[debugout]); + } + } + + // Sending direct chat packet and removing dynamic array + Socket->write(ChatPacket, packetsize); + Socket->flushSendBuffer(); + delete[] ChatPacket; + + return true; +} + + + +bool PChat::HandleGameChat(PClient *Client, const uint8_t *Packet) +{ + // if player is shunned, ignore all incomming chat and game commands. + // ServerAdmins are not affected by any shuns. (Should never happen anyways...) + if((Client->GetChar()->IsShunned() == true) && (Client->GetAccountLevel() < PAL_ADMIN)) return true; + + int i, j, k; + + uint8_t chattype = *(uint8_t*)&Packet[7]; +// ----------------------------------------------- + if(chattype == 0x1B) { + // Local chat + i = 8; + j = 0; + + char ChatText[255]; + + do { + ChatText[j] = Packet[i]; + i++; + j++; + } while (ChatText[j-1] != 0x00); + + ChatText[j] = '\0'; + if(ChatText[0] == '@' && sizeof(ChatText) > 2) { + GameCommands->HandleGameCommand(ChatText, Client); + } else { + // We know its working, so we dont need console output anymore + //Console->Print("Local Chat: %s", ChatText); + //Console->Print("Client CharName is: %s", Chars->GetChar(Client->GetCharID())->GetName().c_str()); + sendLocal(Client, ChatText, false); + } + +// ----------------------------------------------- + } else if (chattype == 0x3B) { + // Non-Local chat + i = 13; + j = 0; + k = 0; + + char ChatText[255]; + + do { + ChatText[j] = Packet[i]; + i++; + j++; + } while (ChatText[j-1] != 0x00); + + + ChatText[j] = '\0'; + if(ChatText[0] == '@' && sizeof(ChatText) > 2) { + GameCommands->HandleGameCommand(ChatText, Client); + } else { + // Console->Print("CHATLINE: %s HEX: %#X", ChatText, Packet[i-1]); + char Channel[4]; + + for(k = 0; k <= 3; k ++) { + Channel[k] = Packet[k+8]; + } + // Console->Print("Channel no %#x %#x %#x %#x", Channel[0], Channel[1], Channel[2], Channel[3]); + + // First, check if packet is a direct-chat-packet + if(*(uint8_t*)&Packet[8] == 0x04) { + //Console->Print("Direct Chat: %s", ChatText); + sendPlayerDirect(Client, ChatText, *(uint32_t*)&Packet[9], false); + //sendDirect(Client, ChatText, false); + // "DIRECT> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_BUDDY) { + //Console->Print("Buddy Chat: %s", ChatText); + sendBuddy(Client, ChatText, false); + // "BUDDY> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CLAN) { + //Console->Print("Clan Chat: %s", ChatText); + sendClan(Client, ChatText, false); + // "CLAN> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_TEAM) { + //Console->Print("Team Chat: %s", ChatText); + sendTeam(Client, ChatText, false); + // "TEAM> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_ZONE) { + //Console->Print("Custom - Zone Chat: %s", ChatText); + sendZone(Client, ChatText, false); + // "ZONE> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_FRAKTION) { + //Console->Print("Custom - Fraktion Chat: %s", ChatText); + sendFrak(Client, ChatText, false); + // "FRACTION> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_CANYON) { + //Console->Print("Custom - Trade_Canyon Chat: %s", ChatText); + sendTradeCS(Client, ChatText, false); + // "TRADE - CS> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_MB) { + //Console->Print("Custom - Trade_MB Chat: %s", ChatText); + sendTradeMB(Client, ChatText, false); + // "TRADE - MB> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_NC) { + //Console->Print("Custom - Trade_NC Chat: %s", ChatText); + sendTradeNC(Client, ChatText, false); + // "TRADE - NC> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_TH) { + //Console->Print("Custom - Trade_TH Chat: %s", ChatText); + sendTradeTH(Client, ChatText, false); + // "TRADE - TH> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TRADE_WASTE) { + //Console->Print("Custom - Trade_Waste Chat: %s", ChatText); + sendTradeWL(Client, ChatText, false); + // "TRADE - WL> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_OOC) { + //Console->Print("Custom - OOC Chat: %s", ChatText); + sendOOC(Client, ChatText, false); + // "OOC> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_PLAYERHELP) { + //Console->Print("Custom - PlayerToPlayerhelp Chat: %s", ChatText); + sendHelp(Client, ChatText, false); + // "HELP> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_CLANSEARCH) { + //Console->Print("Custom - Clansearch Chat: %s", ChatText); + sendClanSearch(Client, ChatText, false); + // "CLANSEARCH> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_CANYON) { + //Console->Print("Custom - Services_Canyon Chat: %s", ChatText); + sendServicesCS(Client, ChatText, false); + // "SKILL - CS> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_MB) { + //Console->Print("Custom - Services_MB Chat: %s", ChatText); + sendServicesMB(Client, ChatText, false); + // "SKILL - MB> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_NC) { + //Console->Print("Custom - Services_NC Chat: %s", ChatText); + sendServicesNC(Client, ChatText, false); + // "SKILL - NC> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_TH) { + //Console->Print("Custom - Services_TH Chat: %s", ChatText); + sendServicesTH(Client, ChatText, false); + // "SKILL - TH> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_SERVICES_WASTE) { + //Console->Print("Custom - Services_Waste Chat: %s", ChatText); + sendServicesWL(Client, ChatText, false); + // "SKILL - WL> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_10) { + //Console->Print("Custom - Team10 Chat: %s", ChatText); + sendTeam10(Client, ChatText, false); + // "TEAMSEARCH 10> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_30) { + //Console->Print("Custom - Team30 Chat: %s", ChatText); + sendTeam30(Client, ChatText, false); + // "EAMSEARCH 30> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_50) { + //Console->Print("Custom - Team50 Chat: %s", ChatText); + sendTeam50(Client, ChatText, false); + // "EAMSEARCH 50> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_CUS_TEAM_70) { + //Console->Print("Custom - Team70 Chat: %s", ChatText); + sendTeam70(Client, ChatText, false); + // "EAMSEARCH 70> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_ADMIN) { + //Console->Print("Admin Chat: %s", ChatText); + sendAdmin(Client, ChatText, false); + // "ADMIN> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_GMADMIN) { + //Console->Print("Admin Chat: %s", ChatText); + sendGMAdmin(Client, ChatText, false); + // "ADMIN> %s: %s", PlayerName, ChatText + } + else if(*(uint32_t*)Channel == CHANNEL_GMCHAT) { + //Console->Print("GameMaster Chat: %s", ChatText); + sendGM(Client, ChatText, false); + // "GM> %s: %s", PlayerName, ChatText + } + else { + Console->Print("Unknown Chat-Channel: %#x", *(uint32_t*)Channel); + }; + } +} +return (true); +} + +bool PChat::cmpr(const uint8_t *Array1, const uint8_t *Array2) { + if(Array1[0] == Array2[0] && Array1[1] == Array2[1]) { + return true; + } else { + return false; + } +} diff --git a/TinNS/Source/GameServer/Chat.hxx b/TinNS/Source/GameServer/Chat.hxx index 7d20a6e..c499f98 100644 --- a/TinNS/Source/GameServer/Chat.hxx +++ b/TinNS/Source/GameServer/Chat.hxx @@ -1,152 +1,152 @@ -#pragma once - -#include - -#define LOCALCHAT_MAXDISTANCE 1433 - -class PClient; - -class PChat { -public: - PChat(); - ~PChat(); - - // INCOMING CHAT - bool HandleGameChat(PClient *Client, const uint8_t *Packet); - bool cmpr(const uint8_t *Array1, const uint8_t *Array2); - - // this function is called by the other more specific functions and simply sends the data to the receiver-client - bool send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut=false); - - // this is for debugging and sends the current connected playerlist to the receiver-client - void sendConnectedList(PClient* receiver, bool debugOut=false); - - // specific channel functions: - void sendBuddy(PClient* author, const char* text, bool debugOut=false); - void sendLocal(PClient* author, const char* text, bool debugOut=false); - void sendClan(PClient* author, const char* text, bool debugOut=false); - void sendTeam(PClient* author, const char* text, bool debugOut=false); - void sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut=false); - void sendZone(PClient* author, const char* text, bool debugOut=false); - void sendFrak(PClient* author, const char* text, bool debugOut=false); - void sendTradeCS(PClient* author, const char* text, bool debugOut=false); - void sendTradeMB(PClient* author, const char* text, bool debugOut=false); - void sendTradeNC(PClient* author, const char* text, bool debugOut=false); - void sendTradeTH(PClient* author, const char* text, bool debugOut=false); - void sendTradeWL(PClient* author, const char* text, bool debugOut=false); - void sendOOC(PClient* author, const char* text, bool debugOut=false); - void sendHelp(PClient* author, const char* text, bool debugOut=false); - void sendClanSearch(PClient* author, const char* text, bool debugOut=false); - void sendServicesCS(PClient* author, const char* text, bool debugOut=false); - void sendServicesMB(PClient* author, const char* text, bool debugOut=false); - void sendServicesNC(PClient* author, const char* text, bool debugOut=false); - void sendServicesTH(PClient* author, const char* text, bool debugOut=false); - void sendServicesWL(PClient* author, const char* text, bool debugOut=false); - void sendTeam10(PClient* author, const char* text, bool debugOut=false); - void sendTeam30(PClient* author, const char* text, bool debugOut=false); - void sendTeam50(PClient* author, const char* text, bool debugOut=false); - void sendTeam70(PClient* author, const char* text, bool debugOut=false); - void sendAdmin(PClient* author, const char* text, bool debugOut=false); - void sendGM(PClient* author, const char* text, bool debugOut=false); - void sendGMAdmin(PClient* author, const char* text, bool debugOut=false); - - void sendBroadcast(const char* text, bool debugOut=false); - void sendOOCBroadcast(const char* text, bool debugOut=false); - void sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut=false); - void sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut=false); - bool chanEnabled(PClient* Client, uint32_t channel); -}; - -/** A WARNING: DO >N O T< (!!!) CHANGE >ANY< OF THE FOLLOWING VARIABLES UNLESS YOU KNOW EXACT WHAT YOU'RE DOING! **/ -/** You can easily mess up the entire chat subsystem. If you're unsure, ask Namikon first! **/ -/* -#################### - CHANNEL-CODES: - (INCOMING) -#################### -*/ -static const uint32_t CHANNEL_BUDDY = 0x00000000; // Buddy -static const uint32_t CHANNEL_CLAN = 0x00000002; // Clan -static const uint32_t CHANNEL_TEAM = 0x00000003; // Team -static const uint32_t CHANNEL_DIRECT = 0xFFFFFFFF; // Direct UNKNOWN YET -static const uint32_t CHANNEL_CUS_ZONE = 0x00000105; // Custom -> Zone -static const uint32_t CHANNEL_CUS_FRAKTION = 0x00000205; // Custom -> Fraktion -static const uint32_t CHANNEL_CUS_TRADE_CANYON = 0x00002005; // Custom -> Trade Canyon -static const uint32_t CHANNEL_CUS_TRADE_MB = 0x00000805; // Custom -> Trade MB -static const uint32_t CHANNEL_CUS_TRADE_NC = 0x00000405; // Custom -> Trade NC -static const uint32_t CHANNEL_CUS_TRADE_TH = 0x00001005; // Custom -> Trade TH -static const uint32_t CHANNEL_CUS_TRADE_WASTE = 0x00004005; // Custom -> Trade Wastelands -static const uint32_t CHANNEL_CUS_OOC = 0x04000005; // Custom -> OOC -static const uint32_t CHANNEL_CUS_PLAYERHELP = 0x02000005; // Custom -> Player 2 Player help -static const uint32_t CHANNEL_CUS_CLANSEARCH = 0x01000005; // Custom -> Searching Clan -static const uint32_t CHANNEL_CUS_SERVICES_CANYON = 0x00040005; // Custom -> Runner Services Canyon -static const uint32_t CHANNEL_CUS_SERVICES_MB = 0x00010005; // Custom -> Runner Services MB -static const uint32_t CHANNEL_CUS_SERVICES_NC = 0x00008005; // Custom -> Runner Services NC -static const uint32_t CHANNEL_CUS_SERVICES_TH = 0x00020005; // Custom -> Runner Services TH -static const uint32_t CHANNEL_CUS_SERVICES_WASTE = 0x00080005; // Custom -> Runner Services Wastelands -static const uint32_t CHANNEL_CUS_TEAM_10 = 0x00100005; // Custom -> Searching Team ~10 -static const uint32_t CHANNEL_CUS_TEAM_30 = 0x00200005; // Custom -> Searching Team ~30 -static const uint32_t CHANNEL_CUS_TEAM_50 = 0x00400005; // Custom -> Searching Team ~50 -static const uint32_t CHANNEL_CUS_TEAM_70 = 0x00800005; // Custom -> Searching Team ~70 -static const uint32_t CHANNEL_ADMIN = 0x000000FF; // Admin chat -static const uint32_t CHANNEL_GMADMIN = 0x000000FE; // Admin chat -static const uint32_t CHANNEL_GMCHAT = 0x000000FD; // GameMaster chat -/* -#################### - CHANNEL-CODES: - (OUTGOING) -#################### -*/ -static const uint8_t CHAT_BUDDY[] = {0x00, 0x10}; -static const uint8_t CHAT_LOCAL[] = {0x01, 0x10}; -static const uint8_t CHAT_CLAN[] = {0x02, 0x10}; -static const uint8_t CHAT_TEAM[] = {0x03, 0x10}; -static const uint8_t CHAT_DIRECT[] = {0x04, 0x10}; -static const uint8_t CHAT_ZONE[] = {0x05, 0x00}; -static const uint8_t CHAT_FRAK[] = {0x05, 0x01}; -static const uint8_t CHAT_TRADECS[] = {0x05, 0x05}; -static const uint8_t CHAT_TRADEMB[] = {0x05, 0x03}; -static const uint8_t CHAT_TRADENC[] = {0x05, 0x02}; -static const uint8_t CHAT_TRADETH[] = {0x05, 0x04}; -static const uint8_t CHAT_TRADEWL[] = {0x05, 0x06}; -static const uint8_t CHAT_OOC[] = {0x05, 0x12}; -static const uint8_t CHAT_HELP[] = {0x05, 0x11}; -static const uint8_t CHAT_CLANSEARCH[] = {0x05, 0x10}; -static const uint8_t CHAT_SERVICECS[] = {0x05, 0x0A}; -static const uint8_t CHAT_SERVICESMB[] = {0x05, 0x08}; -static const uint8_t CHAT_SERVICESNC[] = {0x05, 0x07}; -static const uint8_t CHAT_SERVICESTH[] = {0x05, 0x09}; -static const uint8_t CHAT_SERVICESWL[] = {0x05, 0x0B}; -static const uint8_t CHAT_TEAM10[] = {0x05, 0x0C}; -static const uint8_t CHAT_TEAM30[] = {0x05, 0x0D}; -static const uint8_t CHAT_TEAM50[] = {0x05, 0x0E}; -static const uint8_t CHAT_TEAM70[] = {0x05, 0x0F}; -static const uint8_t CHAT_ADMIN[] = {0xFF, 0x10}; -static const uint8_t CHAT_GMADMIN[] = {0xFE, 0x10}; -static const uint8_t CHAT_GM[] = {0xFD, 0x10}; - -/* -#################### - CHANNEL-CODES: -(EN/DISABLE-ABLE CHANNELS) -#################### -*/ -static const uint32_t C_ZONE = 1; -static const uint32_t C_FRAK = 2; -static const uint32_t C_TRADENC = 4; -static const uint32_t C_TRADEMB = 8; -static const uint32_t C_TRADETH = 16; -static const uint32_t C_TRADECS = 32; -static const uint32_t C_TRADEWL = 64; -static const uint32_t C_SERVICENC = 128; -static const uint32_t C_SERVICEMB = 256; -static const uint32_t C_SERVICETH = 512; -static const uint32_t C_SERVICECS = 1024; -static const uint32_t C_SERVICEWL = 2048; -static const uint32_t C_TEAM10 = 4096; -static const uint32_t C_TEAM30 = 8192; -static const uint32_t C_TEAM50 = 16384; -static const uint32_t C_TEAM70 = 32768; -static const uint32_t C_CLANSEARCH = 65536; -static const uint32_t C_HELP = 131072; -static const uint32_t C_OOC = 262144; +#pragma once + +#include + +#define LOCALCHAT_MAXDISTANCE 1433 + +class PClient; + +class PChat { +public: + PChat(); + ~PChat(); + + // INCOMING CHAT + bool HandleGameChat(PClient *Client, const uint8_t *Packet); + bool cmpr(const uint8_t *Array1, const uint8_t *Array2); + + // this function is called by the other more specific functions and simply sends the data to the receiver-client + bool send(PClient* receiver, const uint8_t* Channel, const char* AuthorNickName, const char* text, bool debugOut=false); + + // this is for debugging and sends the current connected playerlist to the receiver-client + void sendConnectedList(PClient* receiver, bool debugOut=false); + + // specific channel functions: + void sendBuddy(PClient* author, const char* text, bool debugOut=false); + void sendLocal(PClient* author, const char* text, bool debugOut=false); + void sendClan(PClient* author, const char* text, bool debugOut=false); + void sendTeam(PClient* author, const char* text, bool debugOut=false); + void sendDirect(PClient* author, PClient* receiver, const char* text, bool debugOut=false); + void sendZone(PClient* author, const char* text, bool debugOut=false); + void sendFrak(PClient* author, const char* text, bool debugOut=false); + void sendTradeCS(PClient* author, const char* text, bool debugOut=false); + void sendTradeMB(PClient* author, const char* text, bool debugOut=false); + void sendTradeNC(PClient* author, const char* text, bool debugOut=false); + void sendTradeTH(PClient* author, const char* text, bool debugOut=false); + void sendTradeWL(PClient* author, const char* text, bool debugOut=false); + void sendOOC(PClient* author, const char* text, bool debugOut=false); + void sendHelp(PClient* author, const char* text, bool debugOut=false); + void sendClanSearch(PClient* author, const char* text, bool debugOut=false); + void sendServicesCS(PClient* author, const char* text, bool debugOut=false); + void sendServicesMB(PClient* author, const char* text, bool debugOut=false); + void sendServicesNC(PClient* author, const char* text, bool debugOut=false); + void sendServicesTH(PClient* author, const char* text, bool debugOut=false); + void sendServicesWL(PClient* author, const char* text, bool debugOut=false); + void sendTeam10(PClient* author, const char* text, bool debugOut=false); + void sendTeam30(PClient* author, const char* text, bool debugOut=false); + void sendTeam50(PClient* author, const char* text, bool debugOut=false); + void sendTeam70(PClient* author, const char* text, bool debugOut=false); + void sendAdmin(PClient* author, const char* text, bool debugOut=false); + void sendGM(PClient* author, const char* text, bool debugOut=false); + void sendGMAdmin(PClient* author, const char* text, bool debugOut=false); + + void sendBroadcast(const char* text, bool debugOut=false); + void sendOOCBroadcast(const char* text, bool debugOut=false); + void sendPlayerDirect(PClient* author, const char* text, uint32_t destination, bool debugOut=false); + void sendLocalchat(PClient* receiver, PClient* author, const char* text, bool debugOut=false); + bool chanEnabled(PClient* Client, uint32_t channel); +}; + +/** A WARNING: DO >N O T< (!!!) CHANGE >ANY< OF THE FOLLOWING VARIABLES UNLESS YOU KNOW EXACT WHAT YOU'RE DOING! **/ +/** You can easily mess up the entire chat subsystem. If you're unsure, ask Namikon first! **/ +/* +#################### + CHANNEL-CODES: + (INCOMING) +#################### +*/ +static const uint32_t CHANNEL_BUDDY = 0x00000000; // Buddy +static const uint32_t CHANNEL_CLAN = 0x00000002; // Clan +static const uint32_t CHANNEL_TEAM = 0x00000003; // Team +static const uint32_t CHANNEL_DIRECT = 0xFFFFFFFF; // Direct UNKNOWN YET +static const uint32_t CHANNEL_CUS_ZONE = 0x00000105; // Custom -> Zone +static const uint32_t CHANNEL_CUS_FRAKTION = 0x00000205; // Custom -> Fraktion +static const uint32_t CHANNEL_CUS_TRADE_CANYON = 0x00002005; // Custom -> Trade Canyon +static const uint32_t CHANNEL_CUS_TRADE_MB = 0x00000805; // Custom -> Trade MB +static const uint32_t CHANNEL_CUS_TRADE_NC = 0x00000405; // Custom -> Trade NC +static const uint32_t CHANNEL_CUS_TRADE_TH = 0x00001005; // Custom -> Trade TH +static const uint32_t CHANNEL_CUS_TRADE_WASTE = 0x00004005; // Custom -> Trade Wastelands +static const uint32_t CHANNEL_CUS_OOC = 0x04000005; // Custom -> OOC +static const uint32_t CHANNEL_CUS_PLAYERHELP = 0x02000005; // Custom -> Player 2 Player help +static const uint32_t CHANNEL_CUS_CLANSEARCH = 0x01000005; // Custom -> Searching Clan +static const uint32_t CHANNEL_CUS_SERVICES_CANYON = 0x00040005; // Custom -> Runner Services Canyon +static const uint32_t CHANNEL_CUS_SERVICES_MB = 0x00010005; // Custom -> Runner Services MB +static const uint32_t CHANNEL_CUS_SERVICES_NC = 0x00008005; // Custom -> Runner Services NC +static const uint32_t CHANNEL_CUS_SERVICES_TH = 0x00020005; // Custom -> Runner Services TH +static const uint32_t CHANNEL_CUS_SERVICES_WASTE = 0x00080005; // Custom -> Runner Services Wastelands +static const uint32_t CHANNEL_CUS_TEAM_10 = 0x00100005; // Custom -> Searching Team ~10 +static const uint32_t CHANNEL_CUS_TEAM_30 = 0x00200005; // Custom -> Searching Team ~30 +static const uint32_t CHANNEL_CUS_TEAM_50 = 0x00400005; // Custom -> Searching Team ~50 +static const uint32_t CHANNEL_CUS_TEAM_70 = 0x00800005; // Custom -> Searching Team ~70 +static const uint32_t CHANNEL_ADMIN = 0x000000FF; // Admin chat +static const uint32_t CHANNEL_GMADMIN = 0x000000FE; // Admin chat +static const uint32_t CHANNEL_GMCHAT = 0x000000FD; // GameMaster chat +/* +#################### + CHANNEL-CODES: + (OUTGOING) +#################### +*/ +static const uint8_t CHAT_BUDDY[] = {0x00, 0x10}; +static const uint8_t CHAT_LOCAL[] = {0x01, 0x10}; +static const uint8_t CHAT_CLAN[] = {0x02, 0x10}; +static const uint8_t CHAT_TEAM[] = {0x03, 0x10}; +static const uint8_t CHAT_DIRECT[] = {0x04, 0x10}; +static const uint8_t CHAT_ZONE[] = {0x05, 0x00}; +static const uint8_t CHAT_FRAK[] = {0x05, 0x01}; +static const uint8_t CHAT_TRADECS[] = {0x05, 0x05}; +static const uint8_t CHAT_TRADEMB[] = {0x05, 0x03}; +static const uint8_t CHAT_TRADENC[] = {0x05, 0x02}; +static const uint8_t CHAT_TRADETH[] = {0x05, 0x04}; +static const uint8_t CHAT_TRADEWL[] = {0x05, 0x06}; +static const uint8_t CHAT_OOC[] = {0x05, 0x12}; +static const uint8_t CHAT_HELP[] = {0x05, 0x11}; +static const uint8_t CHAT_CLANSEARCH[] = {0x05, 0x10}; +static const uint8_t CHAT_SERVICECS[] = {0x05, 0x0A}; +static const uint8_t CHAT_SERVICESMB[] = {0x05, 0x08}; +static const uint8_t CHAT_SERVICESNC[] = {0x05, 0x07}; +static const uint8_t CHAT_SERVICESTH[] = {0x05, 0x09}; +static const uint8_t CHAT_SERVICESWL[] = {0x05, 0x0B}; +static const uint8_t CHAT_TEAM10[] = {0x05, 0x0C}; +static const uint8_t CHAT_TEAM30[] = {0x05, 0x0D}; +static const uint8_t CHAT_TEAM50[] = {0x05, 0x0E}; +static const uint8_t CHAT_TEAM70[] = {0x05, 0x0F}; +static const uint8_t CHAT_ADMIN[] = {0xFF, 0x10}; +static const uint8_t CHAT_GMADMIN[] = {0xFE, 0x10}; +static const uint8_t CHAT_GM[] = {0xFD, 0x10}; + +/* +#################### + CHANNEL-CODES: +(EN/DISABLE-ABLE CHANNELS) +#################### +*/ +static const uint32_t C_ZONE = 1; +static const uint32_t C_FRAK = 2; +static const uint32_t C_TRADENC = 4; +static const uint32_t C_TRADEMB = 8; +static const uint32_t C_TRADETH = 16; +static const uint32_t C_TRADECS = 32; +static const uint32_t C_TRADEWL = 64; +static const uint32_t C_SERVICENC = 128; +static const uint32_t C_SERVICEMB = 256; +static const uint32_t C_SERVICETH = 512; +static const uint32_t C_SERVICECS = 1024; +static const uint32_t C_SERVICEWL = 2048; +static const uint32_t C_TEAM10 = 4096; +static const uint32_t C_TEAM30 = 8192; +static const uint32_t C_TEAM50 = 16384; +static const uint32_t C_TEAM70 = 32768; +static const uint32_t C_CLANSEARCH = 65536; +static const uint32_t C_HELP = 131072; +static const uint32_t C_OOC = 262144; diff --git a/TinNS/Source/GameServer/Client.cxx b/TinNS/Source/GameServer/Client.cxx index 7011b38..c3e0508 100644 --- a/TinNS/Source/GameServer/Client.cxx +++ b/TinNS/Source/GameServer/Client.cxx @@ -1,680 +1,680 @@ -#include "GameServer/Includes.hxx" -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -PClient::PClient( int Index ) -{ - mAccountID = 0; - mAccountLevel = 0; - mIndex = Index; - mCharID = 0; - mConnection = PCC_NONE; - mRemotePort = 0; - m_TCPConnection = NULL; - m_UDPConnection = NULL; - - for ( int i = 0; i < DEBUG_MODES ; i++ ) - mDebugMode[i] = false; - - //******** - mAwaitingWarpto = false; - mTargetX = 0; - mTargetY = 0; - mTargetZ = 0; - //******** - mActorRemoveMode = false; - mAcceptNPCUpdates = false; - - testval8 = 0; -} - -PClient::~PClient() -{ - if ( m_TCPConnection ) - { - delete m_TCPConnection; - m_TCPConnection = NULL; - } - if ( m_UDPConnection ) - { - delete m_UDPConnection; - m_UDPConnection = NULL; - } -} -/// ****************************************************** - -bool PClient::GetDebugMode(PDebugMode nDebugID) -{ - return mDebugMode[nDebugID]; -} - -bool PClient::IsAcceptingNPCUpdates() -{ - return mAcceptNPCUpdates; -} - -void PClient::SetAcceptNPCUpdates(bool nVal) -{ - mAcceptNPCUpdates = nVal; -} - -bool PClient::IsZoning() -{ - return mZoning; -} - -void PClient::SetZoning(bool nVal) -{ - mZoning = nVal; - if (!nVal) - mVhcZoning = false; -} - -bool PClient::IsVhcZoning() -{ - return mVhcZoning; -} - -void PClient::SetVhcZoning(bool nVal) -{ - mVhcZoning = nVal; -} - -uint32_t PClient::GetIndex() const -{ - return mIndex; -} - -uint32_t PClient::GetID() const -{ - return mIndex; -} - -uint32_t PClient::GetLocalID() const -{ - return mIndex + 1; -} - -uint32_t PClient::GetCharID() const -{ - return mCharID; -} - -int PClient::GetRemoteUDPPort() const -{ - return mRemotePort; -} - -bool PClient::IsInRemoveActorMode() -{ - return mActorRemoveMode; -} - -void PClient::SetRemoveActorMode(bool nNewValue) -{ - mActorRemoveMode = nNewValue; -} - -void PClient::SetRemoteUDPPort(int port) -{ - mRemotePort = port; -} - -void PClient::SetCharID(int id) -{ - mCharID = id; -} - -uint16_t PClient::GetUDP_ID() -{ - if ( m_UDPConnection ) - return m_UDPConnection->GetUDP_ID(); - else - Console->Print( "%s Unable to get UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); - return 0; -} - -void PClient::SetUDP_ID( int id ) -{ - if ( m_UDPConnection ) - m_UDPConnection->SetUDP_ID( id ); - else - Console->Print( "%s Unable to set UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); -} - -void PClient::IncreaseUDP_ID() -{ - if ( m_UDPConnection ) - m_UDPConnection->IncreaseUDP_ID(); - else - Console->Print( "%s Unable to increase UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); -} - -uint16_t PClient::GetSessionID() -{ - if ( m_UDPConnection ) - return m_UDPConnection->GetSessionID(); - else - Console->Print( "%s Unable to get UDP SessionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); - return 0; -} - -uint16_t PClient::GetTransactionID() -{ - if ( m_UDPConnection ) - return m_UDPConnection->GetTransactionID(); - else - Console->Print( "%s Unable to get UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); - return 0; -} - -void PClient::ResetTransactionID() -{ - if ( m_UDPConnection ) - m_UDPConnection->ResetTransactionID(); - else - Console->Print( "%s Unable to reset UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); -} - -void PClient::IncreaseTransactionID( uint8_t nInc ) -{ - if ( m_UDPConnection ) - m_UDPConnection->IncreaseTransactionID( nInc ); - else - Console->Print( "%s Unable to increase UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); -} - -void PClient::FillInUDP_ID( PMessage* nMessage ) -{ - uint16_t CurrPos; - - if (( nMessage->GetSize() > 9 ) && ( nMessage->U8Data( 0x00 ) == 0x13 ) ) - { - CurrPos = 5; - while ( CurrPos < nMessage->GetSize() ) // do UDP_ID mgt for each 0x03 subtype subpacket - { - if ( nMessage->U8Data( CurrPos + 1 ) == 0x03 ) - { - IncreaseUDP_ID(); - nMessage->U16Data( CurrPos + 2 ) = GetUDP_ID(); - } - CurrPos = CurrPos + nMessage->U8Data( CurrPos ) + 1; - } - } - nMessage->U16Data( 0x01 ) = GetUDP_ID(); - nMessage->U16Data( 0x03 ) = GetSessionID(); -} - -void PClient::setTCPConnection(ConnectionTCP *conn) -{ - m_TCPConnection = conn; - m_UDPConnection = nullptr; - mConnection = PCC_GAME; -} - -void PClient::setUDPConnection(ConnectionUDP *conn) -{ - m_UDPConnection = conn; -} - -ConnectionTCP *PClient::getTCPConn() -{ - return m_TCPConnection; -} - -ConnectionUDP *PClient::getUDPConn() -{ - return m_UDPConnection; -} - -void PClient::SendTCPMessage(PMessage *nMessage) -{ - if (m_TCPConnection) - m_TCPConnection->SendMessage(nMessage); - else - delete nMessage; -} - -void PClient::FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType ) -{ - PMessage* ChunkBuffer; - PMessage* ChunkMsg; - const uint16_t ChunkSize = 220; - uint16_t StartIncUDPIDOnChunk = 0; - uint16_t IncludedHeaderSize = 0; - bool ReplaceFirstByte = false; - uint8_t ReplaceFirstByteValue = 0; - uint16_t MultiTriggeringSize = 0; - - switch ( nType ) - { - case 0x68: // Terminal ReceiveDB - { - ReplaceFirstByte = true; - ReplaceFirstByteValue = 0x21; - MultiTriggeringSize = 220; - IncludedHeaderSize = 9; - StartIncUDPIDOnChunk = 1; - break; - } - case 0x04: - { - Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed yet", nType ); - break; - } - case 0x05: //CharOpenContainerMsg with header & UDP_ID incremented - { - StartIncUDPIDOnChunk = 1; - IncludedHeaderSize = 9; - ReplaceFirstByte = true; - ReplaceFirstByteValue = 0x15; - MultiTriggeringSize = 230; - break; - } - case 0x06: // For sending Custom LUA Scripts to client - { - break; - } - case 0x19: //BaselineMsg (with no header) - { - break; - } - case 0xac: //BuildTraderItemListMsg with header & UDP_ID incremented - { - StartIncUDPIDOnChunk = 1; - IncludedHeaderSize = 9; - ReplaceFirstByte = true; - ReplaceFirstByteValue = 0x15; - MultiTriggeringSize = 230; - break; - } - default: - { - Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed", nType ); - break; - } - } - - if ( nMessage->GetSize() >= MultiTriggeringSize ) - { - if ( gDevDebug ) - Console->Print( YELLOW, BLACK, "[Debug] Fragmenting message type 0x%02x", nType ); - if ( ReplaceFirstByte ) - { - nMessage->U8Data( IncludedHeaderSize ) = ReplaceFirstByteValue; - } - - uint16_t ChunksNum = ( nMessage->GetSize() - IncludedHeaderSize + ChunkSize - 1 ) / ChunkSize; - - for ( uint16_t ChunkID = 0; ChunkID < ChunksNum; ChunkID++ ) - { - ChunkBuffer = nMessage->GetChunk( IncludedHeaderSize, ChunkSize, ChunkID ); - if ( ChunkBuffer == NULL ) - { - Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Bad chunk number: %d for size %d", ChunksNum, nMessage->GetSize() ); - break; - } - - ChunkMsg = new PMessage( ChunkSize + 15 ); - if ( ChunkID >= StartIncUDPIDOnChunk ) - { - IncreaseUDP_ID(); - } - - *ChunkMsg << ( uint8_t )0x13; - *ChunkMsg << ( uint16_t )GetUDP_ID(); - *ChunkMsg << ( uint16_t )GetSessionID(); - *ChunkMsg << ( uint8_t )( 9 + ChunkBuffer->GetSize() ); - *ChunkMsg << ( uint8_t )0x03; - *ChunkMsg << ( uint16_t )GetUDP_ID(); - *ChunkMsg << ( uint8_t )0x07; // Fragmented - *ChunkMsg << ( uint16_t )ChunkID; - *ChunkMsg << ( uint16_t )ChunksNum; - *ChunkMsg << ( uint8_t )nType; - *ChunkMsg << *ChunkBuffer; - - delete ChunkBuffer; - //Console->Print(YELLOW, BLACK, "[Debug] Sending Fragment %d/%d", ChunkID+1, ChunksNum); - //ChunkMsg->Dump(); - SendUDPMessage( ChunkMsg ); - } - delete nMessage; - } - else - { - //Console->Print(YELLOW, BLACK, "[Debug] Sending message WITHOUT Fragmenting"); - SendUDPMessage( nMessage ); - } -} - -void PClient::SendUDPMessage(PMessage *nMessage, bool nVIP) -{ - if (m_UDPConnection) - m_UDPConnection->SendMessage(nMessage, nVIP); - else - delete nMessage; -} - -void PClient::SetDebugMode( PDebugMode nDebugID, bool nVal ) -{ - if ( nDebugID == DBG_ALL ) - { - for ( int i = 0; i < DEBUG_MODES ; i++ ) - mDebugMode[i] = nVal; - } - else - mDebugMode[nDebugID] = nVal; -} - -bool PClient::ChangeCharLocation( uint32_t nLocation, bool DoForce ) -{ - if ( gDevDebug ) - Console->Print( "%s PClient::ChangeCharLocation", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - if ( Worlds->IsValidWorld( nLocation ) ) - { - mAcceptNPCUpdates = false; // Zone changed, reject NPC updates till initial NPC spawn - PChar* tChar = GetChar(); - uint32_t CurrentLocation = tChar->GetLocation(); - if (( CurrentLocation == nLocation ) && !DoForce ) - return true; - - // DoForce is used in GM teleport and jail/unjail command to free player from jail - if (( tChar->IsJailed() == true ) && !DoForce ) - { - if ( CurrentLocation != 550 && CurrentLocation != 551 ) // If player managed to "get out of jail" somehow, replace him there - { - // Do nothing here. This doesnt work as long as we are able to warp the player around just by - // sending some packets out. Enable/modify this if fixed - //tChar->SetLocation(550); - } - // Player still in 550 or 551 and trying to warp out (by death for example) just - // return true and let him respawn at 550 entrypoint 0 - //return true; - } - - PWorld* nWorld; - if (( nWorld = Worlds->LeaseWorld( nLocation ) ) ) - { - if ( tChar->GetLocationLeased() ) - { - // TAke care of sitting chars - uint32_t ChairObjectId; - uint8_t tSeatId; - PSeatType tSeatType; - if (( tSeatType = tChar->GetSeatInUse( &ChairObjectId, &tSeatId ) ) ) - { - bool vhcZoning = false; - PSpawnedVehicle* tVhc = 0; - if ( (tSeatType == seat_vhc) && IsVhcZoning() ) // If seat is vhc, - { // Do additionnal check - if (( tVhc = nWorld->GetSpawnedVehicles()->GetVehicle( ChairObjectId ) ) ) - { - if ( tVhc->GetSeatUser( tSeatId ) == tChar->GetID() ) - { - vhcZoning = true; - } - } - } - - if ( ! vhcZoning ) - { - PUdpCharExitChair::DoLeaveChair( tChar, this, tVhc, true ); - } - /*{ - Worlds->GetWorld( CurrentLocation )->CharLeaveChair( GetLocalID(), ChairObjectId ); - tChar->SetSeatInUse( seat_none ); - }*/ - } - this->InitWarpCircle(); - this->InitCharVanish(); - Worlds->ReleaseWorld( CurrentLocation ); - } - tChar->SetLocation( nLocation ); - tChar->SetLocationLeased(); - - return true; - } - } - else if ( nLocation != 1 ) // try to fall back if bad location - { - Console->Print( YELLOW, BLACK, "[Warning] Client %d want to zone to invalid world %d. Falling back to world 1", mIndex, nLocation ); - return ChangeCharLocation( 1, DoForce ); - } - - return false; -} - -int PClient::GetConnection() const -{ - return mConnection; -} - -const char *PClient::GetAddress() const -{ - return m_TCPConnection->getRemoteAddress(); -} - -uint32_t PClient::GetAccountID() const -{ - return mAccountID; -} - -int PClient::GetAccountLevel() const -{ - return mAccountLevel; -} - -void PClient::GameDisconnect() -{ - mAccountID = 0; - - if ( m_TCPConnection ) - { - delete m_TCPConnection; - m_TCPConnection = NULL; - } - - if ( m_UDPConnection ) - { - delete m_UDPConnection; - m_UDPConnection = NULL; - } - - /**** Will be better to put that char-saving-at-disconnect in Char destructor, when only used Chars will be loaded ****/ - PChar *tChar = GetChar(); - if ( tChar ) - { - SetZoning(); - if ( tChar->GetLocationLeased() ) - { - if ( tChar->GetSeatInUse() ) - { - //if(gDevDebug) - Console->Print( "%s Trying to get leaving char out of her seat", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - PUdpCharExitChair::DoLeaveChair( tChar, this, NULL, true ); - } - /* // replaced by the lines above - PSeatType cSeatType; - uint32_t cSeatObjectId; - uint8_t cSeatId; - PWorld* cWorld; - - cWorld = Worlds->GetWorld(tChar->GetLocation()); - cSeatType = tChar->GetSeatInUse(&cSeatObjectId, &cSeatId); - if(cSeatType) - { - if(cSeatType == seat_chair) - { - cWorld->CharLeaveChair(GetLocalID(), cSeatObjectId); - tChar->SetSeatInUse(seat_none); - } - else if(cSeatType == seat_subway) - { - Subway->UnsetSeatUser(cSeatObjectId, cSeatId, GetLocalID()); - tChar->SetSeatInUse(seat_none); - } - else if(cSeatType == seat_vhc) - { - cWorld->GetSpawnedVehicles()->GetVehicle(cSeatObjectId)->UnsetSeatUser(cSeatId, GetLocalID()); - tChar->SetSeatInUse(seat_none); - } - else - { - Console->Print(RED, BLACK, "[Notice] PClient::GameDisconnect : Leaving seat of unkown type %d", cSeatType); - } - } - */ - } - - if ( tChar->IsDirty() ) - { - bool res = tChar->SQLSave(); - if ( res ) - Console->Print( "%s GameDisconnect: Char %i (Client %i) saved before disconnect.", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex ); - else - Console->Print( RED, BLACK, "[DEBUG] GameDisconnect: Char %i (Client %i) saving before disconnect and FAILED.", tChar->GetID(), mIndex ); - } - else - { - Console->Print( "%s GameDisconnect: Char %i (Client %i) no save needed.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex ); - if ( !tChar->IsOnline() ) - Console->Print( "%s GameDisconnect: Char %i (Client %i) wasn't marked as ingame anyway...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex ); - } - - if ( tChar->GetLocationLeased() ) - { - if ( gDevDebug ) - Console->Print( "%s Sending char leaving effect", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - InitWarpCircle(); - InitCharVanish(); - - Worlds->ReleaseWorld( tChar->GetLocation() ); - tChar->SetLocationLeased( false ); - } - - Chars->RemoveChar( mCharID ); - delete tChar; - mCharID = 0; - } - else - { - //Console->Print(YELLOW, BLACK, "GameDisconnect: Client %i had no char online.", mIndex); - } - /**********************************/ - - //mConnection &= ~PCC_GAME; - mConnection = PCC_NONE; -} - -void PClient::RefreshAccountInfo( PAccount *Account ) -{ - mAccountID = Account->GetID(); - mAccountLevel = Account->GetLevel(); -} - -void PClient::LoggedIn(PAccount *Account) -{ - RefreshAccountInfo(Account); -} - -void PClient::Update() -{ - if ( m_TCPConnection ) - { - if ( m_TCPConnection->timeOut() ) - { - Console->Print( "%s GameSocket: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex ); - GameServer->ClientDisconnected( this ); - } - else - { - if ( !m_TCPConnection->update() ) - { - GameServer->ClientDisconnected( this ); - } - } - } - - if ( m_UDPConnection ) - { - if ( m_UDPConnection->timeOut() ) - { - Console->Print( "%s Game UDP: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex ); - GameServer->UDPStreamClosed( this ); - } - else - { - if ( !m_UDPConnection->update() ) - { - GameServer->UDPStreamClosed( this ); - } - } - } -} - -PChar* PClient::GetChar() const -{ - if ( mCharID ) - { - return Chars->GetChar( mCharID ); - } - else - { - return NULL; - } -} - -int PClient::getZoneID() const -{ - return m_ZoneID; -} - -void PClient::SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ) -{ - mAwaitingWarpto = yesno; - mTargetX = NewX; - mTargetY = NewY; - mTargetZ = NewZ; -} - -bool PClient::GetCharAwaitingWarpto( uint16_t* PosX, uint16_t* PosY, uint16_t* PosZ ) -{ - if ( PosX ) - *PosX = mTargetX; - if ( PosY ) - *PosY = mTargetY; - if ( PosZ ) - *PosZ = mTargetZ; - - return mAwaitingWarpto; - /* - if(mAwaitingWarpto == true) - { - - // Position update doesnt work. Uncomment&Change function if ever required again - mAwaitingWarpto = false; - (GetChar()->Coords).mX = mTargetX; - (GetChar()->Coords).mY = mTargetY; - (GetChar()->Coords).mZ = mTargetZ; - return true; - // PMessage* tmpMsg_posupdate; - // - // tmpMsg_posupdate = MsgBuilder->BuildCharPosMoveMsg(this, mTargetX, mTargetY, mTargetZ); - // ClientManager->UDPBroadcast(tmpMsg_posupdate, this); - // tmpMsg_posupdate = NULL; - } - return false; - */ -} - -void PClient::InitWarpCircle() -{ - PMessage* tmpMsg_circle = MsgBuilder->BuildCharShowGlowCircleMsg( this ); - ClientManager->UDPBroadcast( tmpMsg_circle, this, 1000, true ); // send only in a 1000 radius -} - -void PClient::InitCharVanish() -{ - PMessage* tmpMsg_vanish = MsgBuilder->BuildRemoveWorldObjectMsg( GetLocalID() ); - ClientManager->UDPBroadcast( tmpMsg_vanish, this, 0, true ); -} +#include "GameServer/Includes.hxx" +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +PClient::PClient( int Index ) +{ + mAccountID = 0; + mAccountLevel = 0; + mIndex = Index; + mCharID = 0; + mConnection = PCC_NONE; + mRemotePort = 0; + m_TCPConnection = NULL; + m_UDPConnection = NULL; + + for ( int i = 0; i < DEBUG_MODES ; i++ ) + mDebugMode[i] = false; + + //******** + mAwaitingWarpto = false; + mTargetX = 0; + mTargetY = 0; + mTargetZ = 0; + //******** + mActorRemoveMode = false; + mAcceptNPCUpdates = false; + + testval8 = 0; +} + +PClient::~PClient() +{ + if ( m_TCPConnection ) + { + delete m_TCPConnection; + m_TCPConnection = NULL; + } + if ( m_UDPConnection ) + { + delete m_UDPConnection; + m_UDPConnection = NULL; + } +} +/// ****************************************************** + +bool PClient::GetDebugMode(PDebugMode nDebugID) +{ + return mDebugMode[nDebugID]; +} + +bool PClient::IsAcceptingNPCUpdates() +{ + return mAcceptNPCUpdates; +} + +void PClient::SetAcceptNPCUpdates(bool nVal) +{ + mAcceptNPCUpdates = nVal; +} + +bool PClient::IsZoning() +{ + return mZoning; +} + +void PClient::SetZoning(bool nVal) +{ + mZoning = nVal; + if (!nVal) + mVhcZoning = false; +} + +bool PClient::IsVhcZoning() +{ + return mVhcZoning; +} + +void PClient::SetVhcZoning(bool nVal) +{ + mVhcZoning = nVal; +} + +uint32_t PClient::GetIndex() const +{ + return mIndex; +} + +uint32_t PClient::GetID() const +{ + return mIndex; +} + +uint32_t PClient::GetLocalID() const +{ + return mIndex + 1; +} + +uint32_t PClient::GetCharID() const +{ + return mCharID; +} + +int PClient::GetRemoteUDPPort() const +{ + return mRemotePort; +} + +bool PClient::IsInRemoveActorMode() +{ + return mActorRemoveMode; +} + +void PClient::SetRemoveActorMode(bool nNewValue) +{ + mActorRemoveMode = nNewValue; +} + +void PClient::SetRemoteUDPPort(int port) +{ + mRemotePort = port; +} + +void PClient::SetCharID(int id) +{ + mCharID = id; +} + +uint16_t PClient::GetUDP_ID() +{ + if ( m_UDPConnection ) + return m_UDPConnection->GetUDP_ID(); + else + Console->Print( "%s Unable to get UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); + return 0; +} + +void PClient::SetUDP_ID( int id ) +{ + if ( m_UDPConnection ) + m_UDPConnection->SetUDP_ID( id ); + else + Console->Print( "%s Unable to set UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); +} + +void PClient::IncreaseUDP_ID() +{ + if ( m_UDPConnection ) + m_UDPConnection->IncreaseUDP_ID(); + else + Console->Print( "%s Unable to increase UDP_ID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); +} + +uint16_t PClient::GetSessionID() +{ + if ( m_UDPConnection ) + return m_UDPConnection->GetSessionID(); + else + Console->Print( "%s Unable to get UDP SessionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); + return 0; +} + +uint16_t PClient::GetTransactionID() +{ + if ( m_UDPConnection ) + return m_UDPConnection->GetTransactionID(); + else + Console->Print( "%s Unable to get UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); + return 0; +} + +void PClient::ResetTransactionID() +{ + if ( m_UDPConnection ) + m_UDPConnection->ResetTransactionID(); + else + Console->Print( "%s Unable to reset UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); +} + +void PClient::IncreaseTransactionID( uint8_t nInc ) +{ + if ( m_UDPConnection ) + m_UDPConnection->IncreaseTransactionID( nInc ); + else + Console->Print( "%s Unable to increase UDP TransactionID, UDP ConnectionClass is not yet initialized!", Console->ColorText( RED, BLACK, "[WARNING]" ) ); +} + +void PClient::FillInUDP_ID( PMessage* nMessage ) +{ + uint16_t CurrPos; + + if (( nMessage->GetSize() > 9 ) && ( nMessage->U8Data( 0x00 ) == 0x13 ) ) + { + CurrPos = 5; + while ( CurrPos < nMessage->GetSize() ) // do UDP_ID mgt for each 0x03 subtype subpacket + { + if ( nMessage->U8Data( CurrPos + 1 ) == 0x03 ) + { + IncreaseUDP_ID(); + nMessage->U16Data( CurrPos + 2 ) = GetUDP_ID(); + } + CurrPos = CurrPos + nMessage->U8Data( CurrPos ) + 1; + } + } + nMessage->U16Data( 0x01 ) = GetUDP_ID(); + nMessage->U16Data( 0x03 ) = GetSessionID(); +} + +void PClient::setTCPConnection(ConnectionTCP *conn) +{ + m_TCPConnection = conn; + m_UDPConnection = nullptr; + mConnection = PCC_GAME; +} + +void PClient::setUDPConnection(ConnectionUDP *conn) +{ + m_UDPConnection = conn; +} + +ConnectionTCP *PClient::getTCPConn() +{ + return m_TCPConnection; +} + +ConnectionUDP *PClient::getUDPConn() +{ + return m_UDPConnection; +} + +void PClient::SendTCPMessage(PMessage *nMessage) +{ + if (m_TCPConnection) + m_TCPConnection->SendMessage(nMessage); + else + delete nMessage; +} + +void PClient::FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType ) +{ + PMessage* ChunkBuffer; + PMessage* ChunkMsg; + const uint16_t ChunkSize = 220; + uint16_t StartIncUDPIDOnChunk = 0; + uint16_t IncludedHeaderSize = 0; + bool ReplaceFirstByte = false; + uint8_t ReplaceFirstByteValue = 0; + uint16_t MultiTriggeringSize = 0; + + switch ( nType ) + { + case 0x68: // Terminal ReceiveDB + { + ReplaceFirstByte = true; + ReplaceFirstByteValue = 0x21; + MultiTriggeringSize = 220; + IncludedHeaderSize = 9; + StartIncUDPIDOnChunk = 1; + break; + } + case 0x04: + { + Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed yet", nType ); + break; + } + case 0x05: //CharOpenContainerMsg with header & UDP_ID incremented + { + StartIncUDPIDOnChunk = 1; + IncludedHeaderSize = 9; + ReplaceFirstByte = true; + ReplaceFirstByteValue = 0x15; + MultiTriggeringSize = 230; + break; + } + case 0x06: // For sending Custom LUA Scripts to client + { + break; + } + case 0x19: //BaselineMsg (with no header) + { + break; + } + case 0xac: //BuildTraderItemListMsg with header & UDP_ID incremented + { + StartIncUDPIDOnChunk = 1; + IncludedHeaderSize = 9; + ReplaceFirstByte = true; + ReplaceFirstByteValue = 0x15; + MultiTriggeringSize = 230; + break; + } + default: + { + Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Message type 0x%02x not managed", nType ); + break; + } + } + + if ( nMessage->GetSize() >= MultiTriggeringSize ) + { + if ( gDevDebug ) + Console->Print( YELLOW, BLACK, "[Debug] Fragmenting message type 0x%02x", nType ); + if ( ReplaceFirstByte ) + { + nMessage->U8Data( IncludedHeaderSize ) = ReplaceFirstByteValue; + } + + uint16_t ChunksNum = ( nMessage->GetSize() - IncludedHeaderSize + ChunkSize - 1 ) / ChunkSize; + + for ( uint16_t ChunkID = 0; ChunkID < ChunksNum; ChunkID++ ) + { + ChunkBuffer = nMessage->GetChunk( IncludedHeaderSize, ChunkSize, ChunkID ); + if ( ChunkBuffer == NULL ) + { + Console->Print( RED, BLACK, "[Error] PClient::FragmentAndSendUDPMessage: Bad chunk number: %d for size %d", ChunksNum, nMessage->GetSize() ); + break; + } + + ChunkMsg = new PMessage( ChunkSize + 15 ); + if ( ChunkID >= StartIncUDPIDOnChunk ) + { + IncreaseUDP_ID(); + } + + *ChunkMsg << ( uint8_t )0x13; + *ChunkMsg << ( uint16_t )GetUDP_ID(); + *ChunkMsg << ( uint16_t )GetSessionID(); + *ChunkMsg << ( uint8_t )( 9 + ChunkBuffer->GetSize() ); + *ChunkMsg << ( uint8_t )0x03; + *ChunkMsg << ( uint16_t )GetUDP_ID(); + *ChunkMsg << ( uint8_t )0x07; // Fragmented + *ChunkMsg << ( uint16_t )ChunkID; + *ChunkMsg << ( uint16_t )ChunksNum; + *ChunkMsg << ( uint8_t )nType; + *ChunkMsg << *ChunkBuffer; + + delete ChunkBuffer; + //Console->Print(YELLOW, BLACK, "[Debug] Sending Fragment %d/%d", ChunkID+1, ChunksNum); + //ChunkMsg->Dump(); + SendUDPMessage( ChunkMsg ); + } + delete nMessage; + } + else + { + //Console->Print(YELLOW, BLACK, "[Debug] Sending message WITHOUT Fragmenting"); + SendUDPMessage( nMessage ); + } +} + +void PClient::SendUDPMessage(PMessage *nMessage, bool nVIP) +{ + if (m_UDPConnection) + m_UDPConnection->SendMessage(nMessage, nVIP); + else + delete nMessage; +} + +void PClient::SetDebugMode( PDebugMode nDebugID, bool nVal ) +{ + if ( nDebugID == DBG_ALL ) + { + for ( int i = 0; i < DEBUG_MODES ; i++ ) + mDebugMode[i] = nVal; + } + else + mDebugMode[nDebugID] = nVal; +} + +bool PClient::ChangeCharLocation( uint32_t nLocation, bool DoForce ) +{ + if ( gDevDebug ) + Console->Print( "%s PClient::ChangeCharLocation", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + if ( Worlds->IsValidWorld( nLocation ) ) + { + mAcceptNPCUpdates = false; // Zone changed, reject NPC updates till initial NPC spawn + PChar* tChar = GetChar(); + uint32_t CurrentLocation = tChar->GetLocation(); + if (( CurrentLocation == nLocation ) && !DoForce ) + return true; + + // DoForce is used in GM teleport and jail/unjail command to free player from jail + if (( tChar->IsJailed() == true ) && !DoForce ) + { + if ( CurrentLocation != 550 && CurrentLocation != 551 ) // If player managed to "get out of jail" somehow, replace him there + { + // Do nothing here. This doesnt work as long as we are able to warp the player around just by + // sending some packets out. Enable/modify this if fixed + //tChar->SetLocation(550); + } + // Player still in 550 or 551 and trying to warp out (by death for example) just + // return true and let him respawn at 550 entrypoint 0 + //return true; + } + + PWorld* nWorld; + if (( nWorld = Worlds->LeaseWorld( nLocation ) ) ) + { + if ( tChar->GetLocationLeased() ) + { + // TAke care of sitting chars + uint32_t ChairObjectId; + uint8_t tSeatId; + PSeatType tSeatType; + if (( tSeatType = tChar->GetSeatInUse( &ChairObjectId, &tSeatId ) ) ) + { + bool vhcZoning = false; + PSpawnedVehicle* tVhc = 0; + if ( (tSeatType == seat_vhc) && IsVhcZoning() ) // If seat is vhc, + { // Do additionnal check + if (( tVhc = nWorld->GetSpawnedVehicles()->GetVehicle( ChairObjectId ) ) ) + { + if ( tVhc->GetSeatUser( tSeatId ) == tChar->GetID() ) + { + vhcZoning = true; + } + } + } + + if ( ! vhcZoning ) + { + PUdpCharExitChair::DoLeaveChair( tChar, this, tVhc, true ); + } + /*{ + Worlds->GetWorld( CurrentLocation )->CharLeaveChair( GetLocalID(), ChairObjectId ); + tChar->SetSeatInUse( seat_none ); + }*/ + } + this->InitWarpCircle(); + this->InitCharVanish(); + Worlds->ReleaseWorld( CurrentLocation ); + } + tChar->SetLocation( nLocation ); + tChar->SetLocationLeased(); + + return true; + } + } + else if ( nLocation != 1 ) // try to fall back if bad location + { + Console->Print( YELLOW, BLACK, "[Warning] Client %d want to zone to invalid world %d. Falling back to world 1", mIndex, nLocation ); + return ChangeCharLocation( 1, DoForce ); + } + + return false; +} + +int PClient::GetConnection() const +{ + return mConnection; +} + +const char *PClient::GetAddress() const +{ + return m_TCPConnection->getRemoteAddress(); +} + +uint32_t PClient::GetAccountID() const +{ + return mAccountID; +} + +int PClient::GetAccountLevel() const +{ + return mAccountLevel; +} + +void PClient::GameDisconnect() +{ + mAccountID = 0; + + if ( m_TCPConnection ) + { + delete m_TCPConnection; + m_TCPConnection = NULL; + } + + if ( m_UDPConnection ) + { + delete m_UDPConnection; + m_UDPConnection = NULL; + } + + /**** Will be better to put that char-saving-at-disconnect in Char destructor, when only used Chars will be loaded ****/ + PChar *tChar = GetChar(); + if ( tChar ) + { + SetZoning(); + if ( tChar->GetLocationLeased() ) + { + if ( tChar->GetSeatInUse() ) + { + //if(gDevDebug) + Console->Print( "%s Trying to get leaving char out of her seat", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + PUdpCharExitChair::DoLeaveChair( tChar, this, NULL, true ); + } + /* // replaced by the lines above + PSeatType cSeatType; + uint32_t cSeatObjectId; + uint8_t cSeatId; + PWorld* cWorld; + + cWorld = Worlds->GetWorld(tChar->GetLocation()); + cSeatType = tChar->GetSeatInUse(&cSeatObjectId, &cSeatId); + if(cSeatType) + { + if(cSeatType == seat_chair) + { + cWorld->CharLeaveChair(GetLocalID(), cSeatObjectId); + tChar->SetSeatInUse(seat_none); + } + else if(cSeatType == seat_subway) + { + Subway->UnsetSeatUser(cSeatObjectId, cSeatId, GetLocalID()); + tChar->SetSeatInUse(seat_none); + } + else if(cSeatType == seat_vhc) + { + cWorld->GetSpawnedVehicles()->GetVehicle(cSeatObjectId)->UnsetSeatUser(cSeatId, GetLocalID()); + tChar->SetSeatInUse(seat_none); + } + else + { + Console->Print(RED, BLACK, "[Notice] PClient::GameDisconnect : Leaving seat of unkown type %d", cSeatType); + } + } + */ + } + + if ( tChar->IsDirty() ) + { + bool res = tChar->SQLSave(); + if ( res ) + Console->Print( "%s GameDisconnect: Char %i (Client %i) saved before disconnect.", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex ); + else + Console->Print( RED, BLACK, "[DEBUG] GameDisconnect: Char %i (Client %i) saving before disconnect and FAILED.", tChar->GetID(), mIndex ); + } + else + { + Console->Print( "%s GameDisconnect: Char %i (Client %i) no save needed.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex ); + if ( !tChar->IsOnline() ) + Console->Print( "%s GameDisconnect: Char %i (Client %i) wasn't marked as ingame anyway...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tChar->GetID(), mIndex ); + } + + if ( tChar->GetLocationLeased() ) + { + if ( gDevDebug ) + Console->Print( "%s Sending char leaving effect", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + InitWarpCircle(); + InitCharVanish(); + + Worlds->ReleaseWorld( tChar->GetLocation() ); + tChar->SetLocationLeased( false ); + } + + Chars->RemoveChar( mCharID ); + delete tChar; + mCharID = 0; + } + else + { + //Console->Print(YELLOW, BLACK, "GameDisconnect: Client %i had no char online.", mIndex); + } + /**********************************/ + + //mConnection &= ~PCC_GAME; + mConnection = PCC_NONE; +} + +void PClient::RefreshAccountInfo( PAccount *Account ) +{ + mAccountID = Account->GetID(); + mAccountLevel = Account->GetLevel(); +} + +void PClient::LoggedIn(PAccount *Account) +{ + RefreshAccountInfo(Account); +} + +void PClient::Update() +{ + if ( m_TCPConnection ) + { + if ( m_TCPConnection->timeOut() ) + { + Console->Print( "%s GameSocket: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex ); + GameServer->ClientDisconnected( this ); + } + else + { + if ( !m_TCPConnection->update() ) + { + GameServer->ClientDisconnected( this ); + } + } + } + + if ( m_UDPConnection ) + { + if ( m_UDPConnection->timeOut() ) + { + Console->Print( "%s Game UDP: Client %i: timeout", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), mIndex ); + GameServer->UDPStreamClosed( this ); + } + else + { + if ( !m_UDPConnection->update() ) + { + GameServer->UDPStreamClosed( this ); + } + } + } +} + +PChar* PClient::GetChar() const +{ + if ( mCharID ) + { + return Chars->GetChar( mCharID ); + } + else + { + return NULL; + } +} + +int PClient::getZoneID() const +{ + return m_ZoneID; +} + +void PClient::SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ) +{ + mAwaitingWarpto = yesno; + mTargetX = NewX; + mTargetY = NewY; + mTargetZ = NewZ; +} + +bool PClient::GetCharAwaitingWarpto( uint16_t* PosX, uint16_t* PosY, uint16_t* PosZ ) +{ + if ( PosX ) + *PosX = mTargetX; + if ( PosY ) + *PosY = mTargetY; + if ( PosZ ) + *PosZ = mTargetZ; + + return mAwaitingWarpto; + /* + if(mAwaitingWarpto == true) + { + + // Position update doesnt work. Uncomment&Change function if ever required again + mAwaitingWarpto = false; + (GetChar()->Coords).mX = mTargetX; + (GetChar()->Coords).mY = mTargetY; + (GetChar()->Coords).mZ = mTargetZ; + return true; + // PMessage* tmpMsg_posupdate; + // + // tmpMsg_posupdate = MsgBuilder->BuildCharPosMoveMsg(this, mTargetX, mTargetY, mTargetZ); + // ClientManager->UDPBroadcast(tmpMsg_posupdate, this); + // tmpMsg_posupdate = NULL; + } + return false; + */ +} + +void PClient::InitWarpCircle() +{ + PMessage* tmpMsg_circle = MsgBuilder->BuildCharShowGlowCircleMsg( this ); + ClientManager->UDPBroadcast( tmpMsg_circle, this, 1000, true ); // send only in a 1000 radius +} + +void PClient::InitCharVanish() +{ + PMessage* tmpMsg_vanish = MsgBuilder->BuildRemoveWorldObjectMsg( GetLocalID() ); + ClientManager->UDPBroadcast( tmpMsg_vanish, this, 0, true ); +} diff --git a/TinNS/Source/GameServer/Client.hxx b/TinNS/Source/GameServer/Client.hxx index 3dbcf57..e56d96e 100644 --- a/TinNS/Source/GameServer/Client.hxx +++ b/TinNS/Source/GameServer/Client.hxx @@ -1,172 +1,172 @@ -#pragma once - -#include - -class ConnectionTCP; -class ConnectionUDP; -class PMessage; - -// TODO: - check that SetUDP_ID, and the mSessionID(UDP_ID_HIGH) real use, -// and if UDP_ID and mSessionID must be synced (like in NeoX) or not - -enum PClientConnection -{ - PCC_NONE = 0, - PCC_GAME = 1 -}; - -// AccountLevel handling is part of accounts.cpp -/* -enum PClientLevel -{ - PCL_BANNED = -1, - PCL_UNREGPLAYER = 0, - PCL_REGPLAYER = 1, - PCL_VOLUNTEER = 30, - PCL_GM = 50, - PCL_ADMIN = 100 -}; -*/ -#define DEBUG_MODES 3 -enum PDebugMode -{ - DBG_LOCATION = 0, - DBG_ITEMID = 1, - DBG_SUBWAY = 2, - DBG_ALL = DEBUG_MODES // must always be last, with DEBUG_MODES updated as needed -}; - - -class PClient -{ - private : - ConnectionTCP* m_TCPConnection; - ConnectionUDP* m_UDPConnection; - - uint32_t mAccountID; - int mAccountLevel; - uint32_t mIndex; - uint32_t mCharID; - -// uint16_t mUDP_ID; -// uint16_t mSessionID; -// uint16_t mTransactionID; - - // AccountLevel handling is part of accounts.cpp - //PClientLevel mLevel; - int mConnection; - int mRemotePort; - - bool mDebugMode[DEBUG_MODES]; - // new multiuser-chat implementation // - int m_ZoneID; - //int[4] m_IP; - - //******* - bool mActorRemoveMode; - //******* - bool mAwaitingWarpto; - uint16_t mTargetX; - uint16_t mTargetY; - uint16_t mTargetZ; - //******* - bool mAcceptNPCUpdates; - bool mZoning; - bool mVhcZoning; - - public : - PClient( int Index ); - ~PClient(); - - bool GetDebugMode(PDebugMode nDebugID); - void SetDebugMode(PDebugMode nDebugID, bool nVal = true); - - bool IsAcceptingNPCUpdates(); - void SetAcceptNPCUpdates(bool nVal); - bool IsZoning(); - void SetZoning(bool nVal = true); - bool IsVhcZoning(); - void SetVhcZoning(bool nVal = true); - - uint32_t GetIndex() const; // better use GetID() - uint32_t GetID() const; // for better coherency with other classes - uint32_t GetLocalID() const; - uint32_t GetCharID() const; - PChar* GetChar() const; - bool ChangeCharLocation(uint32_t nLocation, bool DoForce = false); - - int GetRemoteUDPPort() const; // Temp solution - - bool IsInRemoveActorMode(); - void SetRemoveActorMode(bool nNewValue); - - void SetRemoteUDPPort(int port); // Temp solution - void SetCharID(int id);//NEW added - - /* - inline uint16_t GetUDP_ID() const { return mUDP_ID; } - inline uint16_t GetSessionID() const { return SESSION_UDP_OFFSET + mUDP_ID ; } - inline uint16_t GetTransactionID() {return mTransactionID; } - void SetUDP_ID(int id); - inline void IncreaseUDP_ID() { SetUDP_ID(mUDP_ID + 1); } - inline void ResetTransactionID() { mTransactionID = 10170; } - - inline void IncreaseTransactionID(uint8_t nInc = 1) { mTransactionID += nInc; } - */ - - // All outgoing ID's and stuff is now part of the ConnectionUDP class itself! - // (which is not so good.... comment from Hammag) - // However, we still have full access to it through these functions - uint16_t GetUDP_ID(); - void SetUDP_ID( int id ); - void IncreaseUDP_ID(); - - uint16_t GetSessionID(); - - uint16_t GetTransactionID(); - void ResetTransactionID(); - void IncreaseTransactionID( uint8_t nInc = 1 ); - - void FillInUDP_ID( PMessage* nMessage ); - -// ************************************************************************ // - // AccountLevel handling is part of accounts.cpp - //inline PClientLevel GetLevel() const { return mLevel; } - - void setTCPConnection(ConnectionTCP *conn); - void setUDPConnection(ConnectionUDP *conn); - - ConnectionTCP* getTCPConn(); - ConnectionUDP* getUDPConn(); - - void SendTCPMessage(PMessage *nMessage); - void FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType ); - void SendUDPMessage(PMessage *nMessage, bool nVIP = false); - - int GetConnection() const; - const char *GetAddress() const; - uint32_t GetAccountID() const; - int GetAccountLevel() const; - - void GameDisconnect(); - - void RefreshAccountInfo(PAccount *Account); - void LoggedIn(PAccount *Account); - void Update(); - - // new multiuser-chat implementation // - int getZoneID() const; - //inline int* getIP() const { return (int*) m_IP; } - - void SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ); - bool GetCharAwaitingWarpto(uint16_t* PosX = NULL, uint16_t* PosY = NULL, uint16_t* PosZ = NULL); - - // Char broadcasted effects - void InitWarpCircle(); - void InitCharVanish(); - - // used for dynamic ingame testing - uint8_t testval8; - uint16_t testval16; - uint32_t testval32; -}; +#pragma once + +#include + +class ConnectionTCP; +class ConnectionUDP; +class PMessage; + +// TODO: - check that SetUDP_ID, and the mSessionID(UDP_ID_HIGH) real use, +// and if UDP_ID and mSessionID must be synced (like in NeoX) or not + +enum PClientConnection +{ + PCC_NONE = 0, + PCC_GAME = 1 +}; + +// AccountLevel handling is part of accounts.cpp +/* +enum PClientLevel +{ + PCL_BANNED = -1, + PCL_UNREGPLAYER = 0, + PCL_REGPLAYER = 1, + PCL_VOLUNTEER = 30, + PCL_GM = 50, + PCL_ADMIN = 100 +}; +*/ +#define DEBUG_MODES 3 +enum PDebugMode +{ + DBG_LOCATION = 0, + DBG_ITEMID = 1, + DBG_SUBWAY = 2, + DBG_ALL = DEBUG_MODES // must always be last, with DEBUG_MODES updated as needed +}; + + +class PClient +{ + private : + ConnectionTCP* m_TCPConnection; + ConnectionUDP* m_UDPConnection; + + uint32_t mAccountID; + int mAccountLevel; + uint32_t mIndex; + uint32_t mCharID; + +// uint16_t mUDP_ID; +// uint16_t mSessionID; +// uint16_t mTransactionID; + + // AccountLevel handling is part of accounts.cpp + //PClientLevel mLevel; + int mConnection; + int mRemotePort; + + bool mDebugMode[DEBUG_MODES]; + // new multiuser-chat implementation // + int m_ZoneID; + //int[4] m_IP; + + //******* + bool mActorRemoveMode; + //******* + bool mAwaitingWarpto; + uint16_t mTargetX; + uint16_t mTargetY; + uint16_t mTargetZ; + //******* + bool mAcceptNPCUpdates; + bool mZoning; + bool mVhcZoning; + + public : + PClient( int Index ); + ~PClient(); + + bool GetDebugMode(PDebugMode nDebugID); + void SetDebugMode(PDebugMode nDebugID, bool nVal = true); + + bool IsAcceptingNPCUpdates(); + void SetAcceptNPCUpdates(bool nVal); + bool IsZoning(); + void SetZoning(bool nVal = true); + bool IsVhcZoning(); + void SetVhcZoning(bool nVal = true); + + uint32_t GetIndex() const; // better use GetID() + uint32_t GetID() const; // for better coherency with other classes + uint32_t GetLocalID() const; + uint32_t GetCharID() const; + PChar* GetChar() const; + bool ChangeCharLocation(uint32_t nLocation, bool DoForce = false); + + int GetRemoteUDPPort() const; // Temp solution + + bool IsInRemoveActorMode(); + void SetRemoveActorMode(bool nNewValue); + + void SetRemoteUDPPort(int port); // Temp solution + void SetCharID(int id);//NEW added + + /* + inline uint16_t GetUDP_ID() const { return mUDP_ID; } + inline uint16_t GetSessionID() const { return SESSION_UDP_OFFSET + mUDP_ID ; } + inline uint16_t GetTransactionID() {return mTransactionID; } + void SetUDP_ID(int id); + inline void IncreaseUDP_ID() { SetUDP_ID(mUDP_ID + 1); } + inline void ResetTransactionID() { mTransactionID = 10170; } + + inline void IncreaseTransactionID(uint8_t nInc = 1) { mTransactionID += nInc; } + */ + + // All outgoing ID's and stuff is now part of the ConnectionUDP class itself! + // (which is not so good.... comment from Hammag) + // However, we still have full access to it through these functions + uint16_t GetUDP_ID(); + void SetUDP_ID( int id ); + void IncreaseUDP_ID(); + + uint16_t GetSessionID(); + + uint16_t GetTransactionID(); + void ResetTransactionID(); + void IncreaseTransactionID( uint8_t nInc = 1 ); + + void FillInUDP_ID( PMessage* nMessage ); + +// ************************************************************************ // + // AccountLevel handling is part of accounts.cpp + //inline PClientLevel GetLevel() const { return mLevel; } + + void setTCPConnection(ConnectionTCP *conn); + void setUDPConnection(ConnectionUDP *conn); + + ConnectionTCP* getTCPConn(); + ConnectionUDP* getUDPConn(); + + void SendTCPMessage(PMessage *nMessage); + void FragmentAndSendUDPMessage( PMessage* nMessage, uint8_t nType ); + void SendUDPMessage(PMessage *nMessage, bool nVIP = false); + + int GetConnection() const; + const char *GetAddress() const; + uint32_t GetAccountID() const; + int GetAccountLevel() const; + + void GameDisconnect(); + + void RefreshAccountInfo(PAccount *Account); + void LoggedIn(PAccount *Account); + void Update(); + + // new multiuser-chat implementation // + int getZoneID() const; + //inline int* getIP() const { return (int*) m_IP; } + + void SetAwaitingWarpto(bool yesno, uint16_t NewX, uint16_t NewY, uint16_t NewZ); + bool GetCharAwaitingWarpto(uint16_t* PosX = NULL, uint16_t* PosY = NULL, uint16_t* PosZ = NULL); + + // Char broadcasted effects + void InitWarpCircle(); + void InitCharVanish(); + + // used for dynamic ingame testing + uint8_t testval8; + uint16_t testval16; + uint32_t testval32; +}; diff --git a/TinNS/Source/GameServer/ClientManager.cxx b/TinNS/Source/GameServer/ClientManager.cxx index efe902a..433e8fe 100644 --- a/TinNS/Source/GameServer/ClientManager.cxx +++ b/TinNS/Source/GameServer/ClientManager.cxx @@ -1,262 +1,262 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -// TODO: - these are just begining of modif, as the Client Manager is bound to be a major component for multiplayer management - -PClientManager::PClientManager() -{ - //mLastID = 0; -} - - -PClientManager::~PClientManager() -{ - /* - for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++) - { - delete it->second; - } - */ -} - -bool PClientManager::addClientToList( PClient* newClient ) -{ - if ( !newClient ) - return false; - - PClientMap::const_iterator it = mClientList.find( newClient->GetLocalID() ); - if ( it == mClientList.end() ) // only if client not found in list - { - /* mClientList.insert(std::make_pair(m_LastID, newClient)); - ++m_LastID; */ - - mClientList.insert( std::make_pair( newClient->GetLocalID(), newClient ) ); - //Console->Print(GREEN, BLACK, "Client %d added to clientmanager", newClient->GetIndex()); - /* if(newClient) - { - return true; - } */ - return true; - } - else - return false; -} - -// Check if a zone is in use -bool PClientManager::IsWorldInUse( uint32_t nWorldID ) const -{ - for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) - { - if ( it->second && it->second->GetChar() ) - { - if ( it->second->GetChar()->GetLocation() == nWorldID ) - return true; - } - } - return false; -} - -// Check if a rawObjectId belongs to a char is in use -PClient* PClientManager::GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const -{ - PClient* nClient; - for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) - { - // note: atm, charid = clientid+1 in any zone (client.h) - if ( (nClient = it->second) && ( nClient->GetLocalID() == rawObjectId ) ) - { - if ( nClient->GetChar() && ( nClient->GetChar()->GetLocation() == nWorldID ) ) - return nClient; - } - } - return 0; -} - -void PClientManager::deleteClientFromList( uint32_t id ) -{ - PClientMap::iterator it = mClientList.find( id ); - if ( it != mClientList.end() ) - { - mClientList.erase( it ); - //Console->Print(YELLOW, BLACK, "Client %d removed from clientmanager", ((PClient*)(it->second))->GetIndex()); - } -} - -/* bool PClientManager::deleteClientFromList(PClient* delClient) -{ - for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++) - { - if(delClient == it->second) - { - // if(it->second) - // { - // delete delClient; - mClientList.erase( it ); - return true; - // } - } - } - return false; -} */ - -PClient* PClientManager::getClientByID( uint32_t id ) const -{ - PClientMap::const_iterator it = mClientList.find( id ); - return (( it != mClientList.end() ) ? ( PClient* )( it->second ) : NULL ); -} - -PClient* PClientManager::getClientByChar( uint32_t CharID ) const -{ - for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) - { - if ( it->second ) - { - if ( it->second->GetCharID() == CharID ) - return it->second; - } - } - return NULL; -} - -PClient* PClientManager::getClientByChar( const std::string &Name ) const -{ - for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) - { - if ( it->second ) - { - if ( it->second->GetChar()->GetName() == Name ) - return it->second; - } - } - return NULL; -} - -/* uint32_t PClientManager::getClientID(PClient* _client) -{ - for(PClientMap::iterator it=mClientList.begin(); it!=mClientList

.end(); it++) - { - if(_client == it->second) - { - return it->first; - } - } - - return -1; -} */ - -// Distance checking doesn't care for Z axis ATM -int PClientManager::UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX, uint16_t nY, uint16_t nZ, uint16_t nMaxDist, uint32_t nSkipCharId, bool nNPCPing ) -{ - int msgCount = 0; - PChar* nChar; - PMessage* tmpMsg; - PClient* itClient; - uint16_t Dapprox; - - for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ ) - { - itClient = ( PClient* )( it->second ); - - // Dont send NPC alive messages when client is not ready for them - if ( !itClient->IsAcceptingNPCUpdates() && nNPCPing ) - continue; - - if ( itClient->getUDPConn() ) - { - nChar = itClient->GetChar(); - if ( nChar && ( nChar->GetLocation() != nZoneID ) )// if limited to zone, do check - continue; - - if (itClient->GetCharID() == nSkipCharId ) // if source of broadcast should be skipped - continue; - - if ( nMaxDist ) // if limited to distance, do check - { - Dapprox = DistanceApprox(( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nX, nY, nZ ); - if ( Dapprox > nMaxDist ) - continue; - } - - /*tmpMsg = new PMessage(nMessage->GetMaxSize()); - (*tmpMsg) = (*nMessage);*/ - tmpMsg = new PMessage( *nMessage ); - - itClient->FillInUDP_ID( tmpMsg ); - itClient->SendUDPMessage( tmpMsg ); - ++msgCount; - } - } - - //Console->Print("Broadcast in zone %d to %d chars", nZoneID, msgCount); - delete nMessage; - return msgCount; -} - -int PClientManager::UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist, bool nSkipSource, bool nNPCPing ) -{ - PChar* nChar; - uint32_t skipCharId = nSkipSource ? nClient->GetCharID() : 0 ; - - if ( nClient && ( nChar = nClient->GetChar() ) ) - { - return UDPBroadcast( nMessage, nChar->GetLocation(), ( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nMaxDist, skipCharId, nNPCPing ); - } - else - { - delete nMessage; - return 0; - } -} - -int PClientManager::SendUDPZoneWelcomeToClient( PClient* nClient ) -{ - int msgCount = 0; - PChar* nChar; - PChar* itChar; - PMessage* tmpMsg; - uint32_t nZoneID; - PClient* itClient; - - if ( nClient && ( nChar = nClient->GetChar() ) ) // if nClient is set, always use its zone - { - nZoneID = nChar->GetLocation(); - } - else - return 0; - - for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ ) - { - if ( nClient->GetLocalID() == it->first ) - continue; - - itClient = ( PClient* )( it->second ); - if ( itClient->getUDPConn() ) - { - itChar = itClient->GetChar(); - if ( itChar->GetLocation() != nZoneID ) // limit to zone - continue; - - tmpMsg = MsgBuilder->BuildCharHelloMsg( itClient ); - - nClient->FillInUDP_ID( tmpMsg ); - nClient->SendUDPMessage( tmpMsg ); - //Console->Print("Welcome data sent from client %d to client %d", itClient->GetIndex(), nClient->GetIndex()); - //tmpMsg->Dump(); - - if ( itChar->GetSeatInUse() != seat_none ) - { - tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( itClient ); - nClient->FillInUDP_ID( tmpMsg ); - nClient->SendUDPMessage( tmpMsg ); - - //Console->Print("Sit on chair %d sent from client %d to client %d", (itChar->GetChairInUse()+1)*1024, itClient->GetIndex(), nClient->GetIndex()); - /*tmpMsg = MsgBuilder->BuildCharUseSeatMsg(itClient, (itChar->GetChairInUse()+1)*1024); - nClient->FillInUDP_ID(tmpMsg); - nClient->SendUDPMessage(tmpMsg);*/ - } - ++msgCount; - } - } - - return msgCount; -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +// TODO: - these are just begining of modif, as the Client Manager is bound to be a major component for multiplayer management + +PClientManager::PClientManager() +{ + //mLastID = 0; +} + + +PClientManager::~PClientManager() +{ + /* + for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++) + { + delete it->second; + } + */ +} + +bool PClientManager::addClientToList( PClient* newClient ) +{ + if ( !newClient ) + return false; + + PClientMap::const_iterator it = mClientList.find( newClient->GetLocalID() ); + if ( it == mClientList.end() ) // only if client not found in list + { + /* mClientList.insert(std::make_pair(m_LastID, newClient)); + ++m_LastID; */ + + mClientList.insert( std::make_pair( newClient->GetLocalID(), newClient ) ); + //Console->Print(GREEN, BLACK, "Client %d added to clientmanager", newClient->GetIndex()); + /* if(newClient) + { + return true; + } */ + return true; + } + else + return false; +} + +// Check if a zone is in use +bool PClientManager::IsWorldInUse( uint32_t nWorldID ) const +{ + for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) + { + if ( it->second && it->second->GetChar() ) + { + if ( it->second->GetChar()->GetLocation() == nWorldID ) + return true; + } + } + return false; +} + +// Check if a rawObjectId belongs to a char is in use +PClient* PClientManager::GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const +{ + PClient* nClient; + for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) + { + // note: atm, charid = clientid+1 in any zone (client.h) + if ( (nClient = it->second) && ( nClient->GetLocalID() == rawObjectId ) ) + { + if ( nClient->GetChar() && ( nClient->GetChar()->GetLocation() == nWorldID ) ) + return nClient; + } + } + return 0; +} + +void PClientManager::deleteClientFromList( uint32_t id ) +{ + PClientMap::iterator it = mClientList.find( id ); + if ( it != mClientList.end() ) + { + mClientList.erase( it ); + //Console->Print(YELLOW, BLACK, "Client %d removed from clientmanager", ((PClient*)(it->second))->GetIndex()); + } +} + +/* bool PClientManager::deleteClientFromList(PClient* delClient) +{ + for(PClientMap::iterator it=mClientList.begin(); it!=mClientList.end(); it++) + { + if(delClient == it->second) + { + // if(it->second) + // { + // delete delClient; + mClientList.erase( it ); + return true; + // } + } + } + return false; +} */ + +PClient* PClientManager::getClientByID( uint32_t id ) const +{ + PClientMap::const_iterator it = mClientList.find( id ); + return (( it != mClientList.end() ) ? ( PClient* )( it->second ) : NULL ); +} + +PClient* PClientManager::getClientByChar( uint32_t CharID ) const +{ + for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) + { + if ( it->second ) + { + if ( it->second->GetCharID() == CharID ) + return it->second; + } + } + return NULL; +} + +PClient* PClientManager::getClientByChar( const std::string &Name ) const +{ + for ( PClientMap::const_iterator it = mClientList.begin(); it != mClientList.end(); it++ ) + { + if ( it->second ) + { + if ( it->second->GetChar()->GetName() == Name ) + return it->second; + } + } + return NULL; +} + +/* uint32_t PClientManager::getClientID(PClient* _client) +{ + for(PClientMap::iterator it=mClientList.begin(); it!=mClientList

.end(); it++) + { + if(_client == it->second) + { + return it->first; + } + } + + return -1; +} */ + +// Distance checking doesn't care for Z axis ATM +int PClientManager::UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX, uint16_t nY, uint16_t nZ, uint16_t nMaxDist, uint32_t nSkipCharId, bool nNPCPing ) +{ + int msgCount = 0; + PChar* nChar; + PMessage* tmpMsg; + PClient* itClient; + uint16_t Dapprox; + + for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ ) + { + itClient = ( PClient* )( it->second ); + + // Dont send NPC alive messages when client is not ready for them + if ( !itClient->IsAcceptingNPCUpdates() && nNPCPing ) + continue; + + if ( itClient->getUDPConn() ) + { + nChar = itClient->GetChar(); + if ( nChar && ( nChar->GetLocation() != nZoneID ) )// if limited to zone, do check + continue; + + if (itClient->GetCharID() == nSkipCharId ) // if source of broadcast should be skipped + continue; + + if ( nMaxDist ) // if limited to distance, do check + { + Dapprox = DistanceApprox(( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nX, nY, nZ ); + if ( Dapprox > nMaxDist ) + continue; + } + + /*tmpMsg = new PMessage(nMessage->GetMaxSize()); + (*tmpMsg) = (*nMessage);*/ + tmpMsg = new PMessage( *nMessage ); + + itClient->FillInUDP_ID( tmpMsg ); + itClient->SendUDPMessage( tmpMsg ); + ++msgCount; + } + } + + //Console->Print("Broadcast in zone %d to %d chars", nZoneID, msgCount); + delete nMessage; + return msgCount; +} + +int PClientManager::UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist, bool nSkipSource, bool nNPCPing ) +{ + PChar* nChar; + uint32_t skipCharId = nSkipSource ? nClient->GetCharID() : 0 ; + + if ( nClient && ( nChar = nClient->GetChar() ) ) + { + return UDPBroadcast( nMessage, nChar->GetLocation(), ( nChar->Coords ).mX, ( nChar->Coords ).mY, ( nChar->Coords ).mZ, nMaxDist, skipCharId, nNPCPing ); + } + else + { + delete nMessage; + return 0; + } +} + +int PClientManager::SendUDPZoneWelcomeToClient( PClient* nClient ) +{ + int msgCount = 0; + PChar* nChar; + PChar* itChar; + PMessage* tmpMsg; + uint32_t nZoneID; + PClient* itClient; + + if ( nClient && ( nChar = nClient->GetChar() ) ) // if nClient is set, always use its zone + { + nZoneID = nChar->GetLocation(); + } + else + return 0; + + for ( PClientMap::iterator it = mClientList.begin(); it != mClientList.end(); it++ ) + { + if ( nClient->GetLocalID() == it->first ) + continue; + + itClient = ( PClient* )( it->second ); + if ( itClient->getUDPConn() ) + { + itChar = itClient->GetChar(); + if ( itChar->GetLocation() != nZoneID ) // limit to zone + continue; + + tmpMsg = MsgBuilder->BuildCharHelloMsg( itClient ); + + nClient->FillInUDP_ID( tmpMsg ); + nClient->SendUDPMessage( tmpMsg ); + //Console->Print("Welcome data sent from client %d to client %d", itClient->GetIndex(), nClient->GetIndex()); + //tmpMsg->Dump(); + + if ( itChar->GetSeatInUse() != seat_none ) + { + tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( itClient ); + nClient->FillInUDP_ID( tmpMsg ); + nClient->SendUDPMessage( tmpMsg ); + + //Console->Print("Sit on chair %d sent from client %d to client %d", (itChar->GetChairInUse()+1)*1024, itClient->GetIndex(), nClient->GetIndex()); + /*tmpMsg = MsgBuilder->BuildCharUseSeatMsg(itClient, (itChar->GetChairInUse()+1)*1024); + nClient->FillInUDP_ID(tmpMsg); + nClient->SendUDPMessage(tmpMsg);*/ + } + ++msgCount; + } + } + + return msgCount; +} diff --git a/TinNS/Source/GameServer/ClientManager.hxx b/TinNS/Source/GameServer/ClientManager.hxx index 71eb2db..c99887a 100644 --- a/TinNS/Source/GameServer/ClientManager.hxx +++ b/TinNS/Source/GameServer/ClientManager.hxx @@ -1,35 +1,35 @@ -#pragma once - -#include -#include - -typedef std::map PClientMap; - -class PClientManager { -private: - //int mLastID; - PClientMap mClientList; - -public: - PClientManager(); - ~PClientManager(); - - PClientMap::iterator getClientListBegin() { return mClientList.begin(); } - PClientMap::iterator getClientListEnd() { return mClientList.end(); } - - bool addClientToList( PClient* newClient ); - //void deleteClientFromListByID(int id); - void deleteClientFromList( uint32_t id ); - //bool deleteClientFromList(PClient* delClient); // maybe no use for this... - PClient* getClientByID( uint32_t uint32_t ) const; // returns pointer to a client for further use - PClient* getClientByChar( uint32_t CharID ) const; - PClient* getClientByChar( const std::string &Name ) const; - // int getClientID(PClient* _client); do _client->GetLocalID() - bool IsWorldInUse( uint32_t nWorldID ) const; // Temp until world content fully managed by world - PClient* GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const; // Temp (called by world) until world content fuly managed by world - - // each function return the number of messages sent. - int UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX = 0, uint16_t nY = 0, uint16_t nZ = 0, uint16_t nMaxDist = 0, uint32_t nSkipCharId = 0, bool nNPCPing = false ); - int UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist = 0, bool nSkipSource = false, bool nNPCPing = false ); - int SendUDPZoneWelcomeToClient( PClient* nClient ); -}; +#pragma once + +#include +#include + +typedef std::map PClientMap; + +class PClientManager { +private: + //int mLastID; + PClientMap mClientList; + +public: + PClientManager(); + ~PClientManager(); + + PClientMap::iterator getClientListBegin() { return mClientList.begin(); } + PClientMap::iterator getClientListEnd() { return mClientList.end(); } + + bool addClientToList( PClient* newClient ); + //void deleteClientFromListByID(int id); + void deleteClientFromList( uint32_t id ); + //bool deleteClientFromList(PClient* delClient); // maybe no use for this... + PClient* getClientByID( uint32_t uint32_t ) const; // returns pointer to a client for further use + PClient* getClientByChar( uint32_t CharID ) const; + PClient* getClientByChar( const std::string &Name ) const; + // int getClientID(PClient* _client); do _client->GetLocalID() + bool IsWorldInUse( uint32_t nWorldID ) const; // Temp until world content fully managed by world + PClient* GetClientByCharLocalId( uint32_t rawObjectId, uint32_t nWorldID ) const; // Temp (called by world) until world content fuly managed by world + + // each function return the number of messages sent. + int UDPBroadcast( PMessage* nMessage, uint32_t nZoneID, uint16_t nX = 0, uint16_t nY = 0, uint16_t nZ = 0, uint16_t nMaxDist = 0, uint32_t nSkipCharId = 0, bool nNPCPing = false ); + int UDPBroadcast( PMessage* nMessage, PClient* nClient, uint16_t nMaxDist = 0, bool nSkipSource = false, bool nNPCPing = false ); + int SendUDPZoneWelcomeToClient( PClient* nClient ); +}; diff --git a/TinNS/Source/GameServer/ConfigTemplate.hxx b/TinNS/Source/GameServer/ConfigTemplate.hxx index 03aed73..99d327b 100644 --- a/TinNS/Source/GameServer/ConfigTemplate.hxx +++ b/TinNS/Source/GameServer/ConfigTemplate.hxx @@ -1,108 +1,108 @@ -#pragma once - -/* - TODO: put a single data_directory entry as the root directory for all NC data -*/ - -static const char *GameConfigTemplate[][2] = { - // {option_name, default_value} if default_value is empty string, it means option is mandatory - // List ends with empty string for option_name - {"info_sql_host", "127.0.0.1"}, - {"info_sql_port", "3306"}, - {"info_sql_username", ""}, - {"info_sql_password", ""}, - {"info_sql_database", "infoserver"}, - {"game_sql_host", "127.0.0.1"}, - {"game_sql_port", "3306"}, - {"gameserver_udpport_min", "5000"}, - {"gameserver_udpport_max", "5099"}, - {"game_sql_username", ""}, - {"game_sql_password", ""}, - {"game_sql_database", "gameserver"}, - {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive. - {"server_name", "TinNS"}, - {"server_ip", "127.0.0.1"}, //IP address used with clients reached without NAT (see localnet) - {"no_nat_net", "0"}, // 0 is for "don't bother with NAT", else format is like 192.168.1. (with trailing dot) - {"server_nat_ip", "127.0.0.1"}, //IP address used with clients reached through NAT - {"gameserver_port", "12000"}, - {"server_version", ""}, - {"maxclients", "128"}, - {"gm_slots", "10"}, - //{"defs_path", "./defs"}, - //{"worlds_path", "./worlds"}, - {"nc_data_path", "."}, - {"isc_method", "1"}, - {"isc_server_id", ""}, - {"isc_update_intervall", "60"}, - {"isc_delayed_update_intervall", "6"}, // the purpose of this option is to avoid multiple infoDB update when client just disconnects/reconnects during login phases - {"isc_infoserverip", "127.0.0.1"}, - {"isc_infoserverport", "9991"}, - {"isc_connect_pw", "change_me"}, // make default value empty when isc ready - {"dev_debug", "0"}, // set to non-zero to activate development outputs - {"auto_save_period", "300"}, - {"new_char_location", "1085"}, - {"broadcast_new", "0"}, - {"broadcast_new_hidestaff", "0"}, - {"max_cash", "20000000"}, - {"item_price", "70"}, - {"require_validation", "0"}, - {"minlevel", "0"}, - {"username_filter", "^[a-z][\\w\\-]{2,14}$"}, - {"password_filter", "^[[:graph:]]{3,15}$"}, - {"charname_filter", "^[a-z]+([\\-\\ ]?[a-z]+){0,2}$"}, - {"clanname_filter", "^[a-z][\\w\\-\\ ]{2,14}$"}, - -// For futur use: -// {"max_chars_per_account", "4"}, -// {"multiple_logins_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody -// {"multiple_ingames_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody (needs multiple logins ...) - -// {"local_chat_range", "500"}, - - {"", ""} // do not change this line (end mark) -}; - -static const char *CommandsTemplate[][2] = { - {"debug", "100"}, - {"settime", "100"}, - {"warp", "0"}, -// {"delworlditem", "100"}, -// {"addworlditem", "100"}, -// {"adddoor", "100"}, - {"online", "0"}, - {"sendchat", "50"}, - {"skin", "50"}, - {"effect", "0"}, - {"speed", "0"}, - {"color", "0"}, - {"brightness", "0"}, - {"remove", "50"}, - {"rehash", "100"}, - {"uptime", "0"}, - {"version", "0"}, - {"broadcast", "100"}, - {"kick", "50"}, - {"info", "50"}, - {"setlevel", "100"}, - {"warpto", "50"}, - {"recall", "50"}, - - {"ban", "50"}, // Set ban - {"unban", "50"}, // Remove ban - {"listbans", "50"}, // Show list of all banned accounts - {"shun", "50"}, // Quiet all chat - {"unshun", "50"}, // UnQuiet all chat - {"jail", "50"}, // "Jail" someone (Regants ^^) - {"unjail", "50"}, // Move him out - {"teleport", "50"}, // Warp targetplayer XX to zone YY - {"givemoney", "50"}, // Warp targetplayer XX to zone YY - {"takemoney", "50"}, // Warp targetplayer XX to zone YY - {"spawnactor", "50"}, // Spawn given actor next to player - - {"weather", "50"}, // Set weather in a zone - {"setmainskill", "50"}, // Set mainskill (INT,PSI,DEX,CON,STR) of own char or someone else - {"setsubskill", "50"}, // Set subskill (BRT,HCK,PPU,...) of own char or someone else - {"npc", "50"}, // do actions with NPCs - - {"", ""} // do not change this line (end mark) -}; +#pragma once + +/* + TODO: put a single data_directory entry as the root directory for all NC data +*/ + +static const char *GameConfigTemplate[][2] = { + // {option_name, default_value} if default_value is empty string, it means option is mandatory + // List ends with empty string for option_name + {"info_sql_host", "127.0.0.1"}, + {"info_sql_port", "3306"}, + {"info_sql_username", ""}, + {"info_sql_password", ""}, + {"info_sql_database", "infoserver"}, + {"game_sql_host", "127.0.0.1"}, + {"game_sql_port", "3306"}, + {"gameserver_udpport_min", "5000"}, + {"gameserver_udpport_max", "5099"}, + {"game_sql_username", ""}, + {"game_sql_password", ""}, + {"game_sql_database", "gameserver"}, + {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive. + {"server_name", "TinNS"}, + {"server_ip", "127.0.0.1"}, //IP address used with clients reached without NAT (see localnet) + {"no_nat_net", "0"}, // 0 is for "don't bother with NAT", else format is like 192.168.1. (with trailing dot) + {"server_nat_ip", "127.0.0.1"}, //IP address used with clients reached through NAT + {"gameserver_port", "12000"}, + {"server_version", ""}, + {"maxclients", "128"}, + {"gm_slots", "10"}, + //{"defs_path", "./defs"}, + //{"worlds_path", "./worlds"}, + {"nc_data_path", "."}, + {"isc_method", "1"}, + {"isc_server_id", ""}, + {"isc_update_intervall", "60"}, + {"isc_delayed_update_intervall", "6"}, // the purpose of this option is to avoid multiple infoDB update when client just disconnects/reconnects during login phases + {"isc_infoserverip", "127.0.0.1"}, + {"isc_infoserverport", "9991"}, + {"isc_connect_pw", "change_me"}, // make default value empty when isc ready + {"dev_debug", "0"}, // set to non-zero to activate development outputs + {"auto_save_period", "300"}, + {"new_char_location", "1085"}, + {"broadcast_new", "0"}, + {"broadcast_new_hidestaff", "0"}, + {"max_cash", "20000000"}, + {"item_price", "70"}, + {"require_validation", "0"}, + {"minlevel", "0"}, + {"username_filter", "^[a-z][\\w\\-]{2,14}$"}, + {"password_filter", "^[[:graph:]]{3,15}$"}, + {"charname_filter", "^[a-z]+([\\-\\ ]?[a-z]+){0,2}$"}, + {"clanname_filter", "^[a-z][\\w\\-\\ ]{2,14}$"}, + +// For futur use: +// {"max_chars_per_account", "4"}, +// {"multiple_logins_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody +// {"multiple_ingames_per_account", "0"}, // 0=nobody, 1=gm+ only, 2=everybody (needs multiple logins ...) + +// {"local_chat_range", "500"}, + + {"", ""} // do not change this line (end mark) +}; + +static const char *CommandsTemplate[][2] = { + {"debug", "100"}, + {"settime", "100"}, + {"warp", "0"}, +// {"delworlditem", "100"}, +// {"addworlditem", "100"}, +// {"adddoor", "100"}, + {"online", "0"}, + {"sendchat", "50"}, + {"skin", "50"}, + {"effect", "0"}, + {"speed", "0"}, + {"color", "0"}, + {"brightness", "0"}, + {"remove", "50"}, + {"rehash", "100"}, + {"uptime", "0"}, + {"version", "0"}, + {"broadcast", "100"}, + {"kick", "50"}, + {"info", "50"}, + {"setlevel", "100"}, + {"warpto", "50"}, + {"recall", "50"}, + + {"ban", "50"}, // Set ban + {"unban", "50"}, // Remove ban + {"listbans", "50"}, // Show list of all banned accounts + {"shun", "50"}, // Quiet all chat + {"unshun", "50"}, // UnQuiet all chat + {"jail", "50"}, // "Jail" someone (Regants ^^) + {"unjail", "50"}, // Move him out + {"teleport", "50"}, // Warp targetplayer XX to zone YY + {"givemoney", "50"}, // Warp targetplayer XX to zone YY + {"takemoney", "50"}, // Warp targetplayer XX to zone YY + {"spawnactor", "50"}, // Spawn given actor next to player + + {"weather", "50"}, // Set weather in a zone + {"setmainskill", "50"}, // Set mainskill (INT,PSI,DEX,CON,STR) of own char or someone else + {"setsubskill", "50"}, // Set subskill (BRT,HCK,PPU,...) of own char or someone else + {"npc", "50"}, // do actions with NPCs + + {"", ""} // do not change this line (end mark) +}; diff --git a/TinNS/Source/GameServer/Container.cxx b/TinNS/Source/GameServer/Container.cxx index 64b1991..43fbe1d 100644 --- a/TinNS/Source/GameServer/Container.cxx +++ b/TinNS/Source/GameServer/Container.cxx @@ -1,880 +1,880 @@ -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -/* --- PContainerEntry class --- */ - -PContainerEntry::PContainerEntry( PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID, bool SetDirty ) -{ - mItem = nItem; - mPosX = X; - mPosY = Y; - mInvID = nInvID; - mDirtyFlag = SetDirty; -} - -PContainerEntry::PContainerEntry( MYSQL_ROW row ) -{ - mItem = NULL; - mInvID = atoi( row[i_invid] ); - mPosX = atoi( row[i_x] ); - mPosY = atoi( row[i_y] ); - mDirtyFlag = false; - - uint32_t nItemID = atoi( row[i_itemid] ); - uint8_t nStackSize = atoi( row[i_qty] ); - // = std::atoi(row[i_type]); - uint8_t CurDur = atoi( row[i_curdur] ); - uint8_t Dmg = atoi( row[i_dmg] ); - uint8_t Freq = atoi( row[i_freq] ); - uint8_t Hand = atoi( row[i_hand] ); - uint8_t Rng = atoi( row[i_rng] ); - uint8_t Dur = atoi( row[i_maxdur] ); - - mItem = new PItem( nItemID, nStackSize, CurDur, Dur, Dmg, Freq, Hand, Rng ); -} - -PContainerEntry::~PContainerEntry() -{ - delete mItem; -} - -bool PContainerEntry::SQLSave( uint32_t CharID, uint32_t InvLoc ) -{ - std::string query, queryv; - - queryv += Ssprintf( " inv_charid='%u',inv_loc='%u',inv_x='%u',inv_y='%u'", CharID, InvLoc, mPosX, mPosY ); - queryv += Ssprintf( ",inv_itemid='%u',inv_qty='%u'", mItem->mItemID, mItem->mStackSize ); - //queryv += Ssprintf( ",inv_type='%u'", 0 ); - queryv += Ssprintf( ",inv_cdur='%u'", mItem->mCurDuration ); - queryv += Ssprintf( ",inv_dmg='%u'", mItem->mDamages ); - queryv += Ssprintf( ",inv_frq='%u'", mItem->mFrequency ); - queryv += Ssprintf( ",inv_hnd='%u'", mItem->mHandling ); - queryv += Ssprintf( ",inv_rng='%u'", mItem->mRange ); - queryv += Ssprintf( ",inv_mdur='%u'", mItem->mMaxDuration ); - - if ( mInvID ) - { - query = "UPDATE inventory SET " + queryv; - query += Ssprintf( " WHERE inv_id='%u' LIMIT 1;", mInvID ); - } - else - { - query = "INSERT INTO inventory SET " + queryv + ";"; - } - - if ( MySQL->GameQuery( query.c_str() ) ) - { - Console->Print( RED, BLACK, "PContainerEntry::SQLSave could not add/update some inventory item in the database" ); - Console->Print( "Query was:" ); - Console->Print( "%s", query.c_str() ); - MySQL->ShowGameSQLError(); - return false; - } - else - { - if ( !mInvID ) - { - mInvID = MySQL->GetLastGameInsertId(); - if ( gDevDebug ) - Console->Print( GREEN, BLACK, "New item %d added to inventory DB", mInvID ); - } -//Console->Print(YELLOW, BLACK, "PContainerEntry::SQLSave - Query was:"); -//Console->Print(YELLOW, BLACK, "%s", query.c_str()); - mDirtyFlag = false; - return true; - } -} - -bool PContainerEntry::SQLDelete() -{ - std::string query; - - if ( mInvID ) - { - query = Ssprintf( "DELETE FROM inventory WHERE inv_id='%u' LIMIT 1;", mInvID ); - - if ( MySQL->GameQuery( query.c_str() ) ) - { - Console->Print( RED, BLACK, "PContainerEntry::SQLDelete could not delete some container item from the database" ); - Console->Print( "Query was:" ); - Console->Print( "%s", query.c_str() ); - MySQL->ShowGameSQLError(); - return false; - } - else - { - if ( gDevDebug ) - Console->Print( GREEN, BLACK, "Item %d deleted from container DB", mInvID ); - mInvID = 0; - delete mItem; - mItem = NULL; - - mDirtyFlag = false; - return true; - } - } - else - { - Console->Print( YELLOW, BLACK, "PContainerEntry::SQLDelete: Item was not in inventory DB" ); - return true; - } -} - -/* --- PContainer class --- */ - -PContainer::PContainer( uint8_t nMaxSlots ) -{ - mMaxSlots = ( nMaxSlots > CONTAINER_MAX_SIZE ? CONTAINER_MAX_SIZE : nMaxSlots ) ; - if ( mMaxSlots ) - mContContent = new std::vector< PContainerEntry* >( mMaxSlots, NULL ); - else - mContContent = new std::vector< PContainerEntry* >; - mCharID = 0; - mInvLoc = 0; - mExclusiveUseCharID = 0; - mDirtyFlag = false; -} - -PContainer::~PContainer() -{ - for ( uint8_t i = 0; i < mContContent->size(); ++i ) - delete mContContent->at( i ); - - if ( mExclusiveUseCharID ) - Console->Print( RED, BLACK, "[ERROR] PContainer::~PContainer: Char %d still has exclusive access to container !!! Bad Pointer error will happen.", mExclusiveUseCharID ); -} - -bool PContainer::AddEntry( PContainerEntry* NewEntry, uint8_t nSlotId ) -{ - if ( IsSlotAllowed( nSlotId ) ) - { - for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed - mContContent->push_back( static_cast(NULL) ); - if ( mContContent->at( nSlotId ) ) - { - Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry already %d in use !!!", nSlotId ); - return false; - } - mContContent->at( nSlotId ) = NewEntry; - mDirtyFlag = true; - this->SetEntryPosXY( NewEntry, nSlotId, NewEntry->mPosX, NewEntry->mPosY ); - return true; - } - else - { - Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots ); - return false; - } - /* --- degug only --- - Console->Print(GREEN, BLACK, "PContainer::AddEntry: added item %d at pos (%d,%d)", NewEntry->mItem->GetItemID(), NewEntry->mPosX, NewEntry->mPosY); - - Dump(); - --- --- */ -} - -void PContainer::SetEntryPosXY( PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX, uint8_t nPosY ) -{ - nPosX = nPosY; - nEntry->Set2DPos( nSlotId, 0 ); - mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag; -} - -PContainerEntry* PContainer::RemoveEntry( uint8_t nSlotId ) -{ - PContainerEntry* tEntry = NULL; - - if ( nSlotId < mContContent->size() ) - { - tEntry = mContContent->at( nSlotId ); - mContContent->at( nSlotId ) = NULL; - } - return tEntry; -} - -bool PContainer::GetFreeSlot( uint8_t* nSlotId ) -{ - return IsSlotFree( *nSlotId ); -} - -void PContainer::Compact( uint8_t startSlotId ) -{ - uint8_t i, j; - PContainerEntry* tEntry; - - for ( i = j = startSlotId; i < mContContent->size(); ++i ) - { - if ( mContContent->at( i ) ) - { - if ( j < i ) - { - mContContent->at( j ) = tEntry = mContContent->at( i ); - this->SetEntryPosXY( tEntry, j, tEntry->mPosX, tEntry->mPosX ); - mContContent->at( i ) = NULL; - mDirtyFlag = true; - } - ++j; - } - } - - if ( !mMaxSlots ) // reduce size only if not fixed-size - { - for ( ; j < i; ++j ) - mContContent->pop_back(); - } -} - -bool PContainer::StartUse( uint32_t nExclusiveUseCharID ) -{ - if ( mExclusiveUseCharID ) - return false; - else - { - mExclusiveUseCharID = nExclusiveUseCharID; - return true; - } -} - -bool PContainer::EndUse( uint32_t nExclusiveUseCharID ) -{ - if ( nExclusiveUseCharID == mExclusiveUseCharID ) - { - mExclusiveUseCharID = 0; - return true; - } - else - { - Console->Print( RED, BLACK, "[Warning] PContainer::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID ); - return false; - } -} - -bool PContainer::SQLLoad() -{ - if ( !mCharID ) - { - return false; - } - - MYSQL_RES *result; - MYSQL_ROW row; - char query[1024]; - PContainerEntry* NewEntry; - bool SaveDirtyFlag; - uint8_t nSlotId; - //uint8_t nPosX, nPosY, nSizeX, nSizeY; - - /*if (!mContContent.empty()) - { - Console->Print(RED, BLACK, "PContainer::SQLLoad: We don't want to load inventory on non-empty inventory for char %d", mCharID); - return false; - }*/ - - snprintf( query, 1024, "SELECT * FROM inventory WHERE inv_charid='%d' AND inv_loc='%d' ORDER BY inv_x ASC", mCharID, mInvLoc ); - result = MySQL->GameResQuery( query ); - if ( result == NULL ) - { - Console->Print( RED, BLACK, "[Warning] PContainer::SQLLoad could not load inventory from the database" ); - Console->Print( "Query was:" ); - Console->Print( "%s", query ); - MySQL->ShowGameSQLError(); - return false; - } - while (( row = mysql_fetch_row( result ) ) ) - { - NewEntry = new PContainerEntry( row ); - if ( NewEntry->mItem->GetItemID() ) - { - nSlotId = NewEntry->mPosX; - SaveDirtyFlag = mDirtyFlag; - - if ( ! this->GetFreeSlot( &nSlotId ) || ! this->AddEntry( NewEntry, nSlotId ) ) - { - Console->Print( YELLOW, BLACK, "[Warning] PContainer::SQLLoad: Can't add item %d in slot %d of char %d inventory", NewEntry->mItem->GetItemID(), nSlotId, mCharID ); - delete NewEntry; - mDirtyFlag = SaveDirtyFlag; - } - else - { - mDirtyFlag = SaveDirtyFlag || ( nSlotId != NewEntry->mPosX ); - } - } - else - { - Console->Print( YELLOW, BLACK, "[Notice] Invalid item in DB (inv_id = %d) - Ignored", NewEntry->mInvID ); - delete NewEntry; - } - } - MySQL->FreeGameSQLResult( result ); - return true; -} - -bool PContainer::SQLSave() -{ - if ( !mCharID ) - return false; - - PContainerEntry* ContEntry; - bool SavedOK = true; - - for ( uint8_t i = 0; i < mContContent->size(); ++i ) - { - if (( ContEntry = mContContent->at( i ) ) ) - { - if (( ContEntry->mDirtyFlag ) ) - { - SavedOK = SavedOK && ContEntry->SQLSave( mCharID, mInvLoc ); - } - } - } - - if ( SavedOK ) - { - mDirtyFlag = false; - } - return SavedOK; -} - -bool PContainer::IsSlotFree( uint8_t nSlotId ) -{ - if ( !IsSlotAllowed( nSlotId ) ) - return false; - - if ( nSlotId >= mContContent->size() ) - return true; - else - return !( mContContent->at( nSlotId ) ); -} - -bool PContainer::AddItem( PItem* NewItem, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty ) -{ - /* --- auto stacking not implemented yet - 1 - if stackable, check if same item(S) exists - 2 - - if exist - 3 - - - add to stack - 4 - - - if no new stack remains, update LastPutXY & return true - 5 - find an empty space - 6 - - x - put in new space, update LastPutXY & return true - - */ - - if ( NewItem->GetItemID() == 0 ) - { - Console->Print( RED, BLACK, "[Warning] PContainer::AddItem: invalid item : ID 0" ); - return false; - } - - PContainerEntry* NewEntry = new PContainerEntry( NewItem, nPosX, nPosY, nInvID, SetDirty ); - - if ( this->GetFreeSlot( &nPosX ) && this->AddEntry( NewEntry, nPosX ) ) // !!!! nPosX not good - return true; - else - { - delete NewEntry; - return false; - } -} - -bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId, uint8_t nPosX, uint8_t nPosY ) -{ - if ( dstContainer == this ) - return this->MoveItem( srcSlotId, nCount, dstSlotId ); - else if ( dstContainer->GetFreeSlot( &dstSlotId ) ) - { - uint8_t savePosX, savePosY; - PContainerEntry* tEntry = this->GetEntry( srcSlotId ); - if ( tEntry ) - { - tEntry->Get2DPos( &savePosX, &savePosY ); - tEntry->Set2DPos( nPosX, nPosY ); - if ( !dstContainer->AddEntry( tEntry, dstSlotId ) ) - { - tEntry->Set2DPos( savePosX, savePosY ); - Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Couldn't add entry !" ); - return false; - } - tEntry->Get2DPos( &nPosX, &nPosY ); - tEntry->Set2DPos( savePosX, savePosY ); - RemoveEntry( srcSlotId ); - tEntry->Set2DPos( nPosX, nPosY ); - - if ( dstContainer->mCharID != this->mCharID ) // save at once if owner changes - { - if ( !tEntry->SQLSave( dstContainer->mCharID, dstContainer->mInvLoc ) ) // TODO: improve to manage non-persistent containers - { - Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Moved entry not saved" ); - } - //else - //{ - // Console->Print(GREEN, BLACK, "[Succes] PContainer::MoveItem - Moved entry saved"); - //} - } - return true; - } - else - { - Console->Print( RED, BLACK, "[Warning] trying to move invalid entry %d", srcSlotId ); - return false; - } - } - return false; -} - -// !!! Not partial move yet !!! -bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId ) -{ - if ( !( IsSlotAllowed( srcSlotId ) && IsSlotAllowed( dstSlotId ) ) ) - return false; - - if ( srcSlotId == dstSlotId ) - return true; - - if (( mContContent->at( srcSlotId ) ) - && ( mContContent->at( srcSlotId )->mItem->GetStackSize() >= nCount ) - && IsSlotFree( dstSlotId ) ) - { - PContainerEntry* tEntry = mContContent->at( dstSlotId ) = mContContent->at( srcSlotId ); - tEntry->mPosX = dstSlotId; - tEntry->mPosY = 0; - tEntry->mDirtyFlag = true; - mContContent->at( srcSlotId ) = NULL; - mDirtyFlag = true; - return true; - } - else - return false; -} - -std::vector< PContainerEntry* >* PContainer::GetEntries() -{ - std::vector< PContainerEntry* >* Entries = new std::vector< PContainerEntry* >; - - for ( uint8_t i = 0; i < mContContent->size(); ++i ) - { - if ( mContContent->at( i ) ) - Entries->push_back( mContContent->at( i ) ); - } - - return Entries; -} - -PContainerEntry* PContainer::GetEntry( uint8_t nSlotId ) -{ - if ( nSlotId >= mContContent->size() ) - return NULL; - - return mContContent->at( nSlotId ); -} - -PItem* PContainer::GetItem( uint8_t nSlotId ) -{ - PContainerEntry* tEntry = this->GetEntry( nSlotId ); - return ( tEntry ? tEntry->mItem : NULL ); -} - -uint8_t PContainer::RandomFill( uint8_t nItemCount, int nItemContainerDefIndex ) -{ - PItem* nItem = NULL; - const PDefItems* nItemDef; - uint32_t nItemSeqId; - uint8_t CreatedCount = 0; - - if ( !nItemCount ) - nItemCount = mMaxSlots; - if ( !nItemCount ) - nItemCount = CONTAINER_MAX_SIZE; - - if ( nItemContainerDefIndex >= 0 ) - { - int newItemIdx, newItemIndex; - uint8_t newItemQuality; - - const PDefItemContainer* containerDef = GameDefs->ItemContainers()->GetDef( nItemContainerDefIndex ); - if ( containerDef ) - { - for ( uint8_t i = 0; i < nItemCount; ++i ) - { - newItemIdx = containerDef->GetRandomItemIdx(); - if ( newItemIdx >= 0 ) - { - newItemIndex = containerDef->GetItemId( newItemIdx ); - newItemQuality = ( uint8_t )( 255 & int( 255.0 * containerDef->GetQuality( newItemIdx ) ) ); - if ( newItemIndex <= 0 ) // Item group - { - newItemIndex = GameDefs->Items()->GetRandomItemIdFromGroup( -newItemIndex ); - } - nItem = new PItem( newItemIndex, 1, 255, newItemQuality, newItemQuality, newItemQuality, newItemQuality, 255 ); - if ( nItem->GetItemID() ) - { - if ( this->AddItem( nItem ) ) - { - ++CreatedCount; - } - else - { - Console->Print( YELLOW, BLACK, "[Warning] Couldn't add item %d at pos %d", nItem->GetItemID(), i ); - delete nItem; - } - } - } - } - } - else - Console->Print( YELLOW, BLACK, "[Warning] Container def not found: %d", nItemContainerDefIndex ); - } - else - { - int NumItemsDefs = GameDefs->Items()->GetNumDefs(); - - for ( uint8_t i = 0; i < nItemCount; ++i ) - { - nItemSeqId = GetRandom( NumItemsDefs, 1 ); - - if (( nItemDef = GameDefs->Items()->GetDefBySeqIndex( nItemSeqId ) ) ) - { - nItem = new PItem( nItemDef->GetIndex(), 1, 255, 255, 255, 255, 255, 255 ); - if ( nItem->GetItemID() ) - { - if ( this->AddItem( nItem ) ) - { - ++CreatedCount; - } - else - { - //Console->Print(GREEN, BLACK, "Couldn't add item % d at pos % d", nItem->GetItemID(), i); - delete nItem; - } - } - } - else - Console->Print( RED, BLACK, "[Warning] PContainer::RandomFill Couldn't find item for SEQ %d", nItemSeqId ); - } - } - return CreatedCount; -} - -void PContainer::Dump() -{ - PContainerEntry* tmpEntry; - PItem* tmpItem; - uint8_t i; - //uint8_t y, x; - - for ( i = 0; i < mContContent->size(); ++i ) - { - if (( tmpEntry = mContContent->at( i ) ) ) - { - tmpItem = tmpEntry->mItem; - Console->Print( GREEN, BLACK, "%d: (%d,%d) (%d x %d) Item %d (InvID %d) %s %s", i, tmpEntry->mPosX, tmpEntry->mPosY, tmpItem->GetSizeX(), tmpItem->GetSizeY(), tmpItem->GetItemID(), tmpEntry->mInvID, tmpItem->GetName().c_str(), tmpEntry->mDirtyFlag ? "[*]" : "" ); - } - } - - if ( mDirtyFlag ) - Console->Print( GREEN, BLACK, "Dirty" ); - Console->Print( GREEN, BLACK, "------------------------------------" ); -} - -/* --- PContainerWithHoles class --- */ - - -/* --- PContainerAutoCompact --- */ -PContainerEntry* PContainerAutoCompact::RemoveEntry( uint8_t nSlotId ) -{ - PContainerEntry* tEntry = NULL; - - if ( nSlotId < mContContent->size() ) - { - tEntry = mContContent->at( nSlotId ); - mContContent->at( nSlotId ) = NULL; - if ( nSlotId == ( mContContent->size() - 1 ) ) - mContContent->pop_back(); - else - Compact( nSlotId ); - } - return tEntry; -} - -bool PContainerAutoCompact::GetFreeSlot( uint8_t* nSlotId ) // not optimal. A "first free from end" would be better at PContainer level -{ - bool Found = false; - - for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId ) - if ( ! mContContent->at( *nSlotId ) ) - { - Found = true; - break; - } - return ( Found || IsSlotAllowed( *nSlotId ) ); -} - -bool PContainerAutoCompact::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId ) -{ - srcSlotId = nCount = dstSlotId; - return false; -} - -/* --- PContainer2D class --- */ - -void PContainer2D::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY ) -{ - //nSlotId = nSlotId; - if (( nPosX >= INV_BACKPACK_COLS ) || ( nPosY == 255 ) ) - { - nPosX = nPosY = 0; - } - nEntry->Set2DPos( nPosX, nPosY ); - mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag; -} - -/* --- PContainer2DWorkaround --- */ -///// -PContainer2DWorkaround::PContainer2DWorkaround( uint8_t nMaxSlots ) : PContainerWithHoles( nMaxSlots ) -{ - mNextFreeSlot = 0; - mMaxCols = 254; - mMaxRows = 254; - mRows = 0; - AddRow(); -} - -PContainer2DWorkaround::~PContainer2DWorkaround() -{ - for ( int i = 0; i < mRows; i++ ) - delete mContSpace[i]; -} - -bool PContainer2DWorkaround::AddEntry( PContainerEntry* tEntry, uint8_t nSlotId ) -{ - if ( IsSlotAllowed( nSlotId ) ) - { - if ( FindValid2DPos( tEntry ) ) - { - for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed - mContContent->push_back( static_cast(NULL) ); - if ( mContContent->at( nSlotId ) ) - { - Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry already %d in use !!!", nSlotId ); - return false; - } - mContContent->at( nSlotId ) = tEntry; - mDirtyFlag = true; - //this->SetEntryPosXY(tEntry, nSlotId, tEntry->mPosX, tEntry->mPosY); - mDirtyFlag = mDirtyFlag || tEntry->mDirtyFlag; - SetUsed( tEntry ); - return true; - } - else - { - Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: No 2D space left !!!", nSlotId, mMaxSlots ); - return false; - } - } - else - { - Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots ); - return false; - } - -} - -PContainerEntry* PContainer2DWorkaround::RemoveEntry( uint8_t nSlotId ) -{ - PContainerEntry* tEntry = NULL; - - if ( nSlotId < mContContent->size() ) - { - tEntry = mContContent->at( nSlotId ); - mContContent->at( nSlotId ) = NULL; - //Console->Print(YELLOW, BLACK, "Cleaning (%d,%d) (%d x %d)", tEntry->mPosX, tEntry->mPosY, tEntry->mItem->GetSizeX(), tEntry->mItem->GetSizeY()); - SetUsed( tEntry, false ); - } - return tEntry; -} - -bool PContainer2DWorkaround::GetFreeSlot( uint8_t* nSlotId ) -{ - if ( IsSlotAllowed( mNextFreeSlot ) ) - { - *nSlotId = mNextFreeSlot++; - return true; - } - else - return false; -} - -void PContainer2DWorkaround::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY ) -{ - //nSlotId = nSlotId; - if (( nPosX == 255 ) && ( nPosY == 255 ) ) - { - nEntry->Set2DPos( 255, 255 ); - } - else - { - if (( nPosX >= mMaxCols ) || ( nPosY >= mMaxRows ) ) - { - nPosX = nPosY = 0; - } - nEntry->Set2DPos( nPosX, nPosY ); - - if ( !FindValid2DPos( nEntry ) ) - { - nEntry->Set2DPos( 255, 255 ); - Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::SetEntryPosXY - Space position already used" ); - } - } - mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag; -} - -bool PContainer2DWorkaround::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId ) -{ - srcSlotId = nCount = dstSlotId; - return false; -} - -void PContainer2DWorkaround::AddRow() -{ - if ( mRows + 1 < mMaxRows ) - { - std::vector* NewRow = new std::vector( mMaxCols, 0 ); - mContSpace.push_back( NewRow ); - ++mRows; - } -} - -bool PContainer2DWorkaround::Is2DFree( uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY ) -{ - if (( PosX == 255 ) && ( PosY == 255 ) ) - { - return true; - } - if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) ) - return false; - - uint8_t h, v; - for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) // what is over existing rows is free - { - for ( h = 0; h < SizeX; h++ ) - { - if ( PosX + h >= mMaxCols ) // what is over max col is not free - return false; - - if (( *mContSpace[PosY+v] )[PosX+h] ) - return false; - } - } - return ( PosY + SizeY <= mMaxRows ); -} - -void PContainer2DWorkaround::SetUsed( PContainerEntry* nEntry, bool Value ) -{ - uint8_t PosX = nEntry->mPosX;; - uint8_t PosY = nEntry->mPosY; - uint8_t SizeX = nEntry->mItem->GetSizeX(); - uint8_t SizeY = nEntry->mItem->GetSizeY(); - - if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) ) - return; - - while ( PosY + SizeY > mRows ) // add new rows when needed - AddRow(); - - uint8_t h, v; - for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) - { - for ( h = 0; ( h < SizeX ) && ( PosX + h < mMaxCols ); h++ ) - ( *mContSpace[PosY+v] )[PosX+h] = Value; - } -} - -bool PContainer2DWorkaround::FindValid2DPos( PContainerEntry* nEntry ) -{ - bool Found = false; - uint8_t SizeX = nEntry->mItem->GetSizeX(); - uint8_t SizeY = nEntry->mItem->GetSizeY(); - uint8_t dPosX, dPosY; - - if ( Is2DFree( nEntry->mPosX, nEntry->mPosY, SizeX, SizeY ) ) - Found = true; - else - { - dPosX = nEntry->mPosX; - dPosY = nEntry->mPosY; - if ( !Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) ) - { - dPosX = dPosY = 0; - //Console->Print(YELLOW, BLACK, "Init pos RESET"); - } - - while ( !Found && Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) ) - { - //Console->Print(YELLOW, BLACK, "Searching line %d", dPosY); - for ( ; dPosX <= ( mMaxCols - SizeX ); ++dPosX ) - { - if (( Found = Is2DFree( dPosX, dPosY, SizeX, SizeY ) ) ) - break; - } - if ( Found ) - { - nEntry->mPosX = dPosX; - nEntry->mPosY = dPosY; - nEntry->mDirtyFlag = true; - //Console->Print(YELLOW, BLACK, "Success: Found new space position : (%d,%d)", dPosX, dPosY); - break; - } - ++dPosY; - dPosX = 0; - } - } - return Found; -} - -void PContainer2DWorkaround::Dump() -{ - PContainer::Dump(); - - std::string tmpS; - uint8_t y, x; - for ( y = 0 ; y < mRows; y++ ) - { - tmpS = ""; - for ( x = 0 ; x < mMaxCols; x++ ) - { - tmpS += (( *mContSpace[y] )[x] ) ? "X" : "."; - } - Console->Print( "%s", tmpS.c_str() ); - } - Console->Print( GREEN, BLACK, "------------------------------------" ); -} - -/* --- PContainerAutoFindFree --- */ -bool PContainerAutoFindFree::GetFreeSlot( uint8_t* nSlotId ) -{ - bool Found = false; - - for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId ) - if ( ! mContContent->at( *nSlotId ) ) - { - Found = true; - break; - } - - return ( Found || IsSlotAllowed( *nSlotId ) ); -} - -/* --- PContainerAutoCompactOnClose --- */ -bool PContainerAutoCompactOnClose::EndUse( uint32_t nExclusiveUseCharID ) -{ - if ( nExclusiveUseCharID == mExclusiveUseCharID ) - { - mExclusiveUseCharID = 0; - Compact(); - return true; - } - else - { - Console->Print( RED, BLACK, "[ERROR] PContainerAutoCompactOnClose::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID ); - return false; - } -} +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +/* --- PContainerEntry class --- */ + +PContainerEntry::PContainerEntry( PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID, bool SetDirty ) +{ + mItem = nItem; + mPosX = X; + mPosY = Y; + mInvID = nInvID; + mDirtyFlag = SetDirty; +} + +PContainerEntry::PContainerEntry( MYSQL_ROW row ) +{ + mItem = NULL; + mInvID = atoi( row[i_invid] ); + mPosX = atoi( row[i_x] ); + mPosY = atoi( row[i_y] ); + mDirtyFlag = false; + + uint32_t nItemID = atoi( row[i_itemid] ); + uint8_t nStackSize = atoi( row[i_qty] ); + // = std::atoi(row[i_type]); + uint8_t CurDur = atoi( row[i_curdur] ); + uint8_t Dmg = atoi( row[i_dmg] ); + uint8_t Freq = atoi( row[i_freq] ); + uint8_t Hand = atoi( row[i_hand] ); + uint8_t Rng = atoi( row[i_rng] ); + uint8_t Dur = atoi( row[i_maxdur] ); + + mItem = new PItem( nItemID, nStackSize, CurDur, Dur, Dmg, Freq, Hand, Rng ); +} + +PContainerEntry::~PContainerEntry() +{ + delete mItem; +} + +bool PContainerEntry::SQLSave( uint32_t CharID, uint32_t InvLoc ) +{ + std::string query, queryv; + + queryv += Ssprintf( " inv_charid='%u',inv_loc='%u',inv_x='%u',inv_y='%u'", CharID, InvLoc, mPosX, mPosY ); + queryv += Ssprintf( ",inv_itemid='%u',inv_qty='%u'", mItem->mItemID, mItem->mStackSize ); + //queryv += Ssprintf( ",inv_type='%u'", 0 ); + queryv += Ssprintf( ",inv_cdur='%u'", mItem->mCurDuration ); + queryv += Ssprintf( ",inv_dmg='%u'", mItem->mDamages ); + queryv += Ssprintf( ",inv_frq='%u'", mItem->mFrequency ); + queryv += Ssprintf( ",inv_hnd='%u'", mItem->mHandling ); + queryv += Ssprintf( ",inv_rng='%u'", mItem->mRange ); + queryv += Ssprintf( ",inv_mdur='%u'", mItem->mMaxDuration ); + + if ( mInvID ) + { + query = "UPDATE inventory SET " + queryv; + query += Ssprintf( " WHERE inv_id='%u' LIMIT 1;", mInvID ); + } + else + { + query = "INSERT INTO inventory SET " + queryv + ";"; + } + + if ( MySQL->GameQuery( query.c_str() ) ) + { + Console->Print( RED, BLACK, "PContainerEntry::SQLSave could not add/update some inventory item in the database" ); + Console->Print( "Query was:" ); + Console->Print( "%s", query.c_str() ); + MySQL->ShowGameSQLError(); + return false; + } + else + { + if ( !mInvID ) + { + mInvID = MySQL->GetLastGameInsertId(); + if ( gDevDebug ) + Console->Print( GREEN, BLACK, "New item %d added to inventory DB", mInvID ); + } +//Console->Print(YELLOW, BLACK, "PContainerEntry::SQLSave - Query was:"); +//Console->Print(YELLOW, BLACK, "%s", query.c_str()); + mDirtyFlag = false; + return true; + } +} + +bool PContainerEntry::SQLDelete() +{ + std::string query; + + if ( mInvID ) + { + query = Ssprintf( "DELETE FROM inventory WHERE inv_id='%u' LIMIT 1;", mInvID ); + + if ( MySQL->GameQuery( query.c_str() ) ) + { + Console->Print( RED, BLACK, "PContainerEntry::SQLDelete could not delete some container item from the database" ); + Console->Print( "Query was:" ); + Console->Print( "%s", query.c_str() ); + MySQL->ShowGameSQLError(); + return false; + } + else + { + if ( gDevDebug ) + Console->Print( GREEN, BLACK, "Item %d deleted from container DB", mInvID ); + mInvID = 0; + delete mItem; + mItem = NULL; + + mDirtyFlag = false; + return true; + } + } + else + { + Console->Print( YELLOW, BLACK, "PContainerEntry::SQLDelete: Item was not in inventory DB" ); + return true; + } +} + +/* --- PContainer class --- */ + +PContainer::PContainer( uint8_t nMaxSlots ) +{ + mMaxSlots = ( nMaxSlots > CONTAINER_MAX_SIZE ? CONTAINER_MAX_SIZE : nMaxSlots ) ; + if ( mMaxSlots ) + mContContent = new std::vector< PContainerEntry* >( mMaxSlots, NULL ); + else + mContContent = new std::vector< PContainerEntry* >; + mCharID = 0; + mInvLoc = 0; + mExclusiveUseCharID = 0; + mDirtyFlag = false; +} + +PContainer::~PContainer() +{ + for ( uint8_t i = 0; i < mContContent->size(); ++i ) + delete mContContent->at( i ); + + if ( mExclusiveUseCharID ) + Console->Print( RED, BLACK, "[ERROR] PContainer::~PContainer: Char %d still has exclusive access to container !!! Bad Pointer error will happen.", mExclusiveUseCharID ); +} + +bool PContainer::AddEntry( PContainerEntry* NewEntry, uint8_t nSlotId ) +{ + if ( IsSlotAllowed( nSlotId ) ) + { + for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed + mContContent->push_back( static_cast(NULL) ); + if ( mContContent->at( nSlotId ) ) + { + Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry already %d in use !!!", nSlotId ); + return false; + } + mContContent->at( nSlotId ) = NewEntry; + mDirtyFlag = true; + this->SetEntryPosXY( NewEntry, nSlotId, NewEntry->mPosX, NewEntry->mPosY ); + return true; + } + else + { + Console->Print( RED, BLACK, "[Warning] PContainer::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots ); + return false; + } + /* --- degug only --- + Console->Print(GREEN, BLACK, "PContainer::AddEntry: added item %d at pos (%d,%d)", NewEntry->mItem->GetItemID(), NewEntry->mPosX, NewEntry->mPosY); + + Dump(); + --- --- */ +} + +void PContainer::SetEntryPosXY( PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX, uint8_t nPosY ) +{ + nPosX = nPosY; + nEntry->Set2DPos( nSlotId, 0 ); + mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag; +} + +PContainerEntry* PContainer::RemoveEntry( uint8_t nSlotId ) +{ + PContainerEntry* tEntry = NULL; + + if ( nSlotId < mContContent->size() ) + { + tEntry = mContContent->at( nSlotId ); + mContContent->at( nSlotId ) = NULL; + } + return tEntry; +} + +bool PContainer::GetFreeSlot( uint8_t* nSlotId ) +{ + return IsSlotFree( *nSlotId ); +} + +void PContainer::Compact( uint8_t startSlotId ) +{ + uint8_t i, j; + PContainerEntry* tEntry; + + for ( i = j = startSlotId; i < mContContent->size(); ++i ) + { + if ( mContContent->at( i ) ) + { + if ( j < i ) + { + mContContent->at( j ) = tEntry = mContContent->at( i ); + this->SetEntryPosXY( tEntry, j, tEntry->mPosX, tEntry->mPosX ); + mContContent->at( i ) = NULL; + mDirtyFlag = true; + } + ++j; + } + } + + if ( !mMaxSlots ) // reduce size only if not fixed-size + { + for ( ; j < i; ++j ) + mContContent->pop_back(); + } +} + +bool PContainer::StartUse( uint32_t nExclusiveUseCharID ) +{ + if ( mExclusiveUseCharID ) + return false; + else + { + mExclusiveUseCharID = nExclusiveUseCharID; + return true; + } +} + +bool PContainer::EndUse( uint32_t nExclusiveUseCharID ) +{ + if ( nExclusiveUseCharID == mExclusiveUseCharID ) + { + mExclusiveUseCharID = 0; + return true; + } + else + { + Console->Print( RED, BLACK, "[Warning] PContainer::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID ); + return false; + } +} + +bool PContainer::SQLLoad() +{ + if ( !mCharID ) + { + return false; + } + + MYSQL_RES *result; + MYSQL_ROW row; + char query[1024]; + PContainerEntry* NewEntry; + bool SaveDirtyFlag; + uint8_t nSlotId; + //uint8_t nPosX, nPosY, nSizeX, nSizeY; + + /*if (!mContContent.empty()) + { + Console->Print(RED, BLACK, "PContainer::SQLLoad: We don't want to load inventory on non-empty inventory for char %d", mCharID); + return false; + }*/ + + snprintf( query, 1024, "SELECT * FROM inventory WHERE inv_charid='%d' AND inv_loc='%d' ORDER BY inv_x ASC", mCharID, mInvLoc ); + result = MySQL->GameResQuery( query ); + if ( result == NULL ) + { + Console->Print( RED, BLACK, "[Warning] PContainer::SQLLoad could not load inventory from the database" ); + Console->Print( "Query was:" ); + Console->Print( "%s", query ); + MySQL->ShowGameSQLError(); + return false; + } + while (( row = mysql_fetch_row( result ) ) ) + { + NewEntry = new PContainerEntry( row ); + if ( NewEntry->mItem->GetItemID() ) + { + nSlotId = NewEntry->mPosX; + SaveDirtyFlag = mDirtyFlag; + + if ( ! this->GetFreeSlot( &nSlotId ) || ! this->AddEntry( NewEntry, nSlotId ) ) + { + Console->Print( YELLOW, BLACK, "[Warning] PContainer::SQLLoad: Can't add item %d in slot %d of char %d inventory", NewEntry->mItem->GetItemID(), nSlotId, mCharID ); + delete NewEntry; + mDirtyFlag = SaveDirtyFlag; + } + else + { + mDirtyFlag = SaveDirtyFlag || ( nSlotId != NewEntry->mPosX ); + } + } + else + { + Console->Print( YELLOW, BLACK, "[Notice] Invalid item in DB (inv_id = %d) - Ignored", NewEntry->mInvID ); + delete NewEntry; + } + } + MySQL->FreeGameSQLResult( result ); + return true; +} + +bool PContainer::SQLSave() +{ + if ( !mCharID ) + return false; + + PContainerEntry* ContEntry; + bool SavedOK = true; + + for ( uint8_t i = 0; i < mContContent->size(); ++i ) + { + if (( ContEntry = mContContent->at( i ) ) ) + { + if (( ContEntry->mDirtyFlag ) ) + { + SavedOK = SavedOK && ContEntry->SQLSave( mCharID, mInvLoc ); + } + } + } + + if ( SavedOK ) + { + mDirtyFlag = false; + } + return SavedOK; +} + +bool PContainer::IsSlotFree( uint8_t nSlotId ) +{ + if ( !IsSlotAllowed( nSlotId ) ) + return false; + + if ( nSlotId >= mContContent->size() ) + return true; + else + return !( mContContent->at( nSlotId ) ); +} + +bool PContainer::AddItem( PItem* NewItem, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty ) +{ + /* --- auto stacking not implemented yet + 1 - if stackable, check if same item(S) exists + 2 - - if exist + 3 - - - add to stack + 4 - - - if no new stack remains, update LastPutXY & return true + 5 - find an empty space + 6 - + x - put in new space, update LastPutXY & return true + + */ + + if ( NewItem->GetItemID() == 0 ) + { + Console->Print( RED, BLACK, "[Warning] PContainer::AddItem: invalid item : ID 0" ); + return false; + } + + PContainerEntry* NewEntry = new PContainerEntry( NewItem, nPosX, nPosY, nInvID, SetDirty ); + + if ( this->GetFreeSlot( &nPosX ) && this->AddEntry( NewEntry, nPosX ) ) // !!!! nPosX not good + return true; + else + { + delete NewEntry; + return false; + } +} + +bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId, uint8_t nPosX, uint8_t nPosY ) +{ + if ( dstContainer == this ) + return this->MoveItem( srcSlotId, nCount, dstSlotId ); + else if ( dstContainer->GetFreeSlot( &dstSlotId ) ) + { + uint8_t savePosX, savePosY; + PContainerEntry* tEntry = this->GetEntry( srcSlotId ); + if ( tEntry ) + { + tEntry->Get2DPos( &savePosX, &savePosY ); + tEntry->Set2DPos( nPosX, nPosY ); + if ( !dstContainer->AddEntry( tEntry, dstSlotId ) ) + { + tEntry->Set2DPos( savePosX, savePosY ); + Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Couldn't add entry !" ); + return false; + } + tEntry->Get2DPos( &nPosX, &nPosY ); + tEntry->Set2DPos( savePosX, savePosY ); + RemoveEntry( srcSlotId ); + tEntry->Set2DPos( nPosX, nPosY ); + + if ( dstContainer->mCharID != this->mCharID ) // save at once if owner changes + { + if ( !tEntry->SQLSave( dstContainer->mCharID, dstContainer->mInvLoc ) ) // TODO: improve to manage non-persistent containers + { + Console->Print( RED, BLACK, "[Warning] PContainer::MoveItem - Moved entry not saved" ); + } + //else + //{ + // Console->Print(GREEN, BLACK, "[Succes] PContainer::MoveItem - Moved entry saved"); + //} + } + return true; + } + else + { + Console->Print( RED, BLACK, "[Warning] trying to move invalid entry %d", srcSlotId ); + return false; + } + } + return false; +} + +// !!! Not partial move yet !!! +bool PContainer::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId ) +{ + if ( !( IsSlotAllowed( srcSlotId ) && IsSlotAllowed( dstSlotId ) ) ) + return false; + + if ( srcSlotId == dstSlotId ) + return true; + + if (( mContContent->at( srcSlotId ) ) + && ( mContContent->at( srcSlotId )->mItem->GetStackSize() >= nCount ) + && IsSlotFree( dstSlotId ) ) + { + PContainerEntry* tEntry = mContContent->at( dstSlotId ) = mContContent->at( srcSlotId ); + tEntry->mPosX = dstSlotId; + tEntry->mPosY = 0; + tEntry->mDirtyFlag = true; + mContContent->at( srcSlotId ) = NULL; + mDirtyFlag = true; + return true; + } + else + return false; +} + +std::vector< PContainerEntry* >* PContainer::GetEntries() +{ + std::vector< PContainerEntry* >* Entries = new std::vector< PContainerEntry* >; + + for ( uint8_t i = 0; i < mContContent->size(); ++i ) + { + if ( mContContent->at( i ) ) + Entries->push_back( mContContent->at( i ) ); + } + + return Entries; +} + +PContainerEntry* PContainer::GetEntry( uint8_t nSlotId ) +{ + if ( nSlotId >= mContContent->size() ) + return NULL; + + return mContContent->at( nSlotId ); +} + +PItem* PContainer::GetItem( uint8_t nSlotId ) +{ + PContainerEntry* tEntry = this->GetEntry( nSlotId ); + return ( tEntry ? tEntry->mItem : NULL ); +} + +uint8_t PContainer::RandomFill( uint8_t nItemCount, int nItemContainerDefIndex ) +{ + PItem* nItem = NULL; + const PDefItems* nItemDef; + uint32_t nItemSeqId; + uint8_t CreatedCount = 0; + + if ( !nItemCount ) + nItemCount = mMaxSlots; + if ( !nItemCount ) + nItemCount = CONTAINER_MAX_SIZE; + + if ( nItemContainerDefIndex >= 0 ) + { + int newItemIdx, newItemIndex; + uint8_t newItemQuality; + + const PDefItemContainer* containerDef = GameDefs->ItemContainers()->GetDef( nItemContainerDefIndex ); + if ( containerDef ) + { + for ( uint8_t i = 0; i < nItemCount; ++i ) + { + newItemIdx = containerDef->GetRandomItemIdx(); + if ( newItemIdx >= 0 ) + { + newItemIndex = containerDef->GetItemId( newItemIdx ); + newItemQuality = ( uint8_t )( 255 & int( 255.0 * containerDef->GetQuality( newItemIdx ) ) ); + if ( newItemIndex <= 0 ) // Item group + { + newItemIndex = GameDefs->Items()->GetRandomItemIdFromGroup( -newItemIndex ); + } + nItem = new PItem( newItemIndex, 1, 255, newItemQuality, newItemQuality, newItemQuality, newItemQuality, 255 ); + if ( nItem->GetItemID() ) + { + if ( this->AddItem( nItem ) ) + { + ++CreatedCount; + } + else + { + Console->Print( YELLOW, BLACK, "[Warning] Couldn't add item %d at pos %d", nItem->GetItemID(), i ); + delete nItem; + } + } + } + } + } + else + Console->Print( YELLOW, BLACK, "[Warning] Container def not found: %d", nItemContainerDefIndex ); + } + else + { + int NumItemsDefs = GameDefs->Items()->GetNumDefs(); + + for ( uint8_t i = 0; i < nItemCount; ++i ) + { + nItemSeqId = GetRandom( NumItemsDefs, 1 ); + + if (( nItemDef = GameDefs->Items()->GetDefBySeqIndex( nItemSeqId ) ) ) + { + nItem = new PItem( nItemDef->GetIndex(), 1, 255, 255, 255, 255, 255, 255 ); + if ( nItem->GetItemID() ) + { + if ( this->AddItem( nItem ) ) + { + ++CreatedCount; + } + else + { + //Console->Print(GREEN, BLACK, "Couldn't add item % d at pos % d", nItem->GetItemID(), i); + delete nItem; + } + } + } + else + Console->Print( RED, BLACK, "[Warning] PContainer::RandomFill Couldn't find item for SEQ %d", nItemSeqId ); + } + } + return CreatedCount; +} + +void PContainer::Dump() +{ + PContainerEntry* tmpEntry; + PItem* tmpItem; + uint8_t i; + //uint8_t y, x; + + for ( i = 0; i < mContContent->size(); ++i ) + { + if (( tmpEntry = mContContent->at( i ) ) ) + { + tmpItem = tmpEntry->mItem; + Console->Print( GREEN, BLACK, "%d: (%d,%d) (%d x %d) Item %d (InvID %d) %s %s", i, tmpEntry->mPosX, tmpEntry->mPosY, tmpItem->GetSizeX(), tmpItem->GetSizeY(), tmpItem->GetItemID(), tmpEntry->mInvID, tmpItem->GetName().c_str(), tmpEntry->mDirtyFlag ? "[*]" : "" ); + } + } + + if ( mDirtyFlag ) + Console->Print( GREEN, BLACK, "Dirty" ); + Console->Print( GREEN, BLACK, "------------------------------------" ); +} + +/* --- PContainerWithHoles class --- */ + + +/* --- PContainerAutoCompact --- */ +PContainerEntry* PContainerAutoCompact::RemoveEntry( uint8_t nSlotId ) +{ + PContainerEntry* tEntry = NULL; + + if ( nSlotId < mContContent->size() ) + { + tEntry = mContContent->at( nSlotId ); + mContContent->at( nSlotId ) = NULL; + if ( nSlotId == ( mContContent->size() - 1 ) ) + mContContent->pop_back(); + else + Compact( nSlotId ); + } + return tEntry; +} + +bool PContainerAutoCompact::GetFreeSlot( uint8_t* nSlotId ) // not optimal. A "first free from end" would be better at PContainer level +{ + bool Found = false; + + for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId ) + if ( ! mContContent->at( *nSlotId ) ) + { + Found = true; + break; + } + return ( Found || IsSlotAllowed( *nSlotId ) ); +} + +bool PContainerAutoCompact::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId ) +{ + srcSlotId = nCount = dstSlotId; + return false; +} + +/* --- PContainer2D class --- */ + +void PContainer2D::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY ) +{ + //nSlotId = nSlotId; + if (( nPosX >= INV_BACKPACK_COLS ) || ( nPosY == 255 ) ) + { + nPosX = nPosY = 0; + } + nEntry->Set2DPos( nPosX, nPosY ); + mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag; +} + +/* --- PContainer2DWorkaround --- */ +///// +PContainer2DWorkaround::PContainer2DWorkaround( uint8_t nMaxSlots ) : PContainerWithHoles( nMaxSlots ) +{ + mNextFreeSlot = 0; + mMaxCols = 254; + mMaxRows = 254; + mRows = 0; + AddRow(); +} + +PContainer2DWorkaround::~PContainer2DWorkaround() +{ + for ( int i = 0; i < mRows; i++ ) + delete mContSpace[i]; +} + +bool PContainer2DWorkaround::AddEntry( PContainerEntry* tEntry, uint8_t nSlotId ) +{ + if ( IsSlotAllowed( nSlotId ) ) + { + if ( FindValid2DPos( tEntry ) ) + { + for ( uint8_t i = mContContent->size(); i <= nSlotId; ++i ) // Extend as needed + mContContent->push_back( static_cast(NULL) ); + if ( mContContent->at( nSlotId ) ) + { + Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry already %d in use !!!", nSlotId ); + return false; + } + mContContent->at( nSlotId ) = tEntry; + mDirtyFlag = true; + //this->SetEntryPosXY(tEntry, nSlotId, tEntry->mPosX, tEntry->mPosY); + mDirtyFlag = mDirtyFlag || tEntry->mDirtyFlag; + SetUsed( tEntry ); + return true; + } + else + { + Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: No 2D space left !!!", nSlotId, mMaxSlots ); + return false; + } + } + else + { + Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::AddEntry: Target entry %d not allowed (max = %d) !!!", nSlotId, mMaxSlots ); + return false; + } + +} + +PContainerEntry* PContainer2DWorkaround::RemoveEntry( uint8_t nSlotId ) +{ + PContainerEntry* tEntry = NULL; + + if ( nSlotId < mContContent->size() ) + { + tEntry = mContContent->at( nSlotId ); + mContContent->at( nSlotId ) = NULL; + //Console->Print(YELLOW, BLACK, "Cleaning (%d,%d) (%d x %d)", tEntry->mPosX, tEntry->mPosY, tEntry->mItem->GetSizeX(), tEntry->mItem->GetSizeY()); + SetUsed( tEntry, false ); + } + return tEntry; +} + +bool PContainer2DWorkaround::GetFreeSlot( uint8_t* nSlotId ) +{ + if ( IsSlotAllowed( mNextFreeSlot ) ) + { + *nSlotId = mNextFreeSlot++; + return true; + } + else + return false; +} + +void PContainer2DWorkaround::SetEntryPosXY( PContainerEntry* nEntry, uint8_t /*nSlotId*/, uint8_t nPosX, uint8_t nPosY ) +{ + //nSlotId = nSlotId; + if (( nPosX == 255 ) && ( nPosY == 255 ) ) + { + nEntry->Set2DPos( 255, 255 ); + } + else + { + if (( nPosX >= mMaxCols ) || ( nPosY >= mMaxRows ) ) + { + nPosX = nPosY = 0; + } + nEntry->Set2DPos( nPosX, nPosY ); + + if ( !FindValid2DPos( nEntry ) ) + { + nEntry->Set2DPos( 255, 255 ); + Console->Print( RED, BLACK, "[Warning] PContainer2DWorkaround::SetEntryPosXY - Space position already used" ); + } + } + mDirtyFlag = mDirtyFlag || nEntry->mDirtyFlag; +} + +bool PContainer2DWorkaround::MoveItem( uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId ) +{ + srcSlotId = nCount = dstSlotId; + return false; +} + +void PContainer2DWorkaround::AddRow() +{ + if ( mRows + 1 < mMaxRows ) + { + std::vector* NewRow = new std::vector( mMaxCols, 0 ); + mContSpace.push_back( NewRow ); + ++mRows; + } +} + +bool PContainer2DWorkaround::Is2DFree( uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY ) +{ + if (( PosX == 255 ) && ( PosY == 255 ) ) + { + return true; + } + if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) ) + return false; + + uint8_t h, v; + for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) // what is over existing rows is free + { + for ( h = 0; h < SizeX; h++ ) + { + if ( PosX + h >= mMaxCols ) // what is over max col is not free + return false; + + if (( *mContSpace[PosY+v] )[PosX+h] ) + return false; + } + } + return ( PosY + SizeY <= mMaxRows ); +} + +void PContainer2DWorkaround::SetUsed( PContainerEntry* nEntry, bool Value ) +{ + uint8_t PosX = nEntry->mPosX;; + uint8_t PosY = nEntry->mPosY; + uint8_t SizeX = nEntry->mItem->GetSizeX(); + uint8_t SizeY = nEntry->mItem->GetSizeY(); + + if ( !Is2DPosAllowed( PosX, PosY, SizeX, SizeY ) ) + return; + + while ( PosY + SizeY > mRows ) // add new rows when needed + AddRow(); + + uint8_t h, v; + for ( v = 0; ( v < SizeY ) && ( PosY + v < mRows ) ; v++ ) + { + for ( h = 0; ( h < SizeX ) && ( PosX + h < mMaxCols ); h++ ) + ( *mContSpace[PosY+v] )[PosX+h] = Value; + } +} + +bool PContainer2DWorkaround::FindValid2DPos( PContainerEntry* nEntry ) +{ + bool Found = false; + uint8_t SizeX = nEntry->mItem->GetSizeX(); + uint8_t SizeY = nEntry->mItem->GetSizeY(); + uint8_t dPosX, dPosY; + + if ( Is2DFree( nEntry->mPosX, nEntry->mPosY, SizeX, SizeY ) ) + Found = true; + else + { + dPosX = nEntry->mPosX; + dPosY = nEntry->mPosY; + if ( !Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) ) + { + dPosX = dPosY = 0; + //Console->Print(YELLOW, BLACK, "Init pos RESET"); + } + + while ( !Found && Is2DPosAllowed( dPosX, dPosY, SizeX, SizeY ) ) + { + //Console->Print(YELLOW, BLACK, "Searching line %d", dPosY); + for ( ; dPosX <= ( mMaxCols - SizeX ); ++dPosX ) + { + if (( Found = Is2DFree( dPosX, dPosY, SizeX, SizeY ) ) ) + break; + } + if ( Found ) + { + nEntry->mPosX = dPosX; + nEntry->mPosY = dPosY; + nEntry->mDirtyFlag = true; + //Console->Print(YELLOW, BLACK, "Success: Found new space position : (%d,%d)", dPosX, dPosY); + break; + } + ++dPosY; + dPosX = 0; + } + } + return Found; +} + +void PContainer2DWorkaround::Dump() +{ + PContainer::Dump(); + + std::string tmpS; + uint8_t y, x; + for ( y = 0 ; y < mRows; y++ ) + { + tmpS = ""; + for ( x = 0 ; x < mMaxCols; x++ ) + { + tmpS += (( *mContSpace[y] )[x] ) ? "X" : "."; + } + Console->Print( "%s", tmpS.c_str() ); + } + Console->Print( GREEN, BLACK, "------------------------------------" ); +} + +/* --- PContainerAutoFindFree --- */ +bool PContainerAutoFindFree::GetFreeSlot( uint8_t* nSlotId ) +{ + bool Found = false; + + for ( *nSlotId = 0; *nSlotId < mContContent->size(); ++*nSlotId ) + if ( ! mContContent->at( *nSlotId ) ) + { + Found = true; + break; + } + + return ( Found || IsSlotAllowed( *nSlotId ) ); +} + +/* --- PContainerAutoCompactOnClose --- */ +bool PContainerAutoCompactOnClose::EndUse( uint32_t nExclusiveUseCharID ) +{ + if ( nExclusiveUseCharID == mExclusiveUseCharID ) + { + mExclusiveUseCharID = 0; + Compact(); + return true; + } + else + { + Console->Print( RED, BLACK, "[ERROR] PContainerAutoCompactOnClose::EndUse called with CharID %d when CharID %d had exclusive use", nExclusiveUseCharID, mExclusiveUseCharID ); + return false; + } +} diff --git a/TinNS/Source/GameServer/Container.hxx b/TinNS/Source/GameServer/Container.hxx index 58bc238..9d86174 100644 --- a/TinNS/Source/GameServer/Container.hxx +++ b/TinNS/Source/GameServer/Container.hxx @@ -1,194 +1,194 @@ -#pragma once - -#include -#include -#ifdef MYSQL_INC_DIR -#include -#else -#include -#endif - -#define CONTAINER_MAX_SIZE 254 - -class PItem; - -class PContainerEntry { - friend class PContainer; - friend class PContainer2D; - friend class PMsgBuilder; - friend class PContainer2DWorkaround; - -private: - enum { - i_invid = 0, - i_charid, - i_invloc, - i_x, - i_y, - i_itemid, - //i_type, - i_flag, - i_qty, - i_sqty, - i_curdur, - i_dmg, - i_freq, - i_hand, - i_rng, - i_maxdur, - i_slots, - i_slt1, - i_slt2, - i_slt3, - i_slt4, - i_slt5, - i_atype, - i_conatin - }; - - PItem* mItem; - uint8_t mPosX; - uint8_t mPosY; - uint32_t mInvID; - bool mDirtyFlag; - - PContainerEntry(PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID = 0, bool SetDirty = true); - PContainerEntry(MYSQL_ROW row); - - bool SQLSave(uint32_t CharID, uint32_t InvLoc); - bool SQLDelete(); - - inline void Set2DPos(uint8_t nPosX, uint8_t nPosY) { mDirtyFlag = mDirtyFlag || (mPosX != nPosX) || (mPosY != nPosY) ; mPosX = nPosX; mPosY = nPosY; } - -public: - ~PContainerEntry(); - - inline void Get2DPos(uint8_t* oPosX, uint8_t* oPosY) { *oPosX = mPosX; *oPosY = mPosY; } -}; - - - -class PContainer // Holes allowed, no autofind free slots -{ - protected: - uint8_t mMaxSlots; - std::vector< PContainerEntry* >* mContContent; - uint32_t mCharID; - uint32_t mInvLoc; - uint32_t mExclusiveUseCharID; - bool mDirtyFlag; - - inline bool IsSlotAllowed(uint8_t nSlotId) { return ((nSlotId < CONTAINER_MAX_SIZE) && (!mMaxSlots || (nSlotId < mMaxSlots))); } - virtual bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0); - virtual PContainerEntry* RemoveEntry(uint8_t nSlotId); - virtual bool GetFreeSlot(uint8_t* nSlotId); - void Compact(uint8_t startSlotId = 0); - - public: - PContainer(uint8_t nMaxSlots = 0); - virtual ~PContainer(); - - inline void SetInfo(uint32_t CharID, uint32_t InvLoc) { mCharID = CharID; mInvLoc = InvLoc; } - inline uint32_t GetOwnerId() { return mCharID; } - inline bool IsDirty() { return mDirtyFlag; } - inline void SetDirty() { mDirtyFlag = true; } - bool StartUse(uint32_t nExclusiveUseCharID = 0); - virtual bool EndUse(uint32_t nExclusiveUseCharID = 0); - bool SQLLoad(); - bool SQLSave(); - bool IsSlotFree(uint8_t nSlotId); - virtual bool AddItem(PItem* NewItem, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true); - virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId); - bool MoveItem(uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId = 0, uint8_t nPosX = 0, uint8_t nPosY = 0); - virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0); - - virtual uint8_t RandomFill(uint8_t nItemCount = 0, int nItemContainerDefIndex = -1); - PContainerEntry* GetEntry(uint8_t nSlotId); - std::vector< PContainerEntry* >* GetEntries(); - PItem* GetItem(uint8_t nSlotId); - virtual void Dump(); -}; - - -class PContainerWithHoles : public PContainer // Holes allowed, no autofind free slots -{ - public: - PContainerWithHoles(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {} - virtual ~PContainerWithHoles() {} -}; - - -class PContainerAutoCompact : public PContainer // No holes allowed, automatic add to end slot (no control on insertion slot) -{ -protected: - virtual PContainerEntry* RemoveEntry(uint8_t nSlotId); - virtual bool GetFreeSlot(uint8_t* nSlotId); - -public: - PContainerAutoCompact(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {} - virtual ~PContainerAutoCompact() {} - virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId); -}; - - -class PContainer2D : public PContainerAutoCompact // + slotId not used, non-significant XY used (no XY check yet) -{ - public: - PContainer2D(uint8_t nMaxSlots = 0) : PContainerAutoCompact(nMaxSlots) {} - virtual ~PContainer2D() {} - - virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0); -}; - -class PContainer2DWorkaround : public PContainerWithHoles // Holes allowed, autofind free slot (always increasing id) -{ -private: - uint8_t mNextFreeSlot; - std::vector< std::vector* > mContSpace; - uint8_t mMaxCols; - uint8_t mMaxRows; - uint8_t mRows; - - void AddRow(); - inline bool Is2DPosAllowed(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY) - { - return ((PosX < mMaxCols-SizeX+1) && (PosY < mMaxRows-SizeY+1)); - } - bool Is2DFree(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY); - bool FindValid2DPos(PContainerEntry* nEntry); - -protected: - bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0); - PContainerEntry* RemoveEntry(uint8_t nSlotId); - bool GetFreeSlot(uint8_t* nSlotId); - - public: - PContainer2DWorkaround(uint8_t nMaxSlots = 0); - ~PContainer2DWorkaround(); - - bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId); - - void Set2DPosMax(uint8_t MaxPosX, uint8_t MaxPosY = 254) { mMaxCols = MaxPosX; mMaxRows = MaxPosY; } - void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0); - void SetUsed(PContainerEntry* nEntry, bool Value = true); - void Dump(); -}; - -class PContainerAutoFindFree : public PContainerWithHoles // No holes kept after EndUse, automatic find first free slots (no control on insertion slot) -{ - protected: - virtual bool GetFreeSlot(uint8_t* nSlotId); - - public: - PContainerAutoFindFree(uint8_t nMaxSlots = 0) : PContainerWithHoles(nMaxSlots) {} - virtual ~PContainerAutoFindFree() {} -}; - -class PContainerAutoCompactOnClose : public PContainerAutoFindFree // No holes kept after EndUse, automatic find first free slots (no control on insertion slot) -{ - public: - PContainerAutoCompactOnClose(uint8_t nMaxSlots = 0) : PContainerAutoFindFree(nMaxSlots) {} - virtual ~PContainerAutoCompactOnClose() {} - - virtual bool EndUse(uint32_t nExclusiveUseCharID = 0); -}; +#pragma once + +#include +#include +#ifdef MYSQL_INC_DIR +#include +#else +#include +#endif + +#define CONTAINER_MAX_SIZE 254 + +class PItem; + +class PContainerEntry { + friend class PContainer; + friend class PContainer2D; + friend class PMsgBuilder; + friend class PContainer2DWorkaround; + +private: + enum { + i_invid = 0, + i_charid, + i_invloc, + i_x, + i_y, + i_itemid, + //i_type, + i_flag, + i_qty, + i_sqty, + i_curdur, + i_dmg, + i_freq, + i_hand, + i_rng, + i_maxdur, + i_slots, + i_slt1, + i_slt2, + i_slt3, + i_slt4, + i_slt5, + i_atype, + i_conatin + }; + + PItem* mItem; + uint8_t mPosX; + uint8_t mPosY; + uint32_t mInvID; + bool mDirtyFlag; + + PContainerEntry(PItem* nItem, uint8_t X, uint8_t Y, uint32_t nInvID = 0, bool SetDirty = true); + PContainerEntry(MYSQL_ROW row); + + bool SQLSave(uint32_t CharID, uint32_t InvLoc); + bool SQLDelete(); + + inline void Set2DPos(uint8_t nPosX, uint8_t nPosY) { mDirtyFlag = mDirtyFlag || (mPosX != nPosX) || (mPosY != nPosY) ; mPosX = nPosX; mPosY = nPosY; } + +public: + ~PContainerEntry(); + + inline void Get2DPos(uint8_t* oPosX, uint8_t* oPosY) { *oPosX = mPosX; *oPosY = mPosY; } +}; + + + +class PContainer // Holes allowed, no autofind free slots +{ + protected: + uint8_t mMaxSlots; + std::vector< PContainerEntry* >* mContContent; + uint32_t mCharID; + uint32_t mInvLoc; + uint32_t mExclusiveUseCharID; + bool mDirtyFlag; + + inline bool IsSlotAllowed(uint8_t nSlotId) { return ((nSlotId < CONTAINER_MAX_SIZE) && (!mMaxSlots || (nSlotId < mMaxSlots))); } + virtual bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0); + virtual PContainerEntry* RemoveEntry(uint8_t nSlotId); + virtual bool GetFreeSlot(uint8_t* nSlotId); + void Compact(uint8_t startSlotId = 0); + + public: + PContainer(uint8_t nMaxSlots = 0); + virtual ~PContainer(); + + inline void SetInfo(uint32_t CharID, uint32_t InvLoc) { mCharID = CharID; mInvLoc = InvLoc; } + inline uint32_t GetOwnerId() { return mCharID; } + inline bool IsDirty() { return mDirtyFlag; } + inline void SetDirty() { mDirtyFlag = true; } + bool StartUse(uint32_t nExclusiveUseCharID = 0); + virtual bool EndUse(uint32_t nExclusiveUseCharID = 0); + bool SQLLoad(); + bool SQLSave(); + bool IsSlotFree(uint8_t nSlotId); + virtual bool AddItem(PItem* NewItem, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true); + virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId); + bool MoveItem(uint8_t srcSlotId, uint8_t nCount, PContainer* dstContainer, uint8_t dstSlotId = 0, uint8_t nPosX = 0, uint8_t nPosY = 0); + virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0); + + virtual uint8_t RandomFill(uint8_t nItemCount = 0, int nItemContainerDefIndex = -1); + PContainerEntry* GetEntry(uint8_t nSlotId); + std::vector< PContainerEntry* >* GetEntries(); + PItem* GetItem(uint8_t nSlotId); + virtual void Dump(); +}; + + +class PContainerWithHoles : public PContainer // Holes allowed, no autofind free slots +{ + public: + PContainerWithHoles(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {} + virtual ~PContainerWithHoles() {} +}; + + +class PContainerAutoCompact : public PContainer // No holes allowed, automatic add to end slot (no control on insertion slot) +{ +protected: + virtual PContainerEntry* RemoveEntry(uint8_t nSlotId); + virtual bool GetFreeSlot(uint8_t* nSlotId); + +public: + PContainerAutoCompact(uint8_t nMaxSlots = 0) : PContainer(nMaxSlots) {} + virtual ~PContainerAutoCompact() {} + virtual bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId); +}; + + +class PContainer2D : public PContainerAutoCompact // + slotId not used, non-significant XY used (no XY check yet) +{ + public: + PContainer2D(uint8_t nMaxSlots = 0) : PContainerAutoCompact(nMaxSlots) {} + virtual ~PContainer2D() {} + + virtual void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0); +}; + +class PContainer2DWorkaround : public PContainerWithHoles // Holes allowed, autofind free slot (always increasing id) +{ +private: + uint8_t mNextFreeSlot; + std::vector< std::vector* > mContSpace; + uint8_t mMaxCols; + uint8_t mMaxRows; + uint8_t mRows; + + void AddRow(); + inline bool Is2DPosAllowed(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY) + { + return ((PosX < mMaxCols-SizeX+1) && (PosY < mMaxRows-SizeY+1)); + } + bool Is2DFree(uint8_t PosX, uint8_t PosY, uint8_t SizeX, uint8_t SizeY); + bool FindValid2DPos(PContainerEntry* nEntry); + +protected: + bool AddEntry(PContainerEntry* NewEntry, uint8_t nSlotId = 0); + PContainerEntry* RemoveEntry(uint8_t nSlotId); + bool GetFreeSlot(uint8_t* nSlotId); + + public: + PContainer2DWorkaround(uint8_t nMaxSlots = 0); + ~PContainer2DWorkaround(); + + bool MoveItem(uint8_t srcSlotId, uint8_t nCount, uint8_t dstSlotId); + + void Set2DPosMax(uint8_t MaxPosX, uint8_t MaxPosY = 254) { mMaxCols = MaxPosX; mMaxRows = MaxPosY; } + void SetEntryPosXY(PContainerEntry* nEntry, uint8_t nSlotId, uint8_t nPosX = 0, uint8_t nPosY = 0); + void SetUsed(PContainerEntry* nEntry, bool Value = true); + void Dump(); +}; + +class PContainerAutoFindFree : public PContainerWithHoles // No holes kept after EndUse, automatic find first free slots (no control on insertion slot) +{ + protected: + virtual bool GetFreeSlot(uint8_t* nSlotId); + + public: + PContainerAutoFindFree(uint8_t nMaxSlots = 0) : PContainerWithHoles(nMaxSlots) {} + virtual ~PContainerAutoFindFree() {} +}; + +class PContainerAutoCompactOnClose : public PContainerAutoFindFree // No holes kept after EndUse, automatic find first free slots (no control on insertion slot) +{ + public: + PContainerAutoCompactOnClose(uint8_t nMaxSlots = 0) : PContainerAutoFindFree(nMaxSlots) {} + virtual ~PContainerAutoCompactOnClose() {} + + virtual bool EndUse(uint32_t nExclusiveUseCharID = 0); +}; diff --git a/TinNS/Source/GameServer/Decoder/MessageDecoder.cxx b/TinNS/Source/GameServer/Decoder/MessageDecoder.cxx index fa36ad3..9a9adae 100644 --- a/TinNS/Source/GameServer/Decoder/MessageDecoder.cxx +++ b/TinNS/Source/GameServer/Decoder/MessageDecoder.cxx @@ -1,169 +1,169 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient) -{ - mDecodeData.mMessage = nMessage; - mDecodeData.mClient = nClient; - mDecodeData.mState = (nMessage && nClient) ? DECODE_MORE : DECODE_UNDEF; - mDecodeData.mUnknownType = 0; - mDecodeData.mHandling0x13Sub = false; - mDecodeData.Sub0x13Start = mDecodeData.Sub0x13StartNext = 0; - mPacketName.erase(); - mDecodeData.mName.str(mPacketName); - mDecodeData.mErrorDetail.erase(); - mDecodeData.mTraceKnownMsg = false; - mDecodeData.mTraceUnknownMsg = false; - mDecodeData.mTraceDump = false; - if (mCurrentAnalyser) - { - delete mCurrentAnalyser; - mCurrentAnalyser = nullptr; - } -} - -PUdpMsgDecoder::PUdpMsgDecoder() -{ - mCurrentAnalyser = nullptr; - Reset(); -} - -PUdpMsgDecoder::PUdpMsgDecoder(PMessage *nMessage, PClient *nClient) -{ - mCurrentAnalyser = nullptr; - Init(nMessage, nClient); -} - -PUdpMsgDecoder::~PUdpMsgDecoder() -{ - if (mCurrentAnalyser) - { - delete mCurrentAnalyser; - } -} - -bool PUdpMsgDecoder::Analyse() -{ - PUdpMsgAnalyser* nextAnalyser; - - if ((mDecodeData.mState & DECODE_MORE) || mDecodeData.mHandling0x13Sub) - { - if (mCurrentAnalyser) - { - delete mCurrentAnalyser; - mCurrentAnalyser = nullptr; - } - if (mDecodeData.mHandling0x13Sub) - { - mPacketName.erase(); - mDecodeData.mName.str(mPacketName); - mCurrentAnalyser = new PUdp0x13(&mDecodeData); - mDecodeData.mState = DECODE_MORE; - } - else - { - mCurrentAnalyser = new PUdpMsgAnalyser(&mDecodeData); - } - - while (mDecodeData.mState & DECODE_MORE) - { - nextAnalyser = mCurrentAnalyser->Analyse(); - if (mCurrentAnalyser != nextAnalyser) - { - delete mCurrentAnalyser; - mCurrentAnalyser = nextAnalyser; - } - } - } - return (!(mDecodeData.mState & (DECODE_MORE | DECODE_ERROR | DECODE_UNKNOWN))); -} - -bool PUdpMsgDecoder::Analyse(PMessage *nMessage, PClient *nClient) -{ - Init(nMessage, nClient); - return Analyse(); -} - -void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState) -{ - mDecodeData.mClientState = nClientState; - Init(nMessage, nClient); -} - -uint8_t PUdpMsgDecoder::GetState() -{ - return mDecodeData.mState; -} - -bool PUdpMsgDecoder::IsError() -{ - return (mDecodeData.mState & DECODE_ERROR); -} - -bool PUdpMsgDecoder::IsKnown() -{ - return (!(mDecodeData.mState & DECODE_UNKNOWN)); -} - -bool PUdpMsgDecoder::MoreSubMsg() -{ - return mDecodeData.mHandling0x13Sub; -} - -bool PUdpMsgDecoder::IsActionReady() -{ - return (mDecodeData.mState & DECODE_ACTION_READY); -} - -bool PUdpMsgDecoder::IsActionDone() -{ - return (mDecodeData.mState & DECODE_ACTION_DONE); -} - -bool PUdpMsgDecoder::IsTraceKnownMsg() -{ - return mDecodeData.mTraceKnownMsg; -} - -bool PUdpMsgDecoder::IsTraceUnknownMsg() -{ - return mDecodeData.mTraceUnknownMsg; -} - -bool PUdpMsgDecoder::IsTraceDump() -{ - return mDecodeData.mTraceDump; -} - -void PUdpMsgDecoder::DumpMsg() -{ - if (mDecodeData.mMessage) - mDecodeData.mMessage->Dump(); -} - -std::string const &PUdpMsgDecoder::GetName() -{ - return (mTmpName = mDecodeData.mName.str()); -} - -std::string const &PUdpMsgDecoder::GetError() -{ - return mDecodeData.mErrorDetail; -} - -bool PUdpMsgDecoder::DoAction() -{ - if (mDecodeData.mState & DECODE_ACTION_READY) - { - return mCurrentAnalyser->DoAction(); - } - else - { - return false; - } -} - -void PUdpMsgDecoder::Reset() -{ - Init(nullptr, nullptr); -} +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient) +{ + mDecodeData.mMessage = nMessage; + mDecodeData.mClient = nClient; + mDecodeData.mState = (nMessage && nClient) ? DECODE_MORE : DECODE_UNDEF; + mDecodeData.mUnknownType = 0; + mDecodeData.mHandling0x13Sub = false; + mDecodeData.Sub0x13Start = mDecodeData.Sub0x13StartNext = 0; + mPacketName.erase(); + mDecodeData.mName.str(mPacketName); + mDecodeData.mErrorDetail.erase(); + mDecodeData.mTraceKnownMsg = false; + mDecodeData.mTraceUnknownMsg = false; + mDecodeData.mTraceDump = false; + if (mCurrentAnalyser) + { + delete mCurrentAnalyser; + mCurrentAnalyser = nullptr; + } +} + +PUdpMsgDecoder::PUdpMsgDecoder() +{ + mCurrentAnalyser = nullptr; + Reset(); +} + +PUdpMsgDecoder::PUdpMsgDecoder(PMessage *nMessage, PClient *nClient) +{ + mCurrentAnalyser = nullptr; + Init(nMessage, nClient); +} + +PUdpMsgDecoder::~PUdpMsgDecoder() +{ + if (mCurrentAnalyser) + { + delete mCurrentAnalyser; + } +} + +bool PUdpMsgDecoder::Analyse() +{ + PUdpMsgAnalyser* nextAnalyser; + + if ((mDecodeData.mState & DECODE_MORE) || mDecodeData.mHandling0x13Sub) + { + if (mCurrentAnalyser) + { + delete mCurrentAnalyser; + mCurrentAnalyser = nullptr; + } + if (mDecodeData.mHandling0x13Sub) + { + mPacketName.erase(); + mDecodeData.mName.str(mPacketName); + mCurrentAnalyser = new PUdp0x13(&mDecodeData); + mDecodeData.mState = DECODE_MORE; + } + else + { + mCurrentAnalyser = new PUdpMsgAnalyser(&mDecodeData); + } + + while (mDecodeData.mState & DECODE_MORE) + { + nextAnalyser = mCurrentAnalyser->Analyse(); + if (mCurrentAnalyser != nextAnalyser) + { + delete mCurrentAnalyser; + mCurrentAnalyser = nextAnalyser; + } + } + } + return (!(mDecodeData.mState & (DECODE_MORE | DECODE_ERROR | DECODE_UNKNOWN))); +} + +bool PUdpMsgDecoder::Analyse(PMessage *nMessage, PClient *nClient) +{ + Init(nMessage, nClient); + return Analyse(); +} + +void PUdpMsgDecoder::Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState) +{ + mDecodeData.mClientState = nClientState; + Init(nMessage, nClient); +} + +uint8_t PUdpMsgDecoder::GetState() +{ + return mDecodeData.mState; +} + +bool PUdpMsgDecoder::IsError() +{ + return (mDecodeData.mState & DECODE_ERROR); +} + +bool PUdpMsgDecoder::IsKnown() +{ + return (!(mDecodeData.mState & DECODE_UNKNOWN)); +} + +bool PUdpMsgDecoder::MoreSubMsg() +{ + return mDecodeData.mHandling0x13Sub; +} + +bool PUdpMsgDecoder::IsActionReady() +{ + return (mDecodeData.mState & DECODE_ACTION_READY); +} + +bool PUdpMsgDecoder::IsActionDone() +{ + return (mDecodeData.mState & DECODE_ACTION_DONE); +} + +bool PUdpMsgDecoder::IsTraceKnownMsg() +{ + return mDecodeData.mTraceKnownMsg; +} + +bool PUdpMsgDecoder::IsTraceUnknownMsg() +{ + return mDecodeData.mTraceUnknownMsg; +} + +bool PUdpMsgDecoder::IsTraceDump() +{ + return mDecodeData.mTraceDump; +} + +void PUdpMsgDecoder::DumpMsg() +{ + if (mDecodeData.mMessage) + mDecodeData.mMessage->Dump(); +} + +std::string const &PUdpMsgDecoder::GetName() +{ + return (mTmpName = mDecodeData.mName.str()); +} + +std::string const &PUdpMsgDecoder::GetError() +{ + return mDecodeData.mErrorDetail; +} + +bool PUdpMsgDecoder::DoAction() +{ + if (mDecodeData.mState & DECODE_ACTION_READY) + { + return mCurrentAnalyser->DoAction(); + } + else + { + return false; + } +} + +void PUdpMsgDecoder::Reset() +{ + Init(nullptr, nullptr); +} diff --git a/TinNS/Source/GameServer/Decoder/MessageDecoder.hxx b/TinNS/Source/GameServer/Decoder/MessageDecoder.hxx index edf2a6b..efa5d76 100644 --- a/TinNS/Source/GameServer/Decoder/MessageDecoder.hxx +++ b/TinNS/Source/GameServer/Decoder/MessageDecoder.hxx @@ -1,73 +1,73 @@ -#pragma once - -#include -#include -#include - -struct PGameState; -class PClient; -class PMessage; -class PUdpMsgAnalyser; - -#define DECODE_UNDEF 0 -#define DECODE_ERROR 1 // one error occured on the current decoding step -#define DECODE_UNKNOWN 2 // the current decoded (sub)message is unkown -#define DECODE_MORE 4 // more decoding needed for the (sub)message -#define DECODE_FINISHED 8 // decoding if finished for the whole message -#define DECODE_ACTION_READY 16 // an action is ready to be done -#define DECODE_ACTION_DONE 32 // the action triggered hasn't to be triggered again -#define DECODE_ACTION_IGNORED 64 // the action wasn't performed for some (good) reason (to combine or not with DONE) -#define DECODE_ACTION_FAILED 128 // the action failed totally or partially (to combine or not with DONE) - -struct PMsgDecodeData { - PMessage *mMessage; - PClient *mClient; - uint8_t mState; - uint8_t mUnknownType; - bool mHandling0x13Sub; - uint16_t Sub0x13Start; - uint16_t Sub0x13StartNext; - std::stringstream mName; - std::string mErrorDetail; - bool mTraceKnownMsg; - bool mTraceUnknownMsg; - bool mTraceDump; - PGameState *mClientState; // Temporary until State is put back in Client object -}; - -// UDP Message decoder -// boolean methods return true if successful - -class PUdpMsgDecoder { -private: - PMsgDecodeData mDecodeData; - PUdpMsgAnalyser *mCurrentAnalyser; - std::string mPacketName; - std::string mTmpName; - - void Init(PMessage *nMessage, PClient *nClient); - -public: - PUdpMsgDecoder(); - PUdpMsgDecoder(PMessage *nMessage, PClient *nClient); - ~PUdpMsgDecoder(); - - bool Analyse(); - bool Analyse(PMessage *nMessage, PClient *nClient); // Can be used on non initialized or already used object - // Temporary form until State is put back in Client object - void Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState); - uint8_t GetState(); - bool IsError(); - bool IsKnown(); - bool MoreSubMsg(); - bool IsActionReady(); - bool IsActionDone(); - bool IsTraceKnownMsg(); - bool IsTraceUnknownMsg(); - bool IsTraceDump(); - void DumpMsg(); - std::string const &GetName(); - std::string const &GetError(); - bool DoAction(); - void Reset(); -}; +#pragma once + +#include +#include +#include + +struct PGameState; +class PClient; +class PMessage; +class PUdpMsgAnalyser; + +#define DECODE_UNDEF 0 +#define DECODE_ERROR 1 // one error occured on the current decoding step +#define DECODE_UNKNOWN 2 // the current decoded (sub)message is unkown +#define DECODE_MORE 4 // more decoding needed for the (sub)message +#define DECODE_FINISHED 8 // decoding if finished for the whole message +#define DECODE_ACTION_READY 16 // an action is ready to be done +#define DECODE_ACTION_DONE 32 // the action triggered hasn't to be triggered again +#define DECODE_ACTION_IGNORED 64 // the action wasn't performed for some (good) reason (to combine or not with DONE) +#define DECODE_ACTION_FAILED 128 // the action failed totally or partially (to combine or not with DONE) + +struct PMsgDecodeData { + PMessage *mMessage; + PClient *mClient; + uint8_t mState; + uint8_t mUnknownType; + bool mHandling0x13Sub; + uint16_t Sub0x13Start; + uint16_t Sub0x13StartNext; + std::stringstream mName; + std::string mErrorDetail; + bool mTraceKnownMsg; + bool mTraceUnknownMsg; + bool mTraceDump; + PGameState *mClientState; // Temporary until State is put back in Client object +}; + +// UDP Message decoder +// boolean methods return true if successful + +class PUdpMsgDecoder { +private: + PMsgDecodeData mDecodeData; + PUdpMsgAnalyser *mCurrentAnalyser; + std::string mPacketName; + std::string mTmpName; + + void Init(PMessage *nMessage, PClient *nClient); + +public: + PUdpMsgDecoder(); + PUdpMsgDecoder(PMessage *nMessage, PClient *nClient); + ~PUdpMsgDecoder(); + + bool Analyse(); + bool Analyse(PMessage *nMessage, PClient *nClient); // Can be used on non initialized or already used object + // Temporary form until State is put back in Client object + void Init(PMessage *nMessage, PClient *nClient, PGameState *nClientState); + uint8_t GetState(); + bool IsError(); + bool IsKnown(); + bool MoreSubMsg(); + bool IsActionReady(); + bool IsActionDone(); + bool IsTraceKnownMsg(); + bool IsTraceUnknownMsg(); + bool IsTraceDump(); + void DumpMsg(); + std::string const &GetName(); + std::string const &GetError(); + bool DoAction(); + void Reset(); +}; diff --git a/TinNS/Source/GameServer/Decoder/Udp0x08.cxx b/TinNS/Source/GameServer/Decoder/Udp0x08.cxx index ab5424a..e92ec1d 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x08.cxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x08.cxx @@ -1,24 +1,24 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" - -PUdp0x08::PUdp0x08(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - nDecodeData->mName << "/0x08"; -} - -PUdpMsgAnalyser* PUdp0x08::Analyse() -{ - mDecodeData->mName << "=Client crash"; - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - - return this; -} - -bool PUdp0x08::DoAction() -{ - // Client crashed, close connection from our side - GameServer->ClientDisconnected(mDecodeData->mClient); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - - return true; -} +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" + +PUdp0x08::PUdp0x08(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + nDecodeData->mName << "/0x08"; +} + +PUdpMsgAnalyser* PUdp0x08::Analyse() +{ + mDecodeData->mName << "=Client crash"; + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + + return this; +} + +bool PUdp0x08::DoAction() +{ + // Client crashed, close connection from our side + GameServer->ClientDisconnected(mDecodeData->mClient); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/Udp0x08.hxx b/TinNS/Source/GameServer/Decoder/Udp0x08.hxx index 81b9443..4d1c3f4 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x08.hxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x08.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdp0x08 : public PUdpMsgAnalyser { -public: - PUdp0x08(PMsgDecodeData *nDecodeData); - //~PUdp0x08(); - PUdpMsgAnalyser* Analyse(); - bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdp0x08 : public PUdpMsgAnalyser { +public: + PUdp0x08(PMsgDecodeData *nDecodeData); + //~PUdp0x08(); + PUdpMsgAnalyser* Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/Udp0x13.hxx b/TinNS/Source/GameServer/Decoder/Udp0x13.hxx index 7d93ffc..79c4768 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x13.hxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x13.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdp0x13 : public PUdpMsgAnalyser { -public: - PUdp0x13(PMsgDecodeData *nDecodeData); - //~PUdp0x13(); - PUdpMsgAnalyser* Analyse(); - //bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdp0x13 : public PUdpMsgAnalyser { +public: + PUdp0x13(PMsgDecodeData *nDecodeData); + //~PUdp0x13(); + PUdpMsgAnalyser* Analyse(); + //bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/Udp0x1f.cxx b/TinNS/Source/GameServer/Decoder/Udp0x1f.cxx index d51857c..d9e6fda 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x1f.cxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x1f.cxx @@ -1,259 +1,259 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdp0x1f ****/ - -PUdp0x1f::PUdp0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x1f"; -} - -PUdpMsgAnalyser* PUdp0x1f::Analyse() -{ - PUdpMsgAnalyser* nextAnalyser = NULL; - mDecodeData->mState = DECODE_MORE; - uint8_t MsgType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 7 ); - uint8_t MsgSubType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 ); - - switch ( MsgType ) - { - case 0x00: - { - nextAnalyser = new PUdpHeldItemBasicAction( mDecodeData ); - break; - } - case 0x01: - { - nextAnalyser = new PUdpHeldItemAimedAction( mDecodeData ); - break; - } - case 0x02: - { - nextAnalyser = new PUdpCharJump( mDecodeData ); - break; - } - case 0x17: - { - nextAnalyser = new PUdpUseObject( mDecodeData ); - break; - } - case 0x19: // NPC Dialog closed - { - nextAnalyser = new PUdpNPCDialogClose( mDecodeData ); - break; - } - case 0x1a: // NPC Dialog action/reply - { - nextAnalyser = new PUdpNPCDialogAction( mDecodeData ); - break; - } - case 0x1b: - { - nextAnalyser = new PUdpChatLocal( mDecodeData ); - break; - } - case 0x1e: // item move QB<>INV<>GND - { - nextAnalyser = new PUdpItemMove( mDecodeData ); - break; - } - case 0x1f: // Slot use - { - nextAnalyser = new PUdpItemSlotUse( mDecodeData ); - break; - } - case 0x20: // Use item for hacking, launcher, "launcher" spell - { - nextAnalyser = new PUdpHeldItemLaunchingAction( mDecodeData ); - break; - } - case 0x22: - { - nextAnalyser = new PUdpCharExitChair( mDecodeData ); - break; - } - case 0x25: - { - mDecodeData->mName << "/0x25"; - switch ( MsgSubType ) - { - case 0x04: // Hack announcement? - { - nextAnalyser = new PUdpSubskillInc( mDecodeData ); - break; - } - case 0x0c: // addons activation - { - nextAnalyser = new PUdpItemAddonActivation( mDecodeData ); - break; - } - case 0x14: // Hack announcement? - { - nextAnalyser = new PUdpItemMoveBP( mDecodeData ); - break; - } - case 0x16: // ???? confirm reload anim start ??? - { - mDecodeData->mUnknownType = MsgSubType; - mDecodeData->mTraceUnknownMsg = true; - break; - } - case 0x17: // Item drop on item - { - nextAnalyser = new PUdpItemDropOnItem( mDecodeData ); - break; - } - case 0x18: - { - mDecodeData->mName << "/0x18"; - switch ( mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 ) ) - { - case 0x01: // Use inventory item - { - nextAnalyser = new PUdpItemUse( mDecodeData ); - break; - } - case 0x0e: // Request manual reload - { - nextAnalyser = new PUdpItemManualReload( mDecodeData ); - break; - } - default: - { - mDecodeData->mUnknownType = MsgSubType; - mDecodeData->mTraceUnknownMsg = true; - break; - } - } - break; - } - - case 0x1d: // ? before Packet0: 0b 03 01 00 1f 00 00 25 1d 00 00 01 - case 0x1e: // ? before Packet0: 0d 03 02 00 1f 00 00 25 1e ff ff ff ff 00 - default: - { - mDecodeData->mUnknownType = MsgSubType; - mDecodeData->mTraceUnknownMsg = true; - break; - } - } - break; - } - case 0x27: - { - nextAnalyser = new PUdpCloseItemContainer( mDecodeData ); - break; - } - case 0x29: - { - nextAnalyser = new PUdpHackSuccess( mDecodeData ); - break; - } - case 0x2c: - { - nextAnalyser = new PUdpHackFail( mDecodeData ); - break; - } - case 0x2e: - { - nextAnalyser = new PUdpOutfitter( mDecodeData ); - break; - } - case 0x2f: - { - nextAnalyser = new PUdpDeathRespawn( mDecodeData ); - break; - } - case 0x33: - { - nextAnalyser = new PUdpChatListAdd( mDecodeData ); - break; - } - case 0x38: - { - nextAnalyser = new PUdpAppartmentAccess( mDecodeData ); - break; - } - case 0x39: - { - nextAnalyser = new PUdpChatListRemove( mDecodeData ); - break; - } - case 0x3b: - { - nextAnalyser = new PUdpChatGlobal( mDecodeData ); - break; - } - case 0x3d: - { - mDecodeData->mName << "/0x3d"; - switch ( MsgSubType ) // In fact MsgSubType is U32, but only lower byte is used - { - case 0x02: - { - nextAnalyser = new PUdpAddGenrepToList( mDecodeData ); - break; - } - case 0x03: - { - nextAnalyser = new PUdpAptGRZoning( mDecodeData ); - break; - } - case 0x04: - { - nextAnalyser = new PUdpGenrepZoning( mDecodeData ); - break; - } - case 0x09: - { - nextAnalyser = new PUdpPopupResponse( mDecodeData ); - break; - } - case 0x0a: - { - nextAnalyser = new PUdpAptLocInfo( mDecodeData ); - break; - } - case 0x0f: - { - nextAnalyser = new PUdpVhcUse( mDecodeData ); - break; - } - case 0x10: - { - nextAnalyser = new PUdpKillSelf( mDecodeData ); - break; - } - default: - { - mDecodeData->mUnknownType = MsgSubType; - break; - } - } - break; - } - case 0x3e: - { - nextAnalyser = new PUdpPvPTrade( mDecodeData ); - break; - } - case 0x4c: - { - nextAnalyser = new PUdpChatChannels( mDecodeData ); - break; - } - default: - { - mDecodeData->mUnknownType = MsgType; - mDecodeData->mTraceUnknownMsg = true; - break; - } - } - - if ( ! nextAnalyser ) - { - nextAnalyser = new PUdpMsgUnknown( mDecodeData ); - } - - return nextAnalyser; -} +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdp0x1f ****/ + +PUdp0x1f::PUdp0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x1f"; +} + +PUdpMsgAnalyser* PUdp0x1f::Analyse() +{ + PUdpMsgAnalyser* nextAnalyser = NULL; + mDecodeData->mState = DECODE_MORE; + uint8_t MsgType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 7 ); + uint8_t MsgSubType = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 8 ); + + switch ( MsgType ) + { + case 0x00: + { + nextAnalyser = new PUdpHeldItemBasicAction( mDecodeData ); + break; + } + case 0x01: + { + nextAnalyser = new PUdpHeldItemAimedAction( mDecodeData ); + break; + } + case 0x02: + { + nextAnalyser = new PUdpCharJump( mDecodeData ); + break; + } + case 0x17: + { + nextAnalyser = new PUdpUseObject( mDecodeData ); + break; + } + case 0x19: // NPC Dialog closed + { + nextAnalyser = new PUdpNPCDialogClose( mDecodeData ); + break; + } + case 0x1a: // NPC Dialog action/reply + { + nextAnalyser = new PUdpNPCDialogAction( mDecodeData ); + break; + } + case 0x1b: + { + nextAnalyser = new PUdpChatLocal( mDecodeData ); + break; + } + case 0x1e: // item move QB<>INV<>GND + { + nextAnalyser = new PUdpItemMove( mDecodeData ); + break; + } + case 0x1f: // Slot use + { + nextAnalyser = new PUdpItemSlotUse( mDecodeData ); + break; + } + case 0x20: // Use item for hacking, launcher, "launcher" spell + { + nextAnalyser = new PUdpHeldItemLaunchingAction( mDecodeData ); + break; + } + case 0x22: + { + nextAnalyser = new PUdpCharExitChair( mDecodeData ); + break; + } + case 0x25: + { + mDecodeData->mName << "/0x25"; + switch ( MsgSubType ) + { + case 0x04: // Hack announcement? + { + nextAnalyser = new PUdpSubskillInc( mDecodeData ); + break; + } + case 0x0c: // addons activation + { + nextAnalyser = new PUdpItemAddonActivation( mDecodeData ); + break; + } + case 0x14: // Hack announcement? + { + nextAnalyser = new PUdpItemMoveBP( mDecodeData ); + break; + } + case 0x16: // ???? confirm reload anim start ??? + { + mDecodeData->mUnknownType = MsgSubType; + mDecodeData->mTraceUnknownMsg = true; + break; + } + case 0x17: // Item drop on item + { + nextAnalyser = new PUdpItemDropOnItem( mDecodeData ); + break; + } + case 0x18: + { + mDecodeData->mName << "/0x18"; + switch ( mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 9 ) ) + { + case 0x01: // Use inventory item + { + nextAnalyser = new PUdpItemUse( mDecodeData ); + break; + } + case 0x0e: // Request manual reload + { + nextAnalyser = new PUdpItemManualReload( mDecodeData ); + break; + } + default: + { + mDecodeData->mUnknownType = MsgSubType; + mDecodeData->mTraceUnknownMsg = true; + break; + } + } + break; + } + + case 0x1d: // ? before Packet0: 0b 03 01 00 1f 00 00 25 1d 00 00 01 + case 0x1e: // ? before Packet0: 0d 03 02 00 1f 00 00 25 1e ff ff ff ff 00 + default: + { + mDecodeData->mUnknownType = MsgSubType; + mDecodeData->mTraceUnknownMsg = true; + break; + } + } + break; + } + case 0x27: + { + nextAnalyser = new PUdpCloseItemContainer( mDecodeData ); + break; + } + case 0x29: + { + nextAnalyser = new PUdpHackSuccess( mDecodeData ); + break; + } + case 0x2c: + { + nextAnalyser = new PUdpHackFail( mDecodeData ); + break; + } + case 0x2e: + { + nextAnalyser = new PUdpOutfitter( mDecodeData ); + break; + } + case 0x2f: + { + nextAnalyser = new PUdpDeathRespawn( mDecodeData ); + break; + } + case 0x33: + { + nextAnalyser = new PUdpChatListAdd( mDecodeData ); + break; + } + case 0x38: + { + nextAnalyser = new PUdpAppartmentAccess( mDecodeData ); + break; + } + case 0x39: + { + nextAnalyser = new PUdpChatListRemove( mDecodeData ); + break; + } + case 0x3b: + { + nextAnalyser = new PUdpChatGlobal( mDecodeData ); + break; + } + case 0x3d: + { + mDecodeData->mName << "/0x3d"; + switch ( MsgSubType ) // In fact MsgSubType is U32, but only lower byte is used + { + case 0x02: + { + nextAnalyser = new PUdpAddGenrepToList( mDecodeData ); + break; + } + case 0x03: + { + nextAnalyser = new PUdpAptGRZoning( mDecodeData ); + break; + } + case 0x04: + { + nextAnalyser = new PUdpGenrepZoning( mDecodeData ); + break; + } + case 0x09: + { + nextAnalyser = new PUdpPopupResponse( mDecodeData ); + break; + } + case 0x0a: + { + nextAnalyser = new PUdpAptLocInfo( mDecodeData ); + break; + } + case 0x0f: + { + nextAnalyser = new PUdpVhcUse( mDecodeData ); + break; + } + case 0x10: + { + nextAnalyser = new PUdpKillSelf( mDecodeData ); + break; + } + default: + { + mDecodeData->mUnknownType = MsgSubType; + break; + } + } + break; + } + case 0x3e: + { + nextAnalyser = new PUdpPvPTrade( mDecodeData ); + break; + } + case 0x4c: + { + nextAnalyser = new PUdpChatChannels( mDecodeData ); + break; + } + default: + { + mDecodeData->mUnknownType = MsgType; + mDecodeData->mTraceUnknownMsg = true; + break; + } + } + + if ( ! nextAnalyser ) + { + nextAnalyser = new PUdpMsgUnknown( mDecodeData ); + } + + return nextAnalyser; +} diff --git a/TinNS/Source/GameServer/Decoder/Udp0x1f.hxx b/TinNS/Source/GameServer/Decoder/Udp0x1f.hxx index 0613a0c..48ba284 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x1f.hxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x1f.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdp0x1f : public PUdpMsgAnalyser { -public: - PUdp0x1f(PMsgDecodeData *nDecodeData); - //~PUdp0x1f(); - PUdpMsgAnalyser *Analyse(); - //bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdp0x1f : public PUdpMsgAnalyser { +public: + PUdp0x1f(PMsgDecodeData *nDecodeData); + //~PUdp0x1f(); + PUdpMsgAnalyser *Analyse(); + //bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/Udp0x22.cxx b/TinNS/Source/GameServer/Decoder/Udp0x22.cxx index 459666b..a2f54ee 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x22.cxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x22.cxx @@ -1,51 +1,51 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdp0x22 ****/ - -PUdp0x22::PUdp0x22(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - nDecodeData->mName << "/0x22"; -} - -PUdpMsgAnalyser* PUdp0x22::Analyse() -{ - PUdpMsgAnalyser* nextAnalyser = NULL; - mDecodeData->mState = DECODE_MORE; - uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5); - switch(MsgType) // MsgType is probably uint16_t rather than uint8_t - { - case 0x03: // Zoning phase 2 - { - nextAnalyser = new PUdpZoning2(mDecodeData); - break; - } - case 0x06: // Char/Clan/Rank/Map Info request - { - nextAnalyser = new PUdpReqInfo(mDecodeData); - break; - } - case 0x0b: // Entity position request - { - nextAnalyser = new PUdpEntityPosRequest(mDecodeData); - break; - } - case 0x0d: // Zoning phase 1 - { - nextAnalyser = new PUdpZoning1(mDecodeData); - break; - } - default: - { - mDecodeData->mUnknownType = MsgType; - break; - } - } - - if (! nextAnalyser) - { - nextAnalyser = new PUdpMsgUnknown(mDecodeData); - } - - return nextAnalyser; -} +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdp0x22 ****/ + +PUdp0x22::PUdp0x22(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + nDecodeData->mName << "/0x22"; +} + +PUdpMsgAnalyser* PUdp0x22::Analyse() +{ + PUdpMsgAnalyser* nextAnalyser = NULL; + mDecodeData->mState = DECODE_MORE; + uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5); + switch(MsgType) // MsgType is probably uint16_t rather than uint8_t + { + case 0x03: // Zoning phase 2 + { + nextAnalyser = new PUdpZoning2(mDecodeData); + break; + } + case 0x06: // Char/Clan/Rank/Map Info request + { + nextAnalyser = new PUdpReqInfo(mDecodeData); + break; + } + case 0x0b: // Entity position request + { + nextAnalyser = new PUdpEntityPosRequest(mDecodeData); + break; + } + case 0x0d: // Zoning phase 1 + { + nextAnalyser = new PUdpZoning1(mDecodeData); + break; + } + default: + { + mDecodeData->mUnknownType = MsgType; + break; + } + } + + if (! nextAnalyser) + { + nextAnalyser = new PUdpMsgUnknown(mDecodeData); + } + + return nextAnalyser; +} diff --git a/TinNS/Source/GameServer/Decoder/Udp0x22.hxx b/TinNS/Source/GameServer/Decoder/Udp0x22.hxx index aa946b3..7795b08 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x22.hxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x22.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdp0x22 : public PUdpMsgAnalyser { -public: - PUdp0x22(PMsgDecodeData *nDecodeData); - //~PUdp0x22(); - PUdpMsgAnalyser *Analyse(); - //bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdp0x22 : public PUdpMsgAnalyser { +public: + PUdp0x22(PMsgDecodeData *nDecodeData); + //~PUdp0x22(); + PUdpMsgAnalyser *Analyse(); + //bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/Udp0x2b.cxx b/TinNS/Source/GameServer/Decoder/Udp0x2b.cxx index 28e9e5a..213629e 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x2b.cxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x2b.cxx @@ -1,57 +1,57 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdp0x2b ****/ - -PUdp0x2b::PUdp0x2b(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - nDecodeData->mName << "/0x2b"; -} - -PUdpMsgAnalyser* PUdp0x2b::Analyse() -{ - PUdpMsgAnalyser* nextAnalyser = nullptr; - mDecodeData->mState = DECODE_MORE; - uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5); - switch(MsgType) - { - case 0x17: // ReceiveDB Terminal Command - { - nextAnalyser = new PUdpReceiveDB(mDecodeData); - break; - } - case 0x18: // UpdateDB Terminal Command - { - nextAnalyser = new PUdpUpdateDB(mDecodeData); - break; - } - case 0x19: // TryAccess Terminal Command - { - nextAnalyser = new PUdpTryAccessDB(mDecodeData); - break; - } - case 0x1b: // DB Query and Command - { - nextAnalyser = new PUdpQueryDB(mDecodeData); - break; - } - case 0x1f: // Citycom? - { - nextAnalyser = new PUdpTeminal0x1f(mDecodeData); - break; - } - - default: - { - mDecodeData->mUnknownType = MsgType; - break; - } - } - - if (! nextAnalyser) - { - nextAnalyser = new PUdpMsgUnknown(mDecodeData); - } - - return nextAnalyser; -} +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdp0x2b ****/ + +PUdp0x2b::PUdp0x2b(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + nDecodeData->mName << "/0x2b"; +} + +PUdpMsgAnalyser* PUdp0x2b::Analyse() +{ + PUdpMsgAnalyser* nextAnalyser = nullptr; + mDecodeData->mState = DECODE_MORE; + uint8_t MsgType = mDecodeData->mMessage->U8Data(mDecodeData->Sub0x13Start + 5); + switch(MsgType) + { + case 0x17: // ReceiveDB Terminal Command + { + nextAnalyser = new PUdpReceiveDB(mDecodeData); + break; + } + case 0x18: // UpdateDB Terminal Command + { + nextAnalyser = new PUdpUpdateDB(mDecodeData); + break; + } + case 0x19: // TryAccess Terminal Command + { + nextAnalyser = new PUdpTryAccessDB(mDecodeData); + break; + } + case 0x1b: // DB Query and Command + { + nextAnalyser = new PUdpQueryDB(mDecodeData); + break; + } + case 0x1f: // Citycom? + { + nextAnalyser = new PUdpTeminal0x1f(mDecodeData); + break; + } + + default: + { + mDecodeData->mUnknownType = MsgType; + break; + } + } + + if (! nextAnalyser) + { + nextAnalyser = new PUdpMsgUnknown(mDecodeData); + } + + return nextAnalyser; +} diff --git a/TinNS/Source/GameServer/Decoder/Udp0x2b.hxx b/TinNS/Source/GameServer/Decoder/Udp0x2b.hxx index e3baa60..1295f9d 100644 --- a/TinNS/Source/GameServer/Decoder/Udp0x2b.hxx +++ b/TinNS/Source/GameServer/Decoder/Udp0x2b.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdp0x2b : public PUdpMsgAnalyser { -public: - PUdp0x2b(PMsgDecodeData *nDecodeData); - //~PUdp0x2b(); - PUdpMsgAnalyser *Analyse(); - //bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdp0x2b : public PUdpMsgAnalyser { +public: + PUdp0x2b(PMsgDecodeData *nDecodeData); + //~PUdp0x2b(); + PUdpMsgAnalyser *Analyse(); + //bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpAnalyser.cxx b/TinNS/Source/GameServer/Decoder/UdpAnalyser.cxx index 24d2aa3..dbe6e37 100644 --- a/TinNS/Source/GameServer/Decoder/UdpAnalyser.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpAnalyser.cxx @@ -1,108 +1,108 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdpMsgAnalyser ****/ - -int PUdpMsgAnalyser::smAnaCount = 0; // temp for check - -PUdpMsgAnalyser::PUdpMsgAnalyser(PMsgDecodeData* nDecodeData) -{ - mDecodeData = nDecodeData; - if (++smAnaCount > 2) // temp for check - Console->Print(RED, BLACK, "Analyser instances count: %d", smAnaCount); // temp for check -} - -PUdpMsgAnalyser::~PUdpMsgAnalyser() -{ - --smAnaCount; -} - -PUdpMsgAnalyser* PUdpMsgAnalyser::Analyse() -{ - PUdpMsgAnalyser* nextAnalyser; - uint8_t MsgType; - - mDecodeData->mState = DECODE_MORE; -//mDecodeData->mTraceKnownMsg = true; // Don't want to trace all known messages -mDecodeData->mTraceUnknownMsg = true; // Want to show all unknown messages - - *(mDecodeData->mMessage) >> MsgType; - switch(MsgType) - { - case 0x01: - { - nextAnalyser = new PUdpSync0(mDecodeData); - break; - } - case 0x03: - { - nextAnalyser = new PUdpSync1(mDecodeData); - break; - } - case 0x08: - { - nextAnalyser = new PUdp0x08(mDecodeData); - break; - } - case 0x13: - { - nextAnalyser = new PUdp0x13(mDecodeData); - break; - } - default: - { - mDecodeData->mUnknownType = MsgType; - nextAnalyser = new PUdpMsgUnknown(mDecodeData); - break; - } - } - return nextAnalyser; -} - -bool PUdpMsgAnalyser::DoAction() -{ - return false; // no action at this level -} - - -/**** Unkown UDP message ****/ - -PUdpMsgUnknown::PUdpMsgUnknown(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - char hexstr[16]; - - nDecodeData->mState = DECODE_UNKNOWN; - snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType); - mDecodeData->mName << hexstr; - nDecodeData->mName << "=Unknown"; -} - -/*PUdpMsgUnknown::~PUdpMsgUnknown() -{ -}*/ - -/*bool PUdpMsgUnknown::DoAction() -{ - return false; -}*/ - -/**** Ignore UDP message ****/ - -PUdpMsgIgnore::PUdpMsgIgnore(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - char hexstr[16]; - - nDecodeData->mState = DECODE_FINISHED; - snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType); - mDecodeData->mName << hexstr; - nDecodeData->mName << "=Ignore"; -} - -/*PUdpMsgUnknown::~PUdpMsgUnknown() -{ -}*/ - -/*bool PUdpMsgUnknown::DoAction() -{ - return false; -}*/ +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdpMsgAnalyser ****/ + +int PUdpMsgAnalyser::smAnaCount = 0; // temp for check + +PUdpMsgAnalyser::PUdpMsgAnalyser(PMsgDecodeData* nDecodeData) +{ + mDecodeData = nDecodeData; + if (++smAnaCount > 2) // temp for check + Console->Print(RED, BLACK, "Analyser instances count: %d", smAnaCount); // temp for check +} + +PUdpMsgAnalyser::~PUdpMsgAnalyser() +{ + --smAnaCount; +} + +PUdpMsgAnalyser* PUdpMsgAnalyser::Analyse() +{ + PUdpMsgAnalyser* nextAnalyser; + uint8_t MsgType; + + mDecodeData->mState = DECODE_MORE; +//mDecodeData->mTraceKnownMsg = true; // Don't want to trace all known messages +mDecodeData->mTraceUnknownMsg = true; // Want to show all unknown messages + + *(mDecodeData->mMessage) >> MsgType; + switch(MsgType) + { + case 0x01: + { + nextAnalyser = new PUdpSync0(mDecodeData); + break; + } + case 0x03: + { + nextAnalyser = new PUdpSync1(mDecodeData); + break; + } + case 0x08: + { + nextAnalyser = new PUdp0x08(mDecodeData); + break; + } + case 0x13: + { + nextAnalyser = new PUdp0x13(mDecodeData); + break; + } + default: + { + mDecodeData->mUnknownType = MsgType; + nextAnalyser = new PUdpMsgUnknown(mDecodeData); + break; + } + } + return nextAnalyser; +} + +bool PUdpMsgAnalyser::DoAction() +{ + return false; // no action at this level +} + + +/**** Unkown UDP message ****/ + +PUdpMsgUnknown::PUdpMsgUnknown(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + char hexstr[16]; + + nDecodeData->mState = DECODE_UNKNOWN; + snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType); + mDecodeData->mName << hexstr; + nDecodeData->mName << "=Unknown"; +} + +/*PUdpMsgUnknown::~PUdpMsgUnknown() +{ +}*/ + +/*bool PUdpMsgUnknown::DoAction() +{ + return false; +}*/ + +/**** Ignore UDP message ****/ + +PUdpMsgIgnore::PUdpMsgIgnore(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + char hexstr[16]; + + nDecodeData->mState = DECODE_FINISHED; + snprintf(hexstr, 16, "/0x%02x", mDecodeData->mUnknownType); + mDecodeData->mName << hexstr; + nDecodeData->mName << "=Ignore"; +} + +/*PUdpMsgUnknown::~PUdpMsgUnknown() +{ +}*/ + +/*bool PUdpMsgUnknown::DoAction() +{ + return false; +}*/ diff --git a/TinNS/Source/GameServer/Decoder/UdpAnalyser.hxx b/TinNS/Source/GameServer/Decoder/UdpAnalyser.hxx index 9c98d48..a6fc151 100644 --- a/TinNS/Source/GameServer/Decoder/UdpAnalyser.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpAnalyser.hxx @@ -1,38 +1,38 @@ -#pragma once - -#include - -struct PMsgDecodeData; - -class PUdpMsgAnalyser { - friend class PUdpMsgDecoder; - -protected: - PMsgDecodeData* mDecodeData; - -public: - PUdpMsgAnalyser(PMsgDecodeData *nDecodeData); - virtual ~PUdpMsgAnalyser(); - - virtual PUdpMsgAnalyser *Analyse(); - virtual bool DoAction(); - - static int32_t smAnaCount; // temp for check - -}; - -class PUdpMsgUnknown : public PUdpMsgAnalyser { -public: - PUdpMsgUnknown(PMsgDecodeData *nDecodeData); - //~PUdpMsgUnknown(); - - //bool DoAction(); -}; - -class PUdpMsgIgnore : public PUdpMsgAnalyser { -public: - PUdpMsgIgnore(PMsgDecodeData *nDecodeData); - //~PUdpMsgUnknown(); - - //bool DoAction(); -}; +#pragma once + +#include + +struct PMsgDecodeData; + +class PUdpMsgAnalyser { + friend class PUdpMsgDecoder; + +protected: + PMsgDecodeData* mDecodeData; + +public: + PUdpMsgAnalyser(PMsgDecodeData *nDecodeData); + virtual ~PUdpMsgAnalyser(); + + virtual PUdpMsgAnalyser *Analyse(); + virtual bool DoAction(); + + static int32_t smAnaCount; // temp for check + +}; + +class PUdpMsgUnknown : public PUdpMsgAnalyser { +public: + PUdpMsgUnknown(PMsgDecodeData *nDecodeData); + //~PUdpMsgUnknown(); + + //bool DoAction(); +}; + +class PUdpMsgIgnore : public PUdpMsgAnalyser { +public: + PUdpMsgIgnore(PMsgDecodeData *nDecodeData); + //~PUdpMsgUnknown(); + + //bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpAppartment.hxx b/TinNS/Source/GameServer/Decoder/UdpAppartment.hxx index ca627bf..d1941c3 100644 --- a/TinNS/Source/GameServer/Decoder/UdpAppartment.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpAppartment.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpAptLocInfo : public PUdpMsgAnalyser { -public: - PUdpAptLocInfo(PMsgDecodeData *nDecodeData); - //~PUdpAptLocInfo(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpAptLocInfo : public PUdpMsgAnalyser { +public: + PUdpAptLocInfo(PMsgDecodeData *nDecodeData); + //~PUdpAptLocInfo(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpCharMove.cxx b/TinNS/Source/GameServer/Decoder/UdpCharMove.cxx index 7100914..1a318e6 100644 --- a/TinNS/Source/GameServer/Decoder/UdpCharMove.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpCharMove.cxx @@ -1,425 +1,425 @@ -#include -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -#define JUMPHEIGHT 160 - -/**** PUdpCharPosUpdate ****/ - -PUdpCharPosUpdate::PUdpCharPosUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x20"; -} - -PUdpMsgAnalyser* PUdpCharPosUpdate::Analyse() -{ - mDecodeData->mName << "=Char position update"; - -//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg -//mDecodeData->mTraceKnownMsg = true; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 4 ); - - *nMsg >> mInfoBitfield; -//bitfield [C?AL UXZY] packet read from LSB -// 8.21 8421 -//Console->Print(YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Bitfield value %02x", mInfoBitfield); - if ( mInfoBitfield & 0x80 ) // Sitting on chair - { - if ( mInfoBitfield & 0x7f ) - { - mDecodeData->mName << " + mixed bitfield (" << mInfoBitfield << ")"; - mDecodeData->mState = DECODE_UNKNOWN | DECODE_FINISHED; - Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent Mixed field value %x", mDecodeData->mClient->GetID(), mInfoBitfield ); - } - else - { - mDecodeData->mName << " (Char sitting)"; - - *nMsg >> mChairItemID; - *nMsg >> mChairItemSeat; - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; -//mDecodeData->mTraceKnownMsg = true; -//mDecodeData->mTraceDump = true; - if ( gDevDebug ) Console->Print( "%s Localid %d sitting on object %d (0x%08x) seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mChairItemID, mChairItemID, mChairItemSeat ); - } - } - else - { - if ( mInfoBitfield & 0x01 ) - { - *nMsg >> mNewY; - } - if ( mInfoBitfield & 0x02 ) - { - *nMsg >> mNewZ; - } - if ( mInfoBitfield & 0x04 ) - { - *nMsg >> mNewX; - } - if ( mInfoBitfield & 0x08 ) - { - *nMsg >> mNewUD; - } - if ( mInfoBitfield & 0x10 ) - { - *nMsg >> mNewLR; - } - if ( mInfoBitfield & 0x20 ) - { - *nMsg >> mNewAct; - } - if ( mInfoBitfield & 0x40 ) // purpose unknown - { - *nMsg >> mNewUnknown; - if ( gDevDebug && mNewUnknown ) - { - Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent field 0x40 (in %x) value %x", mDecodeData->mClient->GetID(), mInfoBitfield, mNewUnknown ); - } - } - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - } - - return this; -} - -bool PUdpCharPosUpdate::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* nChar = nClient->GetChar(); - PMessage* tmpMsg; - - if ( ! (mInfoBitfield & 0x80) ) - { - uint32_t nSeatableObjectId; - uint8_t nSeatId; - if( nChar->GetSeatInUse(&nSeatableObjectId, &nSeatId) == seat_vhc ) - { - tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nSeatableObjectId, nSeatId ); - nClient->FillInUDP_ID(tmpMsg); - nClient->SendUDPMessage( tmpMsg ); - mChairItemID = nSeatableObjectId; - mChairItemSeat = nSeatId; - mInfoBitfield = 0x80; - } - } - - if ( mInfoBitfield & 0x80 ) // Sitting on chair - { - //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient, mChairItemID); - //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient); - //ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config - tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( nClient ); - ClientManager->UDPBroadcast( tmpMsg, nClient, 5000 ); // TODO: Get the range from config - } - else - { - bool IsRealMove = false; - - if (( mInfoBitfield & 0x01 ) && ( nChar->Coords.mY != mNewY ) ) - { - nChar->Coords.mY = mNewY; - IsRealMove = true; - } - if (( mInfoBitfield & 0x02 ) && ( nChar->Coords.mZ != mNewZ ) ) - { - nChar->Coords.mZ = mNewZ; - IsRealMove = true; - } - if (( mInfoBitfield & 0x04 ) && ( nChar->Coords.mX != mNewX ) ) - { - nChar->Coords.mX = mNewX; - IsRealMove = true; - } - if ( mInfoBitfield & 0x08 ) - { - nChar->Coords.mUD = mNewUD; - //IsRealMove = true; - } - if (( mInfoBitfield & 0x10 ) && ( nChar->Coords.mLR != mNewLR ) ) - { - nChar->Coords.mLR = mNewLR; - IsRealMove = true; - } - if ( mInfoBitfield & 0x20 ) - { - nChar->Coords.mAct = mNewAct; - } - if ( mInfoBitfield & 0x20 ) - { - nChar->Coords.mUnknown = mNewUnknown; - } - // movement action byte mask: - // 0x00 NC has no focus (player alt+tab'ed out) - // 0x02 kneeing - // 0x20 Walk mode (= not run mode) - // 0x08 left step - // 0x10 right step - // 0x40 forward - // 0x80 backward - // bits: 00000000 - // BFWRL.K. - - if ( IsRealMove ) - { - nChar->SetDirtyFlag(); - } - /*if(IsRealMove) - if(mInfoBitfield == 0x7f) - { - tmpMsg = MsgBuilder->BuildCharPosUpdateMsg(nClient); - ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config - }*/ - - uint16_t nSaveZ = nChar->Coords.mZ; - if(nChar->Coords.mJumpingState) - { - mInfoBitfield |= 0x02; // Update Z and Act only - if(nChar->Coords.mJumpingState == 1) - { - if ( gDevDebug ) Console->Print( "%s Send moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - (nChar->Coords.mZ) += JUMPHEIGHT; - nChar->Coords.mJumpingState = 2; // Jump done - } - else - nChar->Coords.mJumpingState = 0; // No pending jump - } - - tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield ); - - if(nChar->Coords.mJumpingState) - nChar->Coords.mZ = nSaveZ; - - ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true ); - - if ( IsRealMove && nClient->GetDebugMode( DBG_LOCATION ) ) - { - char DbgMessage[128]; - float f[3]; -// uint32_t h[3]; - f[0] = nChar->Coords.mY - 32000; - f[1] = nChar->Coords.mZ - 32000; - f[2] = nChar->Coords.mX - 32000; - snprintf( DbgMessage, 128, "position y:%0.1f z:%0.1f x:%0.1f lr:%d (Act=%x BF=%x)", f[0], f[1], f[2], nChar->Coords.mLR, nChar->Coords.mAct , mInfoBitfield ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - } - /*{ - uint16_t p[3]; - p[0] = nChar->Coords.mY; - p[1] = nChar->Coords.mZ; - p[2] = nChar->Coords.mX; - for(int i = 0; i<3; i++) - { - if(p[i]< nChar->Coords.minPos[i]) - nChar->Coords.minPos[i] = p[i]; - if(p[i]> nChar->Coords.maxPos[i]) - nChar->Coords.maxPos[i] = p[i]; - } - }*/ - - if(gDevDebug && IsRealMove) - Console->Print("%s Char %d position : X(%d) Y(%d) Z(%d) U/D(%d) L/R(%d) Action(%02x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), nChar->Coords.mX, nChar->Coords.mY, nChar->Coords.mZ, nChar->Coords.mUD, nChar->Coords.mLR, nChar->Coords.mAct); - } - if ( mInfoBitfield >= 0x7f ) - { - tmpMsg = MsgBuilder->BuildCharHealthUpdateMsg( nClient ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - - -/**** PUdpCharExitChair ****/ - -PUdpCharExitChair::PUdpCharExitChair( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x22"; -} - -PUdpMsgAnalyser* PUdpCharExitChair::Analyse() -{ - mDecodeData->mName << "=Char exiting chair"; - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - - return this; -} - -bool PUdpCharExitChair::DoAction() -{ - DoLeaveChair( mDecodeData->mClient->GetChar(), mDecodeData->mClient ); - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - -bool PUdpCharExitChair::DoLeaveChair( PChar* nChar, PClient* nClient, PSpawnedVehicle* nVhc, bool nForce ) -{ - if ( ! nClient ) - nClient = ClientManager->getClientByChar( nChar->GetID() ); - if ( ! nClient ) - { - Console->Print("%s PUdpCharExitChair::DoLeaveChair called without PClient* and client not available when searching by char.", Console->ColorText( RED, BLACK, "[ERROR]" ) ); - return false; - } - - PMessage* tmpMsg; - uint32_t cSeatObjectId; - uint8_t cSeatId; - PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId, &cSeatId ); - uint32_t tNowTime = GameServer->GetGameTime(); - bool ReadyToExit = false; - - // This is only for investigation on subway timing - if ( nClient->GetDebugMode( DBG_SUBWAY ) && ( cSeatType == seat_subway ) ) - { - char DbgMessage[80]; - uint8_t tCabId; - Subway->GetInfoIndex( cSeatObjectId, &tCabId ); - uint8_t tStationId = Subway->GetStation( cSeatObjectId, tNowTime ); - std::string* StationName = Subway->GetStationName( tStationId ); - std::string OpenState = ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) ? "open" : "closed" ); - - snprintf( DbgMessage, 80, "Cab %d (%d) is in station %s (%d). Door is %s (time: %d)", tCabId, cSeatObjectId, StationName->c_str(), tStationId, OpenState.c_str(), tNowTime ); - DbgMessage[79] = 0; - Chat->send( nClient, CHAT_DIRECT, "System", DbgMessage ); - delete StationName; - } - // end investigation - - if ( cSeatType ) - { - PWorld* tWorld = Worlds->GetWorld( nChar->GetLocation() ); - - if ( cSeatType == seat_chair ) - { - tWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId ); - nChar->SetSeatInUse( seat_none ); - ReadyToExit = true; - } - else if ( cSeatType == seat_subway ) - { - if ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) || nForce ) - { - Subway->GetStationExitPosition( &( nChar->Coords ), Subway->GetStation( cSeatObjectId, tNowTime ), GetRandomFloat() ); - Subway->UnsetSeatUser( cSeatObjectId, cSeatId, nChar->GetID() ); - nChar->SetSeatInUse( seat_none ); - ReadyToExit = true; - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, cSeatObjectId ); // "Damn, locked" - nClient->SendUDPMessage( tmpMsg ); - } - } - else if ( cSeatType == seat_vhc ) - { - PSpawnedVehicle* tVhc = tWorld->GetSpawnedVehicles()->GetVehicle( cSeatObjectId ); - if ( tVhc && (!nVhc || (tVhc == nVhc) || nForce) ) - { - PVhcCoordinates tCoords = tVhc->GetPosition(); - tVhc->UnsetSeatUser( cSeatId, nChar->GetID() ); - nChar->SetSeatInUse( seat_none ); - nChar->Coords.SetPosition( tCoords.GetY(), tCoords.GetZ(), tCoords.GetX() ); // to complete with LR - ReadyToExit = true; - } - } - else - { - Console->Print( "%s PUdpCharExitChair::DoLeaveChair : Invalid seat type %d", Console->ColorText( RED, BLACK, "[ERROR]" ), cSeatType ); - } - - if ( ReadyToExit ) - { - nChar->SetSeatInUse( seat_none ); - - tmpMsg = MsgBuilder->BuildCharExitSeatMsg( nClient ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - - if ( gDevDebug ) Console->Print( "%s Localchar %d get up from chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId ); - return true; - } - } - - return false; -} - -/**** PUdpCharJump ****/ - -PUdpCharJump::PUdpCharJump( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x02"; -} - -PUdpMsgAnalyser* PUdpCharJump::Analyse() -{ - mDecodeData->mName << "=Char jumping"; - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - - return this; -} - -bool PUdpCharJump::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* nChar = nClient->GetChar(); - - if( nChar->Coords.mAct & 0xd8 ) // if moving, don't jump now and wait next update - { - nChar->Coords.mJumpingState = 1; // Jump pending. Do at next pos update - if ( gDevDebug ) Console->Print( "%s Prepare moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - } - else // If not moving, jump now - { - if ( gDevDebug ) Console->Print( "%s Send static jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - uint8_t mInfoBitfield = 0x22; // Update Z and Act only - uint16_t nSaveZ = nChar->Coords.mZ; - (nChar->Coords.mZ) += JUMPHEIGHT; - PMessage* tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield ); - nChar->Coords.mZ = nSaveZ; - nChar->Coords.mJumpingState = 2; // Jump done - ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - - return true; -} - - -/**** PUdpCharTargeting ****/ - -PUdpCharTargeting::PUdpCharTargeting( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x2d"; -} - -PUdpMsgAnalyser* PUdpCharTargeting::Analyse() -{ - mDecodeData->mName << "=Targeting char"; - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - - return this; -} - -bool PUdpCharTargeting::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* tChar = nClient->GetChar(); - uint16_t CharID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 2 ); - uint8_t strangeval1 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 4 ); - uint8_t strangeval2 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 5 ); - uint8_t strangeval3 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 ); - - tChar->SetLookingAt( CharID ); - - if ( gDevDebug ) - Console->Print( "%s Char %d targeting char %d. // %d %d %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), CharID, strangeval1, strangeval2, strangeval3 ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +#define JUMPHEIGHT 160 + +/**** PUdpCharPosUpdate ****/ + +PUdpCharPosUpdate::PUdpCharPosUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x20"; +} + +PUdpMsgAnalyser* PUdpCharPosUpdate::Analyse() +{ + mDecodeData->mName << "=Char position update"; + +//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg +//mDecodeData->mTraceKnownMsg = true; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 4 ); + + *nMsg >> mInfoBitfield; +//bitfield [C?AL UXZY] packet read from LSB +// 8.21 8421 +//Console->Print(YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Bitfield value %02x", mInfoBitfield); + if ( mInfoBitfield & 0x80 ) // Sitting on chair + { + if ( mInfoBitfield & 0x7f ) + { + mDecodeData->mName << " + mixed bitfield (" << mInfoBitfield << ")"; + mDecodeData->mState = DECODE_UNKNOWN | DECODE_FINISHED; + Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent Mixed field value %x", mDecodeData->mClient->GetID(), mInfoBitfield ); + } + else + { + mDecodeData->mName << " (Char sitting)"; + + *nMsg >> mChairItemID; + *nMsg >> mChairItemSeat; + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; +//mDecodeData->mTraceKnownMsg = true; +//mDecodeData->mTraceDump = true; + if ( gDevDebug ) Console->Print( "%s Localid %d sitting on object %d (0x%08x) seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mChairItemID, mChairItemID, mChairItemSeat ); + } + } + else + { + if ( mInfoBitfield & 0x01 ) + { + *nMsg >> mNewY; + } + if ( mInfoBitfield & 0x02 ) + { + *nMsg >> mNewZ; + } + if ( mInfoBitfield & 0x04 ) + { + *nMsg >> mNewX; + } + if ( mInfoBitfield & 0x08 ) + { + *nMsg >> mNewUD; + } + if ( mInfoBitfield & 0x10 ) + { + *nMsg >> mNewLR; + } + if ( mInfoBitfield & 0x20 ) + { + *nMsg >> mNewAct; + } + if ( mInfoBitfield & 0x40 ) // purpose unknown + { + *nMsg >> mNewUnknown; + if ( gDevDebug && mNewUnknown ) + { + Console->Print( YELLOW, BLACK, "[DEBUG] PUdpCharPosUpdate: Client %d sent field 0x40 (in %x) value %x", mDecodeData->mClient->GetID(), mInfoBitfield, mNewUnknown ); + } + } + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + } + + return this; +} + +bool PUdpCharPosUpdate::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* nChar = nClient->GetChar(); + PMessage* tmpMsg; + + if ( ! (mInfoBitfield & 0x80) ) + { + uint32_t nSeatableObjectId; + uint8_t nSeatId; + if( nChar->GetSeatInUse(&nSeatableObjectId, &nSeatId) == seat_vhc ) + { + tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nSeatableObjectId, nSeatId ); + nClient->FillInUDP_ID(tmpMsg); + nClient->SendUDPMessage( tmpMsg ); + mChairItemID = nSeatableObjectId; + mChairItemSeat = nSeatId; + mInfoBitfield = 0x80; + } + } + + if ( mInfoBitfield & 0x80 ) // Sitting on chair + { + //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient, mChairItemID); + //tmpMsg = MsgBuilder->BuildCharSittingMsg(nClient); + //ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config + tmpMsg = MsgBuilder->BuildCharPosUpdateMsg( nClient ); + ClientManager->UDPBroadcast( tmpMsg, nClient, 5000 ); // TODO: Get the range from config + } + else + { + bool IsRealMove = false; + + if (( mInfoBitfield & 0x01 ) && ( nChar->Coords.mY != mNewY ) ) + { + nChar->Coords.mY = mNewY; + IsRealMove = true; + } + if (( mInfoBitfield & 0x02 ) && ( nChar->Coords.mZ != mNewZ ) ) + { + nChar->Coords.mZ = mNewZ; + IsRealMove = true; + } + if (( mInfoBitfield & 0x04 ) && ( nChar->Coords.mX != mNewX ) ) + { + nChar->Coords.mX = mNewX; + IsRealMove = true; + } + if ( mInfoBitfield & 0x08 ) + { + nChar->Coords.mUD = mNewUD; + //IsRealMove = true; + } + if (( mInfoBitfield & 0x10 ) && ( nChar->Coords.mLR != mNewLR ) ) + { + nChar->Coords.mLR = mNewLR; + IsRealMove = true; + } + if ( mInfoBitfield & 0x20 ) + { + nChar->Coords.mAct = mNewAct; + } + if ( mInfoBitfield & 0x20 ) + { + nChar->Coords.mUnknown = mNewUnknown; + } + // movement action byte mask: + // 0x00 NC has no focus (player alt+tab'ed out) + // 0x02 kneeing + // 0x20 Walk mode (= not run mode) + // 0x08 left step + // 0x10 right step + // 0x40 forward + // 0x80 backward + // bits: 00000000 + // BFWRL.K. + + if ( IsRealMove ) + { + nChar->SetDirtyFlag(); + } + /*if(IsRealMove) + if(mInfoBitfield == 0x7f) + { + tmpMsg = MsgBuilder->BuildCharPosUpdateMsg(nClient); + ClientManager->UDPBroadcast(tmpMsg, nClient, 5000); // TODO: Get the range from config + }*/ + + uint16_t nSaveZ = nChar->Coords.mZ; + if(nChar->Coords.mJumpingState) + { + mInfoBitfield |= 0x02; // Update Z and Act only + if(nChar->Coords.mJumpingState == 1) + { + if ( gDevDebug ) Console->Print( "%s Send moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + (nChar->Coords.mZ) += JUMPHEIGHT; + nChar->Coords.mJumpingState = 2; // Jump done + } + else + nChar->Coords.mJumpingState = 0; // No pending jump + } + + tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield ); + + if(nChar->Coords.mJumpingState) + nChar->Coords.mZ = nSaveZ; + + ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true ); + + if ( IsRealMove && nClient->GetDebugMode( DBG_LOCATION ) ) + { + char DbgMessage[128]; + float f[3]; +// uint32_t h[3]; + f[0] = nChar->Coords.mY - 32000; + f[1] = nChar->Coords.mZ - 32000; + f[2] = nChar->Coords.mX - 32000; + snprintf( DbgMessage, 128, "position y:%0.1f z:%0.1f x:%0.1f lr:%d (Act=%x BF=%x)", f[0], f[1], f[2], nChar->Coords.mLR, nChar->Coords.mAct , mInfoBitfield ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + } + /*{ + uint16_t p[3]; + p[0] = nChar->Coords.mY; + p[1] = nChar->Coords.mZ; + p[2] = nChar->Coords.mX; + for(int i = 0; i<3; i++) + { + if(p[i]< nChar->Coords.minPos[i]) + nChar->Coords.minPos[i] = p[i]; + if(p[i]> nChar->Coords.maxPos[i]) + nChar->Coords.maxPos[i] = p[i]; + } + }*/ + + if(gDevDebug && IsRealMove) + Console->Print("%s Char %d position : X(%d) Y(%d) Z(%d) U/D(%d) L/R(%d) Action(%02x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), nChar->Coords.mX, nChar->Coords.mY, nChar->Coords.mZ, nChar->Coords.mUD, nChar->Coords.mLR, nChar->Coords.mAct); + } + if ( mInfoBitfield >= 0x7f ) + { + tmpMsg = MsgBuilder->BuildCharHealthUpdateMsg( nClient ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + + +/**** PUdpCharExitChair ****/ + +PUdpCharExitChair::PUdpCharExitChair( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x22"; +} + +PUdpMsgAnalyser* PUdpCharExitChair::Analyse() +{ + mDecodeData->mName << "=Char exiting chair"; + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + + return this; +} + +bool PUdpCharExitChair::DoAction() +{ + DoLeaveChair( mDecodeData->mClient->GetChar(), mDecodeData->mClient ); + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + +bool PUdpCharExitChair::DoLeaveChair( PChar* nChar, PClient* nClient, PSpawnedVehicle* nVhc, bool nForce ) +{ + if ( ! nClient ) + nClient = ClientManager->getClientByChar( nChar->GetID() ); + if ( ! nClient ) + { + Console->Print("%s PUdpCharExitChair::DoLeaveChair called without PClient* and client not available when searching by char.", Console->ColorText( RED, BLACK, "[ERROR]" ) ); + return false; + } + + PMessage* tmpMsg; + uint32_t cSeatObjectId; + uint8_t cSeatId; + PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId, &cSeatId ); + uint32_t tNowTime = GameServer->GetGameTime(); + bool ReadyToExit = false; + + // This is only for investigation on subway timing + if ( nClient->GetDebugMode( DBG_SUBWAY ) && ( cSeatType == seat_subway ) ) + { + char DbgMessage[80]; + uint8_t tCabId; + Subway->GetInfoIndex( cSeatObjectId, &tCabId ); + uint8_t tStationId = Subway->GetStation( cSeatObjectId, tNowTime ); + std::string* StationName = Subway->GetStationName( tStationId ); + std::string OpenState = ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) ? "open" : "closed" ); + + snprintf( DbgMessage, 80, "Cab %d (%d) is in station %s (%d). Door is %s (time: %d)", tCabId, cSeatObjectId, StationName->c_str(), tStationId, OpenState.c_str(), tNowTime ); + DbgMessage[79] = 0; + Chat->send( nClient, CHAT_DIRECT, "System", DbgMessage ); + delete StationName; + } + // end investigation + + if ( cSeatType ) + { + PWorld* tWorld = Worlds->GetWorld( nChar->GetLocation() ); + + if ( cSeatType == seat_chair ) + { + tWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId ); + nChar->SetSeatInUse( seat_none ); + ReadyToExit = true; + } + else if ( cSeatType == seat_subway ) + { + if ( Subway->IsDoorOpen( cSeatObjectId, tNowTime ) || nForce ) + { + Subway->GetStationExitPosition( &( nChar->Coords ), Subway->GetStation( cSeatObjectId, tNowTime ), GetRandomFloat() ); + Subway->UnsetSeatUser( cSeatObjectId, cSeatId, nChar->GetID() ); + nChar->SetSeatInUse( seat_none ); + ReadyToExit = true; + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, cSeatObjectId ); // "Damn, locked" + nClient->SendUDPMessage( tmpMsg ); + } + } + else if ( cSeatType == seat_vhc ) + { + PSpawnedVehicle* tVhc = tWorld->GetSpawnedVehicles()->GetVehicle( cSeatObjectId ); + if ( tVhc && (!nVhc || (tVhc == nVhc) || nForce) ) + { + PVhcCoordinates tCoords = tVhc->GetPosition(); + tVhc->UnsetSeatUser( cSeatId, nChar->GetID() ); + nChar->SetSeatInUse( seat_none ); + nChar->Coords.SetPosition( tCoords.GetY(), tCoords.GetZ(), tCoords.GetX() ); // to complete with LR + ReadyToExit = true; + } + } + else + { + Console->Print( "%s PUdpCharExitChair::DoLeaveChair : Invalid seat type %d", Console->ColorText( RED, BLACK, "[ERROR]" ), cSeatType ); + } + + if ( ReadyToExit ) + { + nChar->SetSeatInUse( seat_none ); + + tmpMsg = MsgBuilder->BuildCharExitSeatMsg( nClient ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + + if ( gDevDebug ) Console->Print( "%s Localchar %d get up from chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId ); + return true; + } + } + + return false; +} + +/**** PUdpCharJump ****/ + +PUdpCharJump::PUdpCharJump( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x02"; +} + +PUdpMsgAnalyser* PUdpCharJump::Analyse() +{ + mDecodeData->mName << "=Char jumping"; + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + + return this; +} + +bool PUdpCharJump::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* nChar = nClient->GetChar(); + + if( nChar->Coords.mAct & 0xd8 ) // if moving, don't jump now and wait next update + { + nChar->Coords.mJumpingState = 1; // Jump pending. Do at next pos update + if ( gDevDebug ) Console->Print( "%s Prepare moving jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + } + else // If not moving, jump now + { + if ( gDevDebug ) Console->Print( "%s Send static jump", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + uint8_t mInfoBitfield = 0x22; // Update Z and Act only + uint16_t nSaveZ = nChar->Coords.mZ; + (nChar->Coords.mZ) += JUMPHEIGHT; + PMessage* tmpMsg = MsgBuilder->BuildCharPosUpdate2Msg( nClient, mInfoBitfield ); + nChar->Coords.mZ = nSaveZ; + nChar->Coords.mJumpingState = 2; // Jump done + ClientManager->UDPBroadcast( tmpMsg, nClient, 5000, true ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + + return true; +} + + +/**** PUdpCharTargeting ****/ + +PUdpCharTargeting::PUdpCharTargeting( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x2d"; +} + +PUdpMsgAnalyser* PUdpCharTargeting::Analyse() +{ + mDecodeData->mName << "=Targeting char"; + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + + return this; +} + +bool PUdpCharTargeting::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* tChar = nClient->GetChar(); + uint16_t CharID = mDecodeData->mMessage->U16Data( mDecodeData->Sub0x13Start + 2 ); + uint8_t strangeval1 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 4 ); + uint8_t strangeval2 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 5 ); + uint8_t strangeval3 = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 ); + + tChar->SetLookingAt( CharID ); + + if ( gDevDebug ) + Console->Print( "%s Char %d targeting char %d. // %d %d %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetID(), CharID, strangeval1, strangeval2, strangeval3 ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpCharMove.hxx b/TinNS/Source/GameServer/Decoder/UdpCharMove.hxx index e0cc96e..c849af6 100644 --- a/TinNS/Source/GameServer/Decoder/UdpCharMove.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpCharMove.hxx @@ -1,56 +1,56 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PChar; -class PClient; -class PSpawnedVehicle; - -class PUdpCharPosUpdate : public PUdpMsgAnalyser { -private: - uint8_t mInfoBitfield; - uint16_t mNewY; - uint16_t mNewZ; - uint16_t mNewX; - uint8_t mNewUD; - uint8_t mNewLR; - uint8_t mNewAct; - uint8_t mNewUnknown; - uint32_t mChairItemID; // uint16_t or uint32_t ??? - uint8_t mChairItemSeat; - -public: - PUdpCharPosUpdate(PMsgDecodeData *nDecodeData); - //~PUdpCharMoves(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpCharExitChair : public PUdpMsgAnalyser { -public: - PUdpCharExitChair(PMsgDecodeData *nDecodeData); - //~PUdpCharExitChair(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - - //nClient is optionnal, nVhc is to limit to that vhc, nForce to force exit event when cab door closed - static bool DoLeaveChair(PChar *nChar, PClient *nClient = nullptr, PSpawnedVehicle *nVhc = nullptr, - bool nForce = false); -}; - -class PUdpCharJump : public PUdpMsgAnalyser { -public: - PUdpCharJump(PMsgDecodeData *nDecodeData); - //~PUdpCharJump(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpCharTargeting : public PUdpMsgAnalyser { -public: - PUdpCharTargeting(PMsgDecodeData *nDecodeData); - //~PUdpCharTargeting(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PChar; +class PClient; +class PSpawnedVehicle; + +class PUdpCharPosUpdate : public PUdpMsgAnalyser { +private: + uint8_t mInfoBitfield; + uint16_t mNewY; + uint16_t mNewZ; + uint16_t mNewX; + uint8_t mNewUD; + uint8_t mNewLR; + uint8_t mNewAct; + uint8_t mNewUnknown; + uint32_t mChairItemID; // uint16_t or uint32_t ??? + uint8_t mChairItemSeat; + +public: + PUdpCharPosUpdate(PMsgDecodeData *nDecodeData); + //~PUdpCharMoves(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpCharExitChair : public PUdpMsgAnalyser { +public: + PUdpCharExitChair(PMsgDecodeData *nDecodeData); + //~PUdpCharExitChair(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + + //nClient is optionnal, nVhc is to limit to that vhc, nForce to force exit event when cab door closed + static bool DoLeaveChair(PChar *nChar, PClient *nClient = nullptr, PSpawnedVehicle *nVhc = nullptr, + bool nForce = false); +}; + +class PUdpCharJump : public PUdpMsgAnalyser { +public: + PUdpCharJump(PMsgDecodeData *nDecodeData); + //~PUdpCharJump(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpCharTargeting : public PUdpMsgAnalyser { +public: + PUdpCharTargeting(PMsgDecodeData *nDecodeData); + //~PUdpCharTargeting(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpChat.hxx b/TinNS/Source/GameServer/Decoder/UdpChat.hxx index 5abf6d8..f16bd01 100644 --- a/TinNS/Source/GameServer/Decoder/UdpChat.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpChat.hxx @@ -1,55 +1,55 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpChatLocal : public PUdpMsgAnalyser { -public: - PUdpChatLocal(PMsgDecodeData *nDecodeData); - //~PUdpChatLocal(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpChatGlobal : public PUdpMsgAnalyser { -public: - PUdpChatGlobal(PMsgDecodeData *nDecodeData); - //~PUdpChatGlobal(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpChatListAdd : public PUdpMsgAnalyser { -private: - uint8_t mChatList; // 1 = Direct, 2 = Buddy List - char *mAddedCharname; - -public: - PUdpChatListAdd(PMsgDecodeData *nDecodeData); - //~PUdpChatListAdd(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpChatListRemove : public PUdpMsgAnalyser { -private: - uint8_t mChatList; - uint32_t mRemovedCharID; - -public: - PUdpChatListRemove(PMsgDecodeData *nDecodeData); - //~PUdpChatListRemove(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpChatChannels : public PUdpMsgAnalyser { -private: - uint32_t mChannelFlags; // 1 bit per custom channel, starting from LSB, in same order as in chat i/f - -public: - PUdpChatChannels(PMsgDecodeData *nDecodeData); - //~PUdpChatChannels(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpChatLocal : public PUdpMsgAnalyser { +public: + PUdpChatLocal(PMsgDecodeData *nDecodeData); + //~PUdpChatLocal(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpChatGlobal : public PUdpMsgAnalyser { +public: + PUdpChatGlobal(PMsgDecodeData *nDecodeData); + //~PUdpChatGlobal(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpChatListAdd : public PUdpMsgAnalyser { +private: + uint8_t mChatList; // 1 = Direct, 2 = Buddy List + char *mAddedCharname; + +public: + PUdpChatListAdd(PMsgDecodeData *nDecodeData); + //~PUdpChatListAdd(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpChatListRemove : public PUdpMsgAnalyser { +private: + uint8_t mChatList; + uint32_t mRemovedCharID; + +public: + PUdpChatListRemove(PMsgDecodeData *nDecodeData); + //~PUdpChatListRemove(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpChatChannels : public PUdpMsgAnalyser { +private: + uint32_t mChannelFlags; // 1 bit per custom channel, starting from LSB, in same order as in chat i/f + +public: + PUdpChatChannels(PMsgDecodeData *nDecodeData); + //~PUdpChatChannels(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.cxx b/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.cxx index 4c17db7..5e2c629 100644 --- a/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.cxx @@ -1,76 +1,76 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -PUdpEntityPosRequest::PUdpEntityPosRequest(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - nDecodeData->mName << "/0x0b"; -} - -PUdpMsgAnalyser* PUdpEntityPosRequest::Analyse() -{ - mDecodeData->mName << "=Entity position request"; - -//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg -//mDecodeData->mTraceKnownMsg = true; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 7); - - *nMsg >> mEntityID; //(uint16_t ... or uint32_t ???) - - if(mEntityID >= WORLDDATATEMPLATE_MAXPOSITEMS) - { - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - mDecodeData->mErrorDetail = Ssprintf("Invalid position entity ID (%d)", mEntityID); - Console->Print("%s Client[%d] sent invalid position entity Id[%d]", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID); - mDecodeData->mTraceDump = true; - } - else - { - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - } - - return this; -} - -bool PUdpEntityPosRequest::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* nChar = nClient->GetChar(); - PWorld* currentWorld = Worlds->GetWorld(nChar->GetLocation()); - float fpX, fpY, fpZ; - uint16_t pX, pY, pZ; - - if(currentWorld) - { - if((mEntityID < WORLDDATATEMPLATE_MAXPOSITEMS) && currentWorld->getPositionItemPosition(mEntityID, &fpX, &fpY, &fpZ)) - { - pX = (uint16_t) (fpX + 32000); - pY = (uint16_t) (fpY + 32000); - pZ = (uint16_t) (fpZ + 32000); - -if(gDevDebug) Console->Print(GREEN, BLACK, "Client %d - Sending pos for entity %d : X=%d Y=%d Z=%d", mDecodeData->mClient->GetID(), mEntityID, pX, pY, pZ); - } - else if(!nClient->GetCharAwaitingWarpto(&pX, &pY, &pZ)) - { - pX = pY = pZ = 0; - Console->Print("%s Client[%d] requested invalid position entity %d. Position reset.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID); - } - - PMessage* tmpMsg; - tmpMsg = MsgBuilder->BuildEntityPositionMsg(nClient, pX, pY, pZ); - nClient->SendUDPMessage(tmpMsg); - (nChar->Coords).mY=pY; - (nChar->Coords).mZ=pZ; - (nChar->Coords).mX=pX; - } - else - { - Console->Print(RED, BLACK, "[Warning] PUdpEntityPosRequest - Invalid world (%d)", nChar->GetLocation()); - } -// if(IsRealMove && nClient->GetDebugMode(DBG_LOCATION)) - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +PUdpEntityPosRequest::PUdpEntityPosRequest(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + nDecodeData->mName << "/0x0b"; +} + +PUdpMsgAnalyser* PUdpEntityPosRequest::Analyse() +{ + mDecodeData->mName << "=Entity position request"; + +//mDecodeData->mTraceUnknownMsg = true; // temp stop being bugged with unknown move msg +//mDecodeData->mTraceKnownMsg = true; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset(mDecodeData->Sub0x13Start + 7); + + *nMsg >> mEntityID; //(uint16_t ... or uint32_t ???) + + if(mEntityID >= WORLDDATATEMPLATE_MAXPOSITEMS) + { + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + mDecodeData->mErrorDetail = Ssprintf("Invalid position entity ID (%d)", mEntityID); + Console->Print("%s Client[%d] sent invalid position entity Id[%d]", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID); + mDecodeData->mTraceDump = true; + } + else + { + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + } + + return this; +} + +bool PUdpEntityPosRequest::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* nChar = nClient->GetChar(); + PWorld* currentWorld = Worlds->GetWorld(nChar->GetLocation()); + float fpX, fpY, fpZ; + uint16_t pX, pY, pZ; + + if(currentWorld) + { + if((mEntityID < WORLDDATATEMPLATE_MAXPOSITEMS) && currentWorld->getPositionItemPosition(mEntityID, &fpX, &fpY, &fpZ)) + { + pX = (uint16_t) (fpX + 32000); + pY = (uint16_t) (fpY + 32000); + pZ = (uint16_t) (fpZ + 32000); + +if(gDevDebug) Console->Print(GREEN, BLACK, "Client %d - Sending pos for entity %d : X=%d Y=%d Z=%d", mDecodeData->mClient->GetID(), mEntityID, pX, pY, pZ); + } + else if(!nClient->GetCharAwaitingWarpto(&pX, &pY, &pZ)) + { + pX = pY = pZ = 0; + Console->Print("%s Client[%d] requested invalid position entity %d. Position reset.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mDecodeData->mClient->GetID(), mEntityID); + } + + PMessage* tmpMsg; + tmpMsg = MsgBuilder->BuildEntityPositionMsg(nClient, pX, pY, pZ); + nClient->SendUDPMessage(tmpMsg); + (nChar->Coords).mY=pY; + (nChar->Coords).mZ=pZ; + (nChar->Coords).mX=pX; + } + else + { + Console->Print(RED, BLACK, "[Warning] PUdpEntityPosRequest - Invalid world (%d)", nChar->GetLocation()); + } +// if(IsRealMove && nClient->GetDebugMode(DBG_LOCATION)) + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.hxx b/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.hxx index a483d36..7a50a76 100644 --- a/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpEntityPositionRequest.hxx @@ -1,15 +1,15 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpEntityPosRequest : public PUdpMsgAnalyser { -private: - uint16_t mEntityID; // u16 or u32 ??? - -public: - PUdpEntityPosRequest(PMsgDecodeData *nDecodeData); - //~PUdpEntityPosRequest(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpEntityPosRequest : public PUdpMsgAnalyser { +private: + uint16_t mEntityID; // u16 or u32 ??? + +public: + PUdpEntityPosRequest(PMsgDecodeData *nDecodeData); + //~PUdpEntityPosRequest(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpHack.hxx b/TinNS/Source/GameServer/Decoder/UdpHack.hxx index bf8eccb..0d79ee3 100644 --- a/TinNS/Source/GameServer/Decoder/UdpHack.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpHack.hxx @@ -1,19 +1,19 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpHackFail : public PUdpMsgAnalyser { -public: - PUdpHackFail(PMsgDecodeData *nDecodeData); - //~PUdpHackFail(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpHackSuccess : public PUdpMsgAnalyser { -public: - PUdpHackSuccess(PMsgDecodeData *nDecodeData); - //~PUdpHackSuccess(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpHackFail : public PUdpMsgAnalyser { +public: + PUdpHackFail(PMsgDecodeData *nDecodeData); + //~PUdpHackFail(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpHackSuccess : public PUdpMsgAnalyser { +public: + PUdpHackSuccess(PMsgDecodeData *nDecodeData); + //~PUdpHackSuccess(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpItemMove.cxx b/TinNS/Source/GameServer/Decoder/UdpItemMove.cxx index bd868ad..4ef1208 100644 --- a/TinNS/Source/GameServer/Decoder/UdpItemMove.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpItemMove.cxx @@ -1,268 +1,268 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdpItemMove ****/ - -#define PUdpItemMove_NO_BOX_TAKE_ALL - -PUdpItemMove::PUdpItemMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x1e"; -} - -PUdpMsgAnalyser* PUdpItemMove::Analyse() -{ - mDecodeData->mName << "=Moving item"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 ); - - *nMsg >> mSrcLoc; - *nMsg >> mSrcX; - *nMsg >> mSrcY; - *nMsg >> mDstLoc; - *nMsg >> mDstX; - *nMsg >> mDstY; - *nMsg >> mItemCnt; - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpItemMove::DoAction() -{ -//mDecodeData->mTraceDump = true; - PMessage* tmpMsg; - bool MoveSucceded = false; - PClient* nClient = mDecodeData->mClient; - PChar* tChar = nClient->GetChar(); - uint8_t origDstX = mDstX; - uint8_t origDstY = mDstY; - PContainerEntry* tEntry; - - PItem* tItem = NULL; - - PContainer* SrcContainer = GetContainerByLoc( tChar, mSrcLoc ); - if ( SrcContainer ) - { - tEntry = SrcContainer->GetEntry( mSrcX ); - tItem = SrcContainer->GetItem( mSrcX ); - if ( mSrcLoc != mDstLoc ) - { - PContainer* DstContainer = GetContainerByLoc( tChar, mDstLoc ); - if ( mSrcY ) - Console->Print( "%s PUdpItemMove: intramove: src Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) ); -#ifdef PUdpItemMove_NO_BOX_TAKE_ALL - if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) ) - { -#endif - if ( DstContainer ) - { - //PContainerEntry* tEntry = SrcContainer->GetEntry(mSrcX); - MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, DstContainer, mDstX, mDstX, mDstY ); - /*if(tEntry) - tEntry->Get2DPos(&mDstX, &mDstY);*/ - } -#ifdef PUdpItemMove_NO_BOX_TAKE_ALL - } -#endif - } - else - { - if ( mSrcY || mDstY ) - Console->Print( "%s PUdpItemMove: intramove: src Y or dst Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) ); - MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, mDstX ); - } - } - - if ( MoveSucceded ) - { - if (( mDstX == 255 ) && ( mDstY == 255 ) && ( mSrcLoc == INV_LOC_BOX ) ) - { - tmpMsg = MsgBuilder->BuildUndefineduseMsg( nClient, 0x2c ); - nClient->SendUDPMessage( tmpMsg ); - tmpMsg = MsgBuilder->BuildBoxItemMoveMsg( nClient, tEntry, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt ); - } - else - { - tmpMsg = MsgBuilder->BuildItemMoveMsg( nClient, mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt ); - } - nClient->SendUDPMessage( tmpMsg ); - - if ( gDevDebug ) - Console->Print( "%s Success : Item move %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" ); - /*Console->Print(YELLOW, BLACK, "--- Worn Inventory ---"); - tChar->GetInventory()->GetContainer(INV_LOC_WORN)->Dump(); - Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---"); - tChar->GetInventory()->GetContainer(INV_LOC_BACKPACK)->Dump(); - Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---"); - tChar->GetInventory()->GetContainer(INV_LOC_GOGO)->Dump(); - if (tChar->GetInventory()->IsDirty()) - Console->Print(YELLOW, BLACK, "Inventory DIRTY"); */ - -// => TO CHECK: deactivate item in-hand if active slot now emtpy ??? - } - else - { -#ifdef PUdpItemMove_NO_BOX_TAKE_ALL - if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) ) - { -#endif - if ( mDstLoc == INV_LOC_GROUND ) - Chat->send( nClient, CHAT_DIRECT, "System", "Can't throw items to the ground yet." ); - else - Console->Print( "%s Item move failed %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" ); - // Send 'null move' - //tmpMsg = MsgBuilder->BuildItemMoveMsg(nClient, mSrcLoc, mSrcX, mSrcY, mSrcLoc, mSrcX, mSrcY, mItemCnt); - //nClient->SendUDPMessage(tmpMsg); -#ifdef PUdpItemMove_NO_BOX_TAKE_ALL - } - else - { - Chat->send( nClient, CHAT_DIRECT, "System", "'TAKE ALL' can't be used yet." ); - } -#endif - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - -PContainer* PUdpItemMove::GetContainerByLoc( PChar* nChar, uint8_t nLoc ) -{ - PContainer* tContainer = NULL; - - switch ( nLoc ) - { - case INV_LOC_WORN: - case INV_LOC_BACKPACK: - case INV_LOC_GOGO: - { - tContainer = nChar->GetInventory()->GetContainer( nLoc ); - break; - } - - case INV_LOC_BOX: - { - tContainer = nChar->GetContainerInExclusiveUse(); - break; - } - case INV_LOC_GROUND: - case INV_LOC_NPCTRADE: - default: - break; - } - - return tContainer; -} - - -/**** PUdpItemMoveBP ****/ - -PUdpItemMoveBP::PUdpItemMoveBP( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x14"; -} - -PUdpMsgAnalyser* PUdpItemMoveBP::Analyse() -{ - mDecodeData->mName << "=Moving item"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 ); - - *nMsg >> mSrcSlotId; - *nMsg >> mDumb; - *nMsg >> mDstX; - *nMsg >> mDstY; - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpItemMoveBP::DoAction() -{ -//mDecodeData->mTraceDump = true; -// PMessage* tmpMsg; - bool MoveSucceded = false; - PClient* nClient = mDecodeData->mClient; - PChar* tChar = nClient->GetChar(); - - PContainer2DWorkaround* SrcContainer = tChar->GetInventory()->GetBackpackContainer(); - if ( SrcContainer ) - { - if ( mDumb ) - Console->Print( "%s PUdpItemMoveBP: Dumb != 0 (%d)", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mDumb ); - if ( gDevDebug ) - Console->Print( "%s PUdpItemMoveBP: Tyring Item move: slot %u => %u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcSlotId, mDstX, mDstY ); - PContainerEntry* tEntry = SrcContainer->GetEntry( mSrcSlotId ); - if ( tEntry ) - { - SrcContainer->SetUsed( tEntry, false ); - SrcContainer->SetEntryPosXY( tEntry, mSrcSlotId, mDstX, mDstY ); - SrcContainer->SetUsed( tEntry ); - SrcContainer->SetDirty(); - MoveSucceded = true; - } - else - Console->Print( "%s PUdpItemMoveBP: trying to use invalid slot %d", Console->ColorText( RED, BLACK, "[WARNING]" ), mSrcSlotId ); - } - else - { - Console->Print( "%s trying to use invalid Backpack container", Console->ColorText( RED, BLACK, "[WARNING]" ) ); - } -//Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---"); -//SrcContainer->Dump(); - -// No answer to confirm ? -//tmpMsg = NULL; - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - -/**** PUdpItemDropOnItem ****/ - -PUdpItemDropOnItem::PUdpItemDropOnItem( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x17"; -} - -PUdpMsgAnalyser* PUdpItemDropOnItem::Analyse() -{ - mDecodeData->mName << "=Dropping item on item"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 ); - - *nMsg >> mSrcLoc; - *nMsg >> mSrcX; // Linear Idx - *nMsg >> mSrcY; // 0 - *nMsg >> mDstLoc; - *nMsg >> mDstX; // Linear Idx - *nMsg >> mDstY; // 0 - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpItemDropOnItem::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* tChar = nClient->GetChar(); - if ( gDevDebug ) - Console->Print( "%s PUdpItemDropOnItem: %u:%u-%u => %u:%u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY ); - PContainer* SrcContainer = PUdpItemMove::GetContainerByLoc( tChar, mSrcLoc ); - PContainer* DstContainer = PUdpItemMove::GetContainerByLoc( tChar, mDstLoc ); - if ( SrcContainer && DstContainer ) - { - PItem* sItem = SrcContainer->GetItem( mSrcX ); - PItem* dItem = DstContainer->GetItem( mDstX ); - - if ( gDevDebug ) - Console->Print( "%s Drop item %s on %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), sItem ? sItem->GetName().c_str() : "???", dItem ? dItem->GetName().c_str() : "???" ); - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdpItemMove ****/ + +#define PUdpItemMove_NO_BOX_TAKE_ALL + +PUdpItemMove::PUdpItemMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x1e"; +} + +PUdpMsgAnalyser* PUdpItemMove::Analyse() +{ + mDecodeData->mName << "=Moving item"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 8 ); + + *nMsg >> mSrcLoc; + *nMsg >> mSrcX; + *nMsg >> mSrcY; + *nMsg >> mDstLoc; + *nMsg >> mDstX; + *nMsg >> mDstY; + *nMsg >> mItemCnt; + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpItemMove::DoAction() +{ +//mDecodeData->mTraceDump = true; + PMessage* tmpMsg; + bool MoveSucceded = false; + PClient* nClient = mDecodeData->mClient; + PChar* tChar = nClient->GetChar(); + uint8_t origDstX = mDstX; + uint8_t origDstY = mDstY; + PContainerEntry* tEntry; + + PItem* tItem = NULL; + + PContainer* SrcContainer = GetContainerByLoc( tChar, mSrcLoc ); + if ( SrcContainer ) + { + tEntry = SrcContainer->GetEntry( mSrcX ); + tItem = SrcContainer->GetItem( mSrcX ); + if ( mSrcLoc != mDstLoc ) + { + PContainer* DstContainer = GetContainerByLoc( tChar, mDstLoc ); + if ( mSrcY ) + Console->Print( "%s PUdpItemMove: intramove: src Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) ); +#ifdef PUdpItemMove_NO_BOX_TAKE_ALL + if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) ) + { +#endif + if ( DstContainer ) + { + //PContainerEntry* tEntry = SrcContainer->GetEntry(mSrcX); + MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, DstContainer, mDstX, mDstX, mDstY ); + /*if(tEntry) + tEntry->Get2DPos(&mDstX, &mDstY);*/ + } +#ifdef PUdpItemMove_NO_BOX_TAKE_ALL + } +#endif + } + else + { + if ( mSrcY || mDstY ) + Console->Print( "%s PUdpItemMove: intramove: src Y or dst Y != 0", Console->ColorText( YELLOW, BLACK, "[WARNING]" ) ); + MoveSucceded = SrcContainer->MoveItem( mSrcX, mItemCnt, mDstX ); + } + } + + if ( MoveSucceded ) + { + if (( mDstX == 255 ) && ( mDstY == 255 ) && ( mSrcLoc == INV_LOC_BOX ) ) + { + tmpMsg = MsgBuilder->BuildUndefineduseMsg( nClient, 0x2c ); + nClient->SendUDPMessage( tmpMsg ); + tmpMsg = MsgBuilder->BuildBoxItemMoveMsg( nClient, tEntry, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt ); + } + else + { + tmpMsg = MsgBuilder->BuildItemMoveMsg( nClient, mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY, mItemCnt ); + } + nClient->SendUDPMessage( tmpMsg ); + + if ( gDevDebug ) + Console->Print( "%s Success : Item move %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" ); + /*Console->Print(YELLOW, BLACK, "--- Worn Inventory ---"); + tChar->GetInventory()->GetContainer(INV_LOC_WORN)->Dump(); + Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---"); + tChar->GetInventory()->GetContainer(INV_LOC_BACKPACK)->Dump(); + Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---"); + tChar->GetInventory()->GetContainer(INV_LOC_GOGO)->Dump(); + if (tChar->GetInventory()->IsDirty()) + Console->Print(YELLOW, BLACK, "Inventory DIRTY"); */ + +// => TO CHECK: deactivate item in-hand if active slot now emtpy ??? + } + else + { +#ifdef PUdpItemMove_NO_BOX_TAKE_ALL + if (( mSrcLoc != INV_LOC_BOX ) || ( mDstX != 255 ) || ( mDstY != 255 ) ) + { +#endif + if ( mDstLoc == INV_LOC_GROUND ) + Chat->send( nClient, CHAT_DIRECT, "System", "Can't throw items to the ground yet." ); + else + Console->Print( "%s Item move failed %u:%u-%u => %u:%u-%u : %u %s", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, origDstX, origDstY, mItemCnt, tItem ? tItem->GetName().c_str() : "" ); + // Send 'null move' + //tmpMsg = MsgBuilder->BuildItemMoveMsg(nClient, mSrcLoc, mSrcX, mSrcY, mSrcLoc, mSrcX, mSrcY, mItemCnt); + //nClient->SendUDPMessage(tmpMsg); +#ifdef PUdpItemMove_NO_BOX_TAKE_ALL + } + else + { + Chat->send( nClient, CHAT_DIRECT, "System", "'TAKE ALL' can't be used yet." ); + } +#endif + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + +PContainer* PUdpItemMove::GetContainerByLoc( PChar* nChar, uint8_t nLoc ) +{ + PContainer* tContainer = NULL; + + switch ( nLoc ) + { + case INV_LOC_WORN: + case INV_LOC_BACKPACK: + case INV_LOC_GOGO: + { + tContainer = nChar->GetInventory()->GetContainer( nLoc ); + break; + } + + case INV_LOC_BOX: + { + tContainer = nChar->GetContainerInExclusiveUse(); + break; + } + case INV_LOC_GROUND: + case INV_LOC_NPCTRADE: + default: + break; + } + + return tContainer; +} + + +/**** PUdpItemMoveBP ****/ + +PUdpItemMoveBP::PUdpItemMoveBP( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x14"; +} + +PUdpMsgAnalyser* PUdpItemMoveBP::Analyse() +{ + mDecodeData->mName << "=Moving item"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 ); + + *nMsg >> mSrcSlotId; + *nMsg >> mDumb; + *nMsg >> mDstX; + *nMsg >> mDstY; + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpItemMoveBP::DoAction() +{ +//mDecodeData->mTraceDump = true; +// PMessage* tmpMsg; + bool MoveSucceded = false; + PClient* nClient = mDecodeData->mClient; + PChar* tChar = nClient->GetChar(); + + PContainer2DWorkaround* SrcContainer = tChar->GetInventory()->GetBackpackContainer(); + if ( SrcContainer ) + { + if ( mDumb ) + Console->Print( "%s PUdpItemMoveBP: Dumb != 0 (%d)", Console->ColorText( YELLOW, BLACK, "[WARNING]" ), mDumb ); + if ( gDevDebug ) + Console->Print( "%s PUdpItemMoveBP: Tyring Item move: slot %u => %u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcSlotId, mDstX, mDstY ); + PContainerEntry* tEntry = SrcContainer->GetEntry( mSrcSlotId ); + if ( tEntry ) + { + SrcContainer->SetUsed( tEntry, false ); + SrcContainer->SetEntryPosXY( tEntry, mSrcSlotId, mDstX, mDstY ); + SrcContainer->SetUsed( tEntry ); + SrcContainer->SetDirty(); + MoveSucceded = true; + } + else + Console->Print( "%s PUdpItemMoveBP: trying to use invalid slot %d", Console->ColorText( RED, BLACK, "[WARNING]" ), mSrcSlotId ); + } + else + { + Console->Print( "%s trying to use invalid Backpack container", Console->ColorText( RED, BLACK, "[WARNING]" ) ); + } +//Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---"); +//SrcContainer->Dump(); + +// No answer to confirm ? +//tmpMsg = NULL; + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + +/**** PUdpItemDropOnItem ****/ + +PUdpItemDropOnItem::PUdpItemDropOnItem( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x17"; +} + +PUdpMsgAnalyser* PUdpItemDropOnItem::Analyse() +{ + mDecodeData->mName << "=Dropping item on item"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 9 ); + + *nMsg >> mSrcLoc; + *nMsg >> mSrcX; // Linear Idx + *nMsg >> mSrcY; // 0 + *nMsg >> mDstLoc; + *nMsg >> mDstX; // Linear Idx + *nMsg >> mDstY; // 0 + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpItemDropOnItem::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* tChar = nClient->GetChar(); + if ( gDevDebug ) + Console->Print( "%s PUdpItemDropOnItem: %u:%u-%u => %u:%u-%u", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mSrcLoc, mSrcX, mSrcY, mDstLoc, mDstX, mDstY ); + PContainer* SrcContainer = PUdpItemMove::GetContainerByLoc( tChar, mSrcLoc ); + PContainer* DstContainer = PUdpItemMove::GetContainerByLoc( tChar, mDstLoc ); + if ( SrcContainer && DstContainer ) + { + PItem* sItem = SrcContainer->GetItem( mSrcX ); + PItem* dItem = DstContainer->GetItem( mDstX ); + + if ( gDevDebug ) + Console->Print( "%s Drop item %s on %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), sItem ? sItem->GetName().c_str() : "???", dItem ? dItem->GetName().c_str() : "???" ); + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpItemMove.hxx b/TinNS/Source/GameServer/Decoder/UdpItemMove.hxx index 4cbd9cf..e19adab 100644 --- a/TinNS/Source/GameServer/Decoder/UdpItemMove.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpItemMove.hxx @@ -1,55 +1,55 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PContainer; - -class PUdpItemMove : public PUdpMsgAnalyser { -private: - uint8_t mSrcLoc; - uint8_t mSrcX; - uint8_t mSrcY; - uint8_t mDstLoc; - uint8_t mDstX; - uint8_t mDstY; - uint8_t mItemCnt; - -public: - PUdpItemMove(PMsgDecodeData *nDecodeData); - //~PUdpItemMove(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - - static PContainer *GetContainerByLoc(PChar *nChar, uint8_t nLoc); -}; - -class PUdpItemMoveBP : public PUdpMsgAnalyser { -private: - uint8_t mSrcSlotId; - uint8_t mDumb; - uint8_t mDstX; - uint8_t mDstY; - -public: - PUdpItemMoveBP(PMsgDecodeData *nDecodeData); - //~PUdpItemMove(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpItemDropOnItem : public PUdpMsgAnalyser { -private: - uint8_t mSrcLoc; - uint8_t mSrcX; - uint8_t mSrcY; - uint8_t mDstLoc; - uint8_t mDstX; - uint8_t mDstY; - -public: - PUdpItemDropOnItem(PMsgDecodeData *nDecodeData); - //~PUdpItemDropOnItem(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PContainer; + +class PUdpItemMove : public PUdpMsgAnalyser { +private: + uint8_t mSrcLoc; + uint8_t mSrcX; + uint8_t mSrcY; + uint8_t mDstLoc; + uint8_t mDstX; + uint8_t mDstY; + uint8_t mItemCnt; + +public: + PUdpItemMove(PMsgDecodeData *nDecodeData); + //~PUdpItemMove(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + + static PContainer *GetContainerByLoc(PChar *nChar, uint8_t nLoc); +}; + +class PUdpItemMoveBP : public PUdpMsgAnalyser { +private: + uint8_t mSrcSlotId; + uint8_t mDumb; + uint8_t mDstX; + uint8_t mDstY; + +public: + PUdpItemMoveBP(PMsgDecodeData *nDecodeData); + //~PUdpItemMove(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpItemDropOnItem : public PUdpMsgAnalyser { +private: + uint8_t mSrcLoc; + uint8_t mSrcX; + uint8_t mSrcY; + uint8_t mDstLoc; + uint8_t mDstX; + uint8_t mDstY; + +public: + PUdpItemDropOnItem(PMsgDecodeData *nDecodeData); + //~PUdpItemDropOnItem(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpOOO.cxx b/TinNS/Source/GameServer/Decoder/UdpOOO.cxx index 5be7d73..7012fc5 100644 --- a/TinNS/Source/GameServer/Decoder/UdpOOO.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpOOO.cxx @@ -1,29 +1,29 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdpOOO ****/ - -PUdpOOO::PUdpOOO(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) -{ - nDecodeData->mName << "/0x01"; -} - -PUdpMsgAnalyser* PUdpOOO::Analyse() -{ - mDecodeData->mName << "=Out Of Order"; - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - - return this; -} - -bool PUdpOOO::DoAction() -{ - uint16_t MissingUDP_ID = mDecodeData->mMessage->U16Data(mDecodeData->Sub0x13Start+5); - - mDecodeData->mClient->getUDPConn()->ReSendUDPMessage(MissingUDP_ID); - //Console->Print("%s Out of Order packet received ! (Client is missing UDPID %d) ***not managed yet***", Console->ColorText(YELLOW, BLACK, "[Notice]"), MissingUDP_ID); - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdpOOO ****/ + +PUdpOOO::PUdpOOO(PMsgDecodeData* nDecodeData) : PUdpMsgAnalyser(nDecodeData) +{ + nDecodeData->mName << "/0x01"; +} + +PUdpMsgAnalyser* PUdpOOO::Analyse() +{ + mDecodeData->mName << "=Out Of Order"; + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + + return this; +} + +bool PUdpOOO::DoAction() +{ + uint16_t MissingUDP_ID = mDecodeData->mMessage->U16Data(mDecodeData->Sub0x13Start+5); + + mDecodeData->mClient->getUDPConn()->ReSendUDPMessage(MissingUDP_ID); + //Console->Print("%s Out of Order packet received ! (Client is missing UDPID %d) ***not managed yet***", Console->ColorText(YELLOW, BLACK, "[Notice]"), MissingUDP_ID); + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpOOO.hxx b/TinNS/Source/GameServer/Decoder/UdpOOO.hxx index 89c759c..edf0b02 100644 --- a/TinNS/Source/GameServer/Decoder/UdpOOO.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpOOO.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpOOO : public PUdpMsgAnalyser { -public: - PUdpOOO(PMsgDecodeData *nDecodeData); - //~PUdpPing(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpOOO : public PUdpMsgAnalyser { +public: + PUdpOOO(PMsgDecodeData *nDecodeData); + //~PUdpPing(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpPacket0.hxx b/TinNS/Source/GameServer/Decoder/UdpPacket0.hxx index 688815a..b21a36d 100644 --- a/TinNS/Source/GameServer/Decoder/UdpPacket0.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpPacket0.hxx @@ -1,11 +1,11 @@ -#pragma once - -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpPacket0 : public PUdpMsgAnalyser { -public: - PUdpPacket0(PMsgDecodeData *nDecodeData); - //~PUdpPacket0(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpPacket0 : public PUdpMsgAnalyser { +public: + PUdpPacket0(PMsgDecodeData *nDecodeData); + //~PUdpPacket0(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpPing.hxx b/TinNS/Source/GameServer/Decoder/UdpPing.hxx index fdea776..3427baf 100644 --- a/TinNS/Source/GameServer/Decoder/UdpPing.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpPing.hxx @@ -1,14 +1,14 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpPing : public PUdpMsgAnalyser { -private: - uint32_t mClientTime; - -public: - PUdpPing(PMsgDecodeData *nDecodeData); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpPing : public PUdpMsgAnalyser { +private: + uint32_t mClientTime; + +public: + PUdpPing(PMsgDecodeData *nDecodeData); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpQuickAccessBelt.hxx b/TinNS/Source/GameServer/Decoder/UdpQuickAccessBelt.hxx index 0f47787..dc389d1 100644 --- a/TinNS/Source/GameServer/Decoder/UdpQuickAccessBelt.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpQuickAccessBelt.hxx @@ -1,15 +1,15 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpItemSlotUse : public PUdpMsgAnalyser { -private: - uint8_t mTargetSlot; - -public: - PUdpItemSlotUse(PMsgDecodeData *nDecodeData); - //~PUdpItemSlotUse(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpItemSlotUse : public PUdpMsgAnalyser { +private: + uint8_t mTargetSlot; + +public: + PUdpItemSlotUse(PMsgDecodeData *nDecodeData); + //~PUdpItemSlotUse(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpRequestInfo.hxx b/TinNS/Source/GameServer/Decoder/UdpRequestInfo.hxx index 5e3163f..3218035 100644 --- a/TinNS/Source/GameServer/Decoder/UdpRequestInfo.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpRequestInfo.hxx @@ -1,16 +1,16 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpReqInfo : public PUdpMsgAnalyser { -private: - uint16_t mRequestType; - uint32_t mInfoId; - -public: - PUdpReqInfo(PMsgDecodeData *nDecodeData); - //~PUdpCharInfo(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpReqInfo : public PUdpMsgAnalyser { +private: + uint16_t mRequestType; + uint32_t mInfoId; + +public: + PUdpReqInfo(PMsgDecodeData *nDecodeData); + //~PUdpCharInfo(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpSubSkill.hxx b/TinNS/Source/GameServer/Decoder/UdpSubSkill.hxx index 4d1e394..eb4b28e 100644 --- a/TinNS/Source/GameServer/Decoder/UdpSubSkill.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpSubSkill.hxx @@ -1,15 +1,15 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpSubskillInc : public PUdpMsgAnalyser { -private: - uint16_t SubskillID; - -public: - PUdpSubskillInc(PMsgDecodeData *nDecodeData); - //~PUdpSubskillInc(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpSubskillInc : public PUdpMsgAnalyser { +private: + uint16_t SubskillID; + +public: + PUdpSubskillInc(PMsgDecodeData *nDecodeData); + //~PUdpSubskillInc(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpSync.hxx b/TinNS/Source/GameServer/Decoder/UdpSync.hxx index 8841d52..1ef9a85 100644 --- a/TinNS/Source/GameServer/Decoder/UdpSync.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpSync.hxx @@ -1,33 +1,33 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpSync0 : public PUdpMsgAnalyser { -public: - PUdpSync0(PMsgDecodeData *nDecodeData); - //~PUdpSync0(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - - static void GetToSync1(PMsgDecodeData *nDecodeData); -}; - -class PUdpSync1 : public PUdpMsgAnalyser { -public: - PUdpSync1(PMsgDecodeData *nDecodeData); - //~PUdpSync1(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpSync2 : public PUdpMsgAnalyser { -private: - uint32_t mClientTime; - -public: - PUdpSync2(PMsgDecodeData *nDecodeData); - //~PUdpSync2(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpSync0 : public PUdpMsgAnalyser { +public: + PUdpSync0(PMsgDecodeData *nDecodeData); + //~PUdpSync0(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + + static void GetToSync1(PMsgDecodeData *nDecodeData); +}; + +class PUdpSync1 : public PUdpMsgAnalyser { +public: + PUdpSync1(PMsgDecodeData *nDecodeData); + //~PUdpSync1(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpSync2 : public PUdpMsgAnalyser { +private: + uint32_t mClientTime; + +public: + PUdpSync2(PMsgDecodeData *nDecodeData); + //~PUdpSync2(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpTerminal.cxx b/TinNS/Source/GameServer/Decoder/UdpTerminal.cxx index 486c63a..004f7ba 100644 --- a/TinNS/Source/GameServer/Decoder/UdpTerminal.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpTerminal.cxx @@ -1,581 +1,581 @@ -#include -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -/*******************************************************************************************/ -/**** PUdpReceiveDB ****/ -/*******************************************************************************************/ -PUdpReceiveDB::PUdpReceiveDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x17"; - mOptionsCount = 0; -} - -PUdpMsgAnalyser* PUdpReceiveDB::Analyse() -{ - PMessage* TmpMsg = mDecodeData->mMessage; - uint16_t Unknown3, OptionSize; - - mDecodeData->mName << "=ReceiveDB request from client"; - - mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); - TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 ); - ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is - ( *TmpMsg ) >> mUnknown1; // command name size - ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is! - ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options! - ( *TmpMsg ) >> mCommandName; // null terminated string - - - while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) - { - ( *TmpMsg ) >> OptionSize; - if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) - { - ( *TmpMsg ) >> mOptions[mOptionsCount++]; - //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! - } - else - { - break; - } - } - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpReceiveDB::DoAction() -{ - //PMessage* tmpMsg; - //PClient* tClient = mDecodeData->mClient; - //PChar* tChar = tClient->GetChar(); - bool Result = false; - - if ( gDevDebug ) - { - Console->Print( "%s ReceiveDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - Console->Print( "%s Open Terminal - Terminal session %04x (?) - Unknown1 %04x - DBId %04x - Unknown2 %02x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId, mUnknown1, mDBId, mUnknown2 ); - Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() ); - for ( uint8_t i = 0; i < mOptionsCount; ++i ) - Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() ); - } - - if ( mCommandName == "VehicleListing" ) - { - Result = ActionVehicleListing(); - } - else if ( mCommandName == "VehicleControl" ) - { - Result = ActionVehicleControl(); - } - else - { - // Let Terminal try before error - Result = Terminal->HandleReceiveDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2); - } - - if ( !Result ) - { - Console->Print( "%s PUdpReceiveDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() ); - for ( uint8_t i = 0; i < mOptionsCount; ++i ) - Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return Result; -} - -bool PUdpReceiveDB::ActionVehicleListing() -{ - PMessage* tmpMsg; - PClient* tClient = mDecodeData->mClient; - PChar* tChar = tClient->GetChar(); - - if ( mOptionsCount == 3 ) // CharId, StartVhcEntry, MaxVhcEntries - { - if ((( uint32_t )atol( mOptions[0].c_str() ) ) != tChar->GetID() ) - { - // Err: invalid CharId. Can alert, But we don't care :-) (except if used for other terminal function) - } - // !!! some more check/regex on values to do before using !!! - uint16_t StartIndex = atoi( mOptions[1].c_str() ); - uint16_t MaxEntries = atoi( mOptions[2].c_str() ); - - uint8_t nStatus = 1; - uint16_t nErrcode = 0; - - tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); - tClient->SendUDPMessage( tmpMsg ); - - PVhcInfoList* VhcList = Vehicles->GetCharVehicles( tChar->GetID(), MaxEntries, StartIndex ); - if ( ! VhcList->empty() ) - { - uint16_t NumEntries = VhcList->size(); - std::string* Answer = new std::string[4 * NumEntries]; - uint16_t Index = 0; - PVehicleInformation* EntryInfo; -//Console->Print("VHc entries : %d", NumEntries); - - while ( ! VhcList->empty() ) - { - EntryInfo = VhcList->front(); - VhcList->pop(); - Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleId() ); //vhcId - Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleType() ); //vhcType - Answer[Index++] = Ssprintf( "%u", EntryInfo->GetStatus() ); //vhcStatus 0:parking, 1:in_service, 2:destroyed - Answer[Index++] = Ssprintf( "%u", EntryInfo->GetHealth() ); //vhcHealth% -//Console->Print("Entry: %s/%s/%s/%s", Answer[Index-4].c_str(), Answer[Index-3].c_str(), Answer[Index-2].c_str(), Answer[Index-1].c_str()); - delete EntryInfo; - } - - tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, NumEntries, 4 ); - tClient->SendUDPMessage( tmpMsg ); - delete [] Answer; - } - delete VhcList; - - return true; - } - else - return false; - /* - // Option1=CharId, Option2=resultEntryStart, Option3=maxResultEntries - S=> 03/2b/1a VehicleListing+0 - 13 2a 00 7c be 19 - 03 2a 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .*.+......Vehicl - 65 4c 69 73 74 69 6e 67 00 eListing. - S=> 03/2b/17 0f 00 08 00 04 00 <0f 00><04 00> - VehicleListing+0 - - - (val: 0=stored) - (val: 0-255) - == - 03/2b/17 0f 00 01 00 04 00 <0f 00><04 00> - 31 - 03 54 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 4c 69 73 74 .....VehicleList - 69 6e 67 00 06 00 32 35 32 37 37 00 03 00 36 30 ing...25277...60 - 00 02 00 30 00 04 00 32 35 35 00 ...0...255. - */ -} - -bool PUdpReceiveDB::ActionVehicleControl() -{ - PMessage* tmpMsg; - PClient* tClient = mDecodeData->mClient; - - if ( mOptionsCount == 2 ) // VhcId, CharId - { - // !!! validate values !!! - uint8_t nStatus = 1; - uint16_t nErrcode = 0; - - tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); - tClient->SendUDPMessage( tmpMsg ); - - uint32_t VhcId = ( uint32_t )atol( mOptions[0].c_str() ); - PVehicleInformation EntryInfo; - if ( Vehicles->GetVehicleInfo( VhcId, &EntryInfo ) ) - { - std::string* Answer = new std::string[4]; - Answer[0] = Ssprintf( "%u", EntryInfo.GetVehicleType() ); //vhcType - Answer[1] = Ssprintf( "%u", EntryInfo.GetStatus() ); //vhcStatus - Answer[2] = Ssprintf( "%u", EntryInfo.GetHealth() ); //vhcHealth% - Answer[3] = Ssprintf( "%u", ( 255 - EntryInfo.GetHealth() ) * 1000 * EntryInfo.GetVehicleType() / 255 ); //Repair cost - if ( gDevDebug ) - Console->Print( "%s Entry: %s/%s/%s/%s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Answer[0].c_str(), Answer[1].c_str(), Answer[2].c_str(), Answer[3].c_str() ); - tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, 1, 4 ); - tClient->SendUDPMessage( tmpMsg ); - delete [] Answer; - } - return true; - } - else - return false; - /* - // Option1=VhcId, Option2=CharId - S=> 03/2b/1a VehicleControl - 13 77 00 c9 be 19 - 03 76 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .v.+......Vehicl - 65 43 6f 6e 74 72 6f 6c 00 eControl. - S=> 03/2b/17 0f 00 01 00 04 00 VehicleControl 4 0 255 4255( - 2f - 03 77 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 43 6f 6e 74 .....VehicleCont - 72 6f 6c 00 02 00 34 00 02 00 30 00 04 00 32 35 rol...4...0...25 - 35 00 05 00 34 32 35 35 00 5...4255. - */ -} - -/*******************************************************************************************/ -/**** PUdpUpdateDB ****/ -/*******************************************************************************************/ -PUdpUpdateDB::PUdpUpdateDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x18"; - mOptionsCount = 0; -} - -PUdpMsgAnalyser* PUdpUpdateDB::Analyse() -{ - PMessage* TmpMsg = mDecodeData->mMessage; - uint16_t Unknown3, OptionSize; - - mDecodeData->mName << "=UpdateDB request from client"; - - mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); - TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 ); - ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is - ( *TmpMsg ) >> mUnknown1; // command name size - ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is! - ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options! - ( *TmpMsg ) >> mCommandName; // null terminated string - - - while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) - { - ( *TmpMsg ) >> OptionSize; - if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) - { - ( *TmpMsg ) >> mOptions[mOptionsCount++]; - //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! - } - else - { - break; - } - } - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpUpdateDB::DoAction() -{ - if ( gDevDebug ) - { - Console->Print( "%s UpdateDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId ); - Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() ); - for ( uint8_t i = 0; i < mOptionsCount; ++i ) - Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() ); - } - bool Result = false; - Result = Terminal->HandleUpdateDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2); - - if ( !Result ) - { - Console->Print( "%s PUdpUpdateDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() ); - for ( uint8_t i = 0; i < mOptionsCount; ++i ) - Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() ); - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} -/*******************************************************************************************/ -/**** PUdpTryAccessDB ****/ -/*******************************************************************************************/ -PUdpTryAccessDB::PUdpTryAccessDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x19"; - mOptionsCount = 0; -} - -PUdpMsgAnalyser* PUdpTryAccessDB::Analyse() -{ - PMessage* TmpMsg = mDecodeData->mMessage; - uint16_t Unknown3, OptionSize; - - mDecodeData->mName << "=TryAccess request from client"; - - mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); - TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 ); - ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is - ( *TmpMsg ) >> mUnknown1; // command name size - ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is! - ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options! - ( *TmpMsg ) >> mCommandName; // null terminated string - - while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) - { - ( *TmpMsg ) >> OptionSize; - if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) - { - ( *TmpMsg ) >> mOptions[mOptionsCount++]; - //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! - } - else - { - break; - } - } - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpTryAccessDB::DoAction() -{ - // Let the terminal class handle the request - Terminal->HandleTryAccess(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2); - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} -/*******************************************************************************************/ -/**** PUdpQueryDB ****/ -/*******************************************************************************************/ -PUdpQueryDB::PUdpQueryDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x1b"; - mOptionsCount = 0; -} - -PUdpMsgAnalyser* PUdpQueryDB::Analyse() -{ - PMessage* TmpMsg = mDecodeData->mMessage; - uint16_t OptionSize; - - mDecodeData->mName << "=QueryDB request from client"; - - mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); - TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 18 ); - ( *TmpMsg ) >> OptionSize; // Size of data - ( *TmpMsg ) >> OptionSize; // Size of DB Command Name - if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) - { - ( *TmpMsg ) >> mDBCommandName; - } - ( *TmpMsg ) >> OptionSize; // Size of Command Name - if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) - { - ( *TmpMsg ) >> mCommandName; // null terminated string - } - - while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) - { - ( *TmpMsg ) >> OptionSize; - if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) - { - ( *TmpMsg ) >> mOptions[mOptionsCount++]; - //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! - } - else - { - break; - } - } - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpQueryDB::DoAction() -{ - //PMessage* tmpMsg; - //PClient* tClient = mDecodeData->mClient; - bool Result = false; - - if ( gDevDebug ) - { - Console->Print( "%s QueryDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId ); - Console->Print( "%s DBCommand: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDBCommandName.c_str() ); - Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() ); - for ( uint8_t i = 0; i < mOptionsCount; ++i ) - Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() ); - } - - if ( mDBCommandName == "SPAWNVEHICLE" ) - { - Result = ActionSpawnVehicle(); - } - else if ( mDBCommandName == "REPAIRVEHICLE" ) - { - Result = ActionRepairVehicle(); - } - else if ( mDBCommandName == "DISMISSVEHICLE" ) - { - Result = ActionDismissVehicle(); - } - else - { - // Let Terminal try before error - Result = Terminal->HandleQueryDB(mDecodeData->mClient, &mDBCommandName, &mCommandName, mOptions, mOptionsCount); - } - - if ( !Result ) - { - Console->Print( "%s PUdpQueryDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mDBCommandName.c_str() ); - for ( uint8_t i = 0; i < mOptionsCount; ++i ) - Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return Result; -} - -bool PUdpQueryDB::ActionSpawnVehicle() -{ - PMessage* tmpMsg; - PClient* tClient = mDecodeData->mClient; - PChar* tChar = tClient->GetChar(); - - if ( mOptionsCount == 3 ) // 0, VhcId, CharId - { - uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() ); - //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str()); - // !!! validate values !!! - // !!! + check CharId = current char && CharId is owner of VhcId - uint8_t nStatus = 1; // 1=OK, 0=Err - uint16_t nErrcode = 16; // 0=n/a 16=Already Spawned // MsdId = 2500+nErrcode [MISC] - - tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); - tClient->SendUDPMessage( tmpMsg ); - - PVhcCoordinates NewPosition; - PWorld* CurrentWorld = Worlds->GetWorld( tChar->GetLocation() ); - bool relativePos = false; - if ( tChar->GetLastUsedObject() && !WorldActors->IsDynamicActor( tChar->GetLastUsedObject() ) && CurrentWorld ) - { - const PFurnitureItemTemplate* tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( tChar->GetLastUsedObject() / 1024 - 1 ); - if ( tFurnitureTemplate && ( tFurnitureTemplate->GetFunctionType() == 28 ) ) // vhc term - { - float decal = 1000; // distance at which to spawn the vhc - float nPosX, nPosY, nPosZ; - tFurnitureTemplate->GetPos( &nPosX, &nPosY, &nPosZ ); - nPosX += 32000; - nPosY += 32000; - float dX = ( tChar->Coords.mX - nPosX ); - float dY = ( tChar->Coords.mY - nPosY ); - float d = decal / sqrt( dX * dX + dY * dY ); - NewPosition.SetPosition( static_cast( nPosY + d * dY ), ( tChar->Coords ).mZ + 100, static_cast( nPosX + d * dX ), ( tChar->Coords ).mUD, 34683, 32403 ); - relativePos = true; - } - } - - if( ! relativePos ) - NewPosition.SetPosition(( tChar->Coords ).mY, ( tChar->Coords ).mZ + 150, ( tChar->Coords ).mX, ( tChar->Coords ).mUD, 34683, 32403 ); - - PSpawnedVehicle* NewVhc = Vehicles->SpawnVehicle( VhcId, tChar->GetLocation(), &NewPosition ); - if ( NewVhc ) - { - tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( NewVhc ); - ClientManager->UDPBroadcast( tmpMsg, tChar->GetLocation() ); - } - - return true; - } - else - return false; -} - -bool PUdpQueryDB::ActionRepairVehicle() -{ - PMessage* tmpMsg; - PClient* tClient = mDecodeData->mClient; - - if ( mOptionsCount == 3 ) // 0, VhcId, CharId - { - //uint32_t VhcId = (uint32_t)atol(mOptions[1].c_str()); - //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str()); - // !!! validate values !!! - - uint8_t nStatus = 1; // 1=OK, 0=Err - uint16_t nErrcode = 18; // 0=n/a 18=Still Spawned, 19=Not enough money - - tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); - tClient->SendUDPMessage( tmpMsg ); - - // Action here - - return true; - } - else - return false; -} - -bool PUdpQueryDB::ActionDismissVehicle() -{ - PMessage* tmpMsg; - PClient* tClient = mDecodeData->mClient; - //PChar* tChar = tClient->GetChar(); - bool Result = false; - - if ( mOptionsCount == 3 ) // 0, VhcId, CharId - { - uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() ); - //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str()); - // !!! validate values !!! - // !!! + check CharId = current char && CharId is owner of VjhcId - // !!! Check vhc empty - uint8_t nStatus = 0; // 1=OK, 0=Err - uint16_t nErrcode = 17; // 0=n/a 17=Not Spawned - PVehicleInformation nInfo; - uint32_t tLocalId = 0; - uint32_t tLocation = 0; - - PSpawnedVehicle* tVhc = Vehicles->GetSpawnedVehicle( VhcId ); - if ( tVhc ) - { - tLocalId = tVhc->GetLocalId(); - tLocation = tVhc->GetLocation(); - uint32_t tCharId; - PChar* tChar; - for ( uint8_t i = 0; i < tVhc->GetNumSeats(); ++i ) - { - if (( tCharId = tVhc->GetSeatUser( i ) ) ) - { - if (( tChar = Chars->GetChar( tCharId ) ) ) - { - PUdpCharExitChair::DoLeaveChair( tChar, NULL, tVhc ); - } - } - } - Result = Vehicles->UnspawnVehicle( VhcId ); - } - - if ( Result ) - { - nStatus = 1; - nErrcode = 0; - } - tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); - tClient->SendUDPMessage( tmpMsg ); - - if ( Result ) - { - tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( tLocalId ); - ClientManager->UDPBroadcast( tmpMsg, tLocation ); - } - return true; - } - else - return false; -} - -/*******************************************************************************************/ -/**** PUdpTeminal0x1f ****/ -/*******************************************************************************************/ -PUdpTeminal0x1f::PUdpTeminal0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x1f"; -} - -PUdpMsgAnalyser* PUdpTeminal0x1f::Analyse() -{ - mDecodeData->mName << "=Open Terminal"; - mTerminalSessionId = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 ); - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpTeminal0x1f::DoAction() -{ - if ( gDevDebug ) - Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +/*******************************************************************************************/ +/**** PUdpReceiveDB ****/ +/*******************************************************************************************/ +PUdpReceiveDB::PUdpReceiveDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x17"; + mOptionsCount = 0; +} + +PUdpMsgAnalyser* PUdpReceiveDB::Analyse() +{ + PMessage* TmpMsg = mDecodeData->mMessage; + uint16_t Unknown3, OptionSize; + + mDecodeData->mName << "=ReceiveDB request from client"; + + mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); + TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 ); + ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is + ( *TmpMsg ) >> mUnknown1; // command name size + ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is! + ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options! + ( *TmpMsg ) >> mCommandName; // null terminated string + + + while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) + { + ( *TmpMsg ) >> OptionSize; + if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) + { + ( *TmpMsg ) >> mOptions[mOptionsCount++]; + //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! + } + else + { + break; + } + } + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpReceiveDB::DoAction() +{ + //PMessage* tmpMsg; + //PClient* tClient = mDecodeData->mClient; + //PChar* tChar = tClient->GetChar(); + bool Result = false; + + if ( gDevDebug ) + { + Console->Print( "%s ReceiveDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + Console->Print( "%s Open Terminal - Terminal session %04x (?) - Unknown1 %04x - DBId %04x - Unknown2 %02x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId, mUnknown1, mDBId, mUnknown2 ); + Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() ); + for ( uint8_t i = 0; i < mOptionsCount; ++i ) + Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() ); + } + + if ( mCommandName == "VehicleListing" ) + { + Result = ActionVehicleListing(); + } + else if ( mCommandName == "VehicleControl" ) + { + Result = ActionVehicleControl(); + } + else + { + // Let Terminal try before error + Result = Terminal->HandleReceiveDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2); + } + + if ( !Result ) + { + Console->Print( "%s PUdpReceiveDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() ); + for ( uint8_t i = 0; i < mOptionsCount; ++i ) + Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return Result; +} + +bool PUdpReceiveDB::ActionVehicleListing() +{ + PMessage* tmpMsg; + PClient* tClient = mDecodeData->mClient; + PChar* tChar = tClient->GetChar(); + + if ( mOptionsCount == 3 ) // CharId, StartVhcEntry, MaxVhcEntries + { + if ((( uint32_t )atol( mOptions[0].c_str() ) ) != tChar->GetID() ) + { + // Err: invalid CharId. Can alert, But we don't care :-) (except if used for other terminal function) + } + // !!! some more check/regex on values to do before using !!! + uint16_t StartIndex = atoi( mOptions[1].c_str() ); + uint16_t MaxEntries = atoi( mOptions[2].c_str() ); + + uint8_t nStatus = 1; + uint16_t nErrcode = 0; + + tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); + tClient->SendUDPMessage( tmpMsg ); + + PVhcInfoList* VhcList = Vehicles->GetCharVehicles( tChar->GetID(), MaxEntries, StartIndex ); + if ( ! VhcList->empty() ) + { + uint16_t NumEntries = VhcList->size(); + std::string* Answer = new std::string[4 * NumEntries]; + uint16_t Index = 0; + PVehicleInformation* EntryInfo; +//Console->Print("VHc entries : %d", NumEntries); + + while ( ! VhcList->empty() ) + { + EntryInfo = VhcList->front(); + VhcList->pop(); + Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleId() ); //vhcId + Answer[Index++] = Ssprintf( "%u", EntryInfo->GetVehicleType() ); //vhcType + Answer[Index++] = Ssprintf( "%u", EntryInfo->GetStatus() ); //vhcStatus 0:parking, 1:in_service, 2:destroyed + Answer[Index++] = Ssprintf( "%u", EntryInfo->GetHealth() ); //vhcHealth% +//Console->Print("Entry: %s/%s/%s/%s", Answer[Index-4].c_str(), Answer[Index-3].c_str(), Answer[Index-2].c_str(), Answer[Index-1].c_str()); + delete EntryInfo; + } + + tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, NumEntries, 4 ); + tClient->SendUDPMessage( tmpMsg ); + delete [] Answer; + } + delete VhcList; + + return true; + } + else + return false; + /* + // Option1=CharId, Option2=resultEntryStart, Option3=maxResultEntries + S=> 03/2b/1a VehicleListing+0 + 13 2a 00 7c be 19 + 03 2a 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .*.+......Vehicl + 65 4c 69 73 74 69 6e 67 00 eListing. + S=> 03/2b/17 0f 00 08 00 04 00 <0f 00><04 00> + VehicleListing+0 + + + (val: 0=stored) + (val: 0-255) + == + 03/2b/17 0f 00 01 00 04 00 <0f 00><04 00> + 31 + 03 54 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 4c 69 73 74 .....VehicleList + 69 6e 67 00 06 00 32 35 32 37 37 00 03 00 36 30 ing...25277...60 + 00 02 00 30 00 04 00 32 35 35 00 ...0...255. + */ +} + +bool PUdpReceiveDB::ActionVehicleControl() +{ + PMessage* tmpMsg; + PClient* tClient = mDecodeData->mClient; + + if ( mOptionsCount == 2 ) // VhcId, CharId + { + // !!! validate values !!! + uint8_t nStatus = 1; + uint16_t nErrcode = 0; + + tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); + tClient->SendUDPMessage( tmpMsg ); + + uint32_t VhcId = ( uint32_t )atol( mOptions[0].c_str() ); + PVehicleInformation EntryInfo; + if ( Vehicles->GetVehicleInfo( VhcId, &EntryInfo ) ) + { + std::string* Answer = new std::string[4]; + Answer[0] = Ssprintf( "%u", EntryInfo.GetVehicleType() ); //vhcType + Answer[1] = Ssprintf( "%u", EntryInfo.GetStatus() ); //vhcStatus + Answer[2] = Ssprintf( "%u", EntryInfo.GetHealth() ); //vhcHealth% + Answer[3] = Ssprintf( "%u", ( 255 - EntryInfo.GetHealth() ) * 1000 * EntryInfo.GetVehicleType() / 255 ); //Repair cost + if ( gDevDebug ) + Console->Print( "%s Entry: %s/%s/%s/%s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), Answer[0].c_str(), Answer[1].c_str(), Answer[2].c_str(), Answer[3].c_str() ); + tmpMsg = MsgBuilder->BuildDBAnswerMsg( tClient, &mCommandName, Answer, 1, 4 ); + tClient->SendUDPMessage( tmpMsg ); + delete [] Answer; + } + return true; + } + else + return false; + /* + // Option1=VhcId, Option2=CharId + S=> 03/2b/1a VehicleControl + 13 77 00 c9 be 19 + 03 76 00 2b 1a 0f 00 01 00 00 56 65 68 69 63 6c .v.+......Vehicl + 65 43 6f 6e 74 72 6f 6c 00 eControl. + S=> 03/2b/17 0f 00 01 00 04 00 VehicleControl 4 0 255 4255( + 2f + 03 77 00 2b 17 0f 00 01 00 04 00 56 65 68 69 63 6c 65 43 6f 6e 74 .....VehicleCont + 72 6f 6c 00 02 00 34 00 02 00 30 00 04 00 32 35 rol...4...0...25 + 35 00 05 00 34 32 35 35 00 5...4255. + */ +} + +/*******************************************************************************************/ +/**** PUdpUpdateDB ****/ +/*******************************************************************************************/ +PUdpUpdateDB::PUdpUpdateDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x18"; + mOptionsCount = 0; +} + +PUdpMsgAnalyser* PUdpUpdateDB::Analyse() +{ + PMessage* TmpMsg = mDecodeData->mMessage; + uint16_t Unknown3, OptionSize; + + mDecodeData->mName << "=UpdateDB request from client"; + + mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); + TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 ); + ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is + ( *TmpMsg ) >> mUnknown1; // command name size + ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is! + ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options! + ( *TmpMsg ) >> mCommandName; // null terminated string + + + while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) + { + ( *TmpMsg ) >> OptionSize; + if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) + { + ( *TmpMsg ) >> mOptions[mOptionsCount++]; + //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! + } + else + { + break; + } + } + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpUpdateDB::DoAction() +{ + if ( gDevDebug ) + { + Console->Print( "%s UpdateDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId ); + Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() ); + for ( uint8_t i = 0; i < mOptionsCount; ++i ) + Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() ); + } + bool Result = false; + Result = Terminal->HandleUpdateDB(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2); + + if ( !Result ) + { + Console->Print( "%s PUdpUpdateDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mCommandName.c_str() ); + for ( uint8_t i = 0; i < mOptionsCount; ++i ) + Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() ); + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} +/*******************************************************************************************/ +/**** PUdpTryAccessDB ****/ +/*******************************************************************************************/ +PUdpTryAccessDB::PUdpTryAccessDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x19"; + mOptionsCount = 0; +} + +PUdpMsgAnalyser* PUdpTryAccessDB::Analyse() +{ + PMessage* TmpMsg = mDecodeData->mMessage; + uint16_t Unknown3, OptionSize; + + mDecodeData->mName << "=TryAccess request from client"; + + mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); + TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 17 ); + ( *TmpMsg ) >> mUnknown2; // Some unknown var maxx used. No idea what that is + ( *TmpMsg ) >> mUnknown1; // command name size + ( *TmpMsg ) >> mDBId; // variable, increments => DB ID. Look in several terminal .tsc files, ENV(DBID) it is! + ( *TmpMsg ) >> Unknown3; // constant ? => Size of Options! + ( *TmpMsg ) >> mCommandName; // null terminated string + + while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) + { + ( *TmpMsg ) >> OptionSize; + if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) + { + ( *TmpMsg ) >> mOptions[mOptionsCount++]; + //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! + } + else + { + break; + } + } + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpTryAccessDB::DoAction() +{ + // Let the terminal class handle the request + Terminal->HandleTryAccess(mDecodeData->mClient, mTerminalSessionId, &mCommandName, mOptions, mOptionsCount, mDBId, mUnknown2); + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} +/*******************************************************************************************/ +/**** PUdpQueryDB ****/ +/*******************************************************************************************/ +PUdpQueryDB::PUdpQueryDB( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x1b"; + mOptionsCount = 0; +} + +PUdpMsgAnalyser* PUdpQueryDB::Analyse() +{ + PMessage* TmpMsg = mDecodeData->mMessage; + uint16_t OptionSize; + + mDecodeData->mName << "=QueryDB request from client"; + + mTerminalSessionId = TmpMsg->U8Data( mDecodeData->Sub0x13Start + 6 ); + TmpMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 18 ); + ( *TmpMsg ) >> OptionSize; // Size of data + ( *TmpMsg ) >> OptionSize; // Size of DB Command Name + if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) + { + ( *TmpMsg ) >> mDBCommandName; + } + ( *TmpMsg ) >> OptionSize; // Size of Command Name + if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) + { + ( *TmpMsg ) >> mCommandName; // null terminated string + } + + while (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && ( mOptionsCount < mMaxOptions ) ) + { + ( *TmpMsg ) >> OptionSize; + if (( TmpMsg->GetNextByteOffset() < mDecodeData->Sub0x13StartNext ) && OptionSize ) + { + ( *TmpMsg ) >> mOptions[mOptionsCount++]; + //if(mOptions[mOptionsCount-1].size() != (OptionSize-1)) Warning (but no pb)! + } + else + { + break; + } + } + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpQueryDB::DoAction() +{ + //PMessage* tmpMsg; + //PClient* tClient = mDecodeData->mClient; + bool Result = false; + + if ( gDevDebug ) + { + Console->Print( "%s QueryDB request from client", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId ); + Console->Print( "%s DBCommand: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDBCommandName.c_str() ); + Console->Print( "%s Command: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mCommandName.c_str() ); + for ( uint8_t i = 0; i < mOptionsCount; ++i ) + Console->Print( "%s Option %d: '%s'", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), i, mOptions[i].c_str() ); + } + + if ( mDBCommandName == "SPAWNVEHICLE" ) + { + Result = ActionSpawnVehicle(); + } + else if ( mDBCommandName == "REPAIRVEHICLE" ) + { + Result = ActionRepairVehicle(); + } + else if ( mDBCommandName == "DISMISSVEHICLE" ) + { + Result = ActionDismissVehicle(); + } + else + { + // Let Terminal try before error + Result = Terminal->HandleQueryDB(mDecodeData->mClient, &mDBCommandName, &mCommandName, mOptions, mOptionsCount); + } + + if ( !Result ) + { + Console->Print( "%s PUdpQueryDB - Error or unknown command %s", Console->ColorText( RED, BLACK, "[WARNING]" ), mDBCommandName.c_str() ); + for ( uint8_t i = 0; i < mOptionsCount; ++i ) + Console->Print( "%s Option %d: '%s'", Console->ColorText( RED, BLACK, "[NOTICE]" ), i, mOptions[i].c_str() ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return Result; +} + +bool PUdpQueryDB::ActionSpawnVehicle() +{ + PMessage* tmpMsg; + PClient* tClient = mDecodeData->mClient; + PChar* tChar = tClient->GetChar(); + + if ( mOptionsCount == 3 ) // 0, VhcId, CharId + { + uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() ); + //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str()); + // !!! validate values !!! + // !!! + check CharId = current char && CharId is owner of VhcId + uint8_t nStatus = 1; // 1=OK, 0=Err + uint16_t nErrcode = 16; // 0=n/a 16=Already Spawned // MsdId = 2500+nErrcode [MISC] + + tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); + tClient->SendUDPMessage( tmpMsg ); + + PVhcCoordinates NewPosition; + PWorld* CurrentWorld = Worlds->GetWorld( tChar->GetLocation() ); + bool relativePos = false; + if ( tChar->GetLastUsedObject() && !WorldActors->IsDynamicActor( tChar->GetLastUsedObject() ) && CurrentWorld ) + { + const PFurnitureItemTemplate* tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( tChar->GetLastUsedObject() / 1024 - 1 ); + if ( tFurnitureTemplate && ( tFurnitureTemplate->GetFunctionType() == 28 ) ) // vhc term + { + float decal = 1000; // distance at which to spawn the vhc + float nPosX, nPosY, nPosZ; + tFurnitureTemplate->GetPos( &nPosX, &nPosY, &nPosZ ); + nPosX += 32000; + nPosY += 32000; + float dX = ( tChar->Coords.mX - nPosX ); + float dY = ( tChar->Coords.mY - nPosY ); + float d = decal / sqrt( dX * dX + dY * dY ); + NewPosition.SetPosition( static_cast( nPosY + d * dY ), ( tChar->Coords ).mZ + 100, static_cast( nPosX + d * dX ), ( tChar->Coords ).mUD, 34683, 32403 ); + relativePos = true; + } + } + + if( ! relativePos ) + NewPosition.SetPosition(( tChar->Coords ).mY, ( tChar->Coords ).mZ + 150, ( tChar->Coords ).mX, ( tChar->Coords ).mUD, 34683, 32403 ); + + PSpawnedVehicle* NewVhc = Vehicles->SpawnVehicle( VhcId, tChar->GetLocation(), &NewPosition ); + if ( NewVhc ) + { + tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( NewVhc ); + ClientManager->UDPBroadcast( tmpMsg, tChar->GetLocation() ); + } + + return true; + } + else + return false; +} + +bool PUdpQueryDB::ActionRepairVehicle() +{ + PMessage* tmpMsg; + PClient* tClient = mDecodeData->mClient; + + if ( mOptionsCount == 3 ) // 0, VhcId, CharId + { + //uint32_t VhcId = (uint32_t)atol(mOptions[1].c_str()); + //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str()); + // !!! validate values !!! + + uint8_t nStatus = 1; // 1=OK, 0=Err + uint16_t nErrcode = 18; // 0=n/a 18=Still Spawned, 19=Not enough money + + tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); + tClient->SendUDPMessage( tmpMsg ); + + // Action here + + return true; + } + else + return false; +} + +bool PUdpQueryDB::ActionDismissVehicle() +{ + PMessage* tmpMsg; + PClient* tClient = mDecodeData->mClient; + //PChar* tChar = tClient->GetChar(); + bool Result = false; + + if ( mOptionsCount == 3 ) // 0, VhcId, CharId + { + uint32_t VhcId = ( uint32_t )atol( mOptions[1].c_str() ); + //uint32_t CharId = (uint32_t)atol(mOptions[2].c_str()); + // !!! validate values !!! + // !!! + check CharId = current char && CharId is owner of VjhcId + // !!! Check vhc empty + uint8_t nStatus = 0; // 1=OK, 0=Err + uint16_t nErrcode = 17; // 0=n/a 17=Not Spawned + PVehicleInformation nInfo; + uint32_t tLocalId = 0; + uint32_t tLocation = 0; + + PSpawnedVehicle* tVhc = Vehicles->GetSpawnedVehicle( VhcId ); + if ( tVhc ) + { + tLocalId = tVhc->GetLocalId(); + tLocation = tVhc->GetLocation(); + uint32_t tCharId; + PChar* tChar; + for ( uint8_t i = 0; i < tVhc->GetNumSeats(); ++i ) + { + if (( tCharId = tVhc->GetSeatUser( i ) ) ) + { + if (( tChar = Chars->GetChar( tCharId ) ) ) + { + PUdpCharExitChair::DoLeaveChair( tChar, NULL, tVhc ); + } + } + } + Result = Vehicles->UnspawnVehicle( VhcId ); + } + + if ( Result ) + { + nStatus = 1; + nErrcode = 0; + } + tmpMsg = MsgBuilder->BuildDBRequestStatusMsg( tClient, &mCommandName, nStatus, nErrcode ); + tClient->SendUDPMessage( tmpMsg ); + + if ( Result ) + { + tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( tLocalId ); + ClientManager->UDPBroadcast( tmpMsg, tLocation ); + } + return true; + } + else + return false; +} + +/*******************************************************************************************/ +/**** PUdpTeminal0x1f ****/ +/*******************************************************************************************/ +PUdpTeminal0x1f::PUdpTeminal0x1f( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x1f"; +} + +PUdpMsgAnalyser* PUdpTeminal0x1f::Analyse() +{ + mDecodeData->mName << "=Open Terminal"; + mTerminalSessionId = mDecodeData->mMessage->U8Data( mDecodeData->Sub0x13Start + 6 ); + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpTeminal0x1f::DoAction() +{ + if ( gDevDebug ) + Console->Print( "%s Open Terminal - Terminal session %04x (?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mTerminalSessionId ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpTerminal.hxx b/TinNS/Source/GameServer/Decoder/UdpTerminal.hxx index 2cabd91..be25bf1 100644 --- a/TinNS/Source/GameServer/Decoder/UdpTerminal.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpTerminal.hxx @@ -1,97 +1,97 @@ -#pragma once - -#include -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpReceiveDB : public PUdpMsgAnalyser { -private: - static const uint8_t mMaxOptions = 9; // Largest: forum\forenlist.tsc(21, 114,...) - uint16_t mTerminalSessionId; - std::string mCommandName; - std::string mOptions[mMaxOptions]; - uint8_t mOptionsCount; - - uint16_t mUnknown1; - uint8_t mUnknown2; - uint16_t mDBId; - - bool ActionVehicleListing(); - bool ActionVehicleControl(); - -public: - PUdpReceiveDB(PMsgDecodeData *nDecodeData); - //~PUdpReceiveDB(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpUpdateDB : public PUdpMsgAnalyser { -private: - static const uint8_t mMaxOptions = 7; // Largest: forum\bbcnewthread.tsc(66): - uint16_t mTerminalSessionId; - std::string mCommandName; - std::string mOptions[mMaxOptions]; - uint8_t mOptionsCount; - - uint16_t mUnknown1; - uint8_t mUnknown2; - uint16_t mDBId; - -public: - PUdpUpdateDB(PMsgDecodeData *nDecodeData); - //~PUdpUpdateDB(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpTryAccessDB : public PUdpMsgAnalyser { -private: - static const uint8_t mMaxOptions = 9; // Largest: stockx\depot.tsc(227): - uint16_t mTerminalSessionId; - std::string mCommandName; - std::string mOptions[mMaxOptions]; - uint8_t mOptionsCount; - - uint16_t mUnknown1; - uint8_t mUnknown2; - uint16_t mDBId; - -public: - PUdpTryAccessDB(PMsgDecodeData *nDecodeData); - //~PUdpTryAccessDB(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpQueryDB : public PUdpMsgAnalyser { // Also called "ServerMessage" in .tsc scripts! -private: - static const uint8_t mMaxOptions = 5; // Largest: politics\transcomment.tsc(36): - uint16_t mTerminalSessionId; - uint16_t mDBId; - std::string mDBCommandName; - std::string mCommandName; - std::string mOptions[mMaxOptions]; - uint8_t mOptionsCount; - - bool ActionSpawnVehicle(); - bool ActionRepairVehicle(); - bool ActionDismissVehicle(); - -public: - PUdpQueryDB(PMsgDecodeData *nDecodeData); - //~PUdpQueryDB(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpTeminal0x1f : public PUdpMsgAnalyser { -private: - uint16_t mTerminalSessionId; - -public: - PUdpTeminal0x1f(PMsgDecodeData *nDecodeData); - //~PUdpTeminal0x1f(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpReceiveDB : public PUdpMsgAnalyser { +private: + static const uint8_t mMaxOptions = 9; // Largest: forum\forenlist.tsc(21, 114,...) + uint16_t mTerminalSessionId; + std::string mCommandName; + std::string mOptions[mMaxOptions]; + uint8_t mOptionsCount; + + uint16_t mUnknown1; + uint8_t mUnknown2; + uint16_t mDBId; + + bool ActionVehicleListing(); + bool ActionVehicleControl(); + +public: + PUdpReceiveDB(PMsgDecodeData *nDecodeData); + //~PUdpReceiveDB(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpUpdateDB : public PUdpMsgAnalyser { +private: + static const uint8_t mMaxOptions = 7; // Largest: forum\bbcnewthread.tsc(66): + uint16_t mTerminalSessionId; + std::string mCommandName; + std::string mOptions[mMaxOptions]; + uint8_t mOptionsCount; + + uint16_t mUnknown1; + uint8_t mUnknown2; + uint16_t mDBId; + +public: + PUdpUpdateDB(PMsgDecodeData *nDecodeData); + //~PUdpUpdateDB(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpTryAccessDB : public PUdpMsgAnalyser { +private: + static const uint8_t mMaxOptions = 9; // Largest: stockx\depot.tsc(227): + uint16_t mTerminalSessionId; + std::string mCommandName; + std::string mOptions[mMaxOptions]; + uint8_t mOptionsCount; + + uint16_t mUnknown1; + uint8_t mUnknown2; + uint16_t mDBId; + +public: + PUdpTryAccessDB(PMsgDecodeData *nDecodeData); + //~PUdpTryAccessDB(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpQueryDB : public PUdpMsgAnalyser { // Also called "ServerMessage" in .tsc scripts! +private: + static const uint8_t mMaxOptions = 5; // Largest: politics\transcomment.tsc(36): + uint16_t mTerminalSessionId; + uint16_t mDBId; + std::string mDBCommandName; + std::string mCommandName; + std::string mOptions[mMaxOptions]; + uint8_t mOptionsCount; + + bool ActionSpawnVehicle(); + bool ActionRepairVehicle(); + bool ActionDismissVehicle(); + +public: + PUdpQueryDB(PMsgDecodeData *nDecodeData); + //~PUdpQueryDB(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpTeminal0x1f : public PUdpMsgAnalyser { +private: + uint16_t mTerminalSessionId; + +public: + PUdpTeminal0x1f(PMsgDecodeData *nDecodeData); + //~PUdpTeminal0x1f(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpUseObject.cxx b/TinNS/Source/GameServer/Decoder/UdpUseObject.cxx index c063aa9..b73f0fd 100644 --- a/TinNS/Source/GameServer/Decoder/UdpUseObject.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpUseObject.cxx @@ -1,867 +1,867 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -uint32_t gVhcId = 0x3ff; - -/**** PUdpVhcMove ****/ - -PUdpUseObject::PUdpUseObject( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x17"; -} - -PUdpMsgAnalyser* PUdpUseObject::Analyse() -{ - mDecodeData->mName << "=Object use"; - - mRawItemID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 8 ); - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpUseObject::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* nChar = nClient->GetChar(); - uint32_t ItemID; - char DbgMessage[128]; - PMessage* tmpMsg; - - bool tHandleDynamicActor = false; - - /*PMessage* cMsg = mDecodeData->mMessage; - uint32_t ClientTime = cMsg->U32Data(mDecodeData->Sub0x13Start+2); - - tmpMsg = MsgBuilder->BuildPingMsg(mDecodeData->mClient, ClientTime); - mDecodeData->mClient->SendUDPMessage(tmpMsg);*/ - - nChar->SetLastUsedObject( mRawItemID ); - - if ( nClient->IsInRemoveActorMode() == true ) - { - if ( WorldActors->IsDynamicActor( mRawItemID ) == true ) - { - WorldActors->DelWorldActor( nClient, mRawItemID ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; - } - else - Chat->send( nClient, CHAT_DIRECT, "System", "This is not an dynamic worldactor. To remove it please type @remove " ); - } - - if ( gDevDebug ) - { - Console->Print( "Char at y=%f (0x%04x) z=%f (0x%04x) x=%f (0x%04x)", ( float )( nChar->Coords.mY - 32000 ), nChar->Coords.mY, ( float )( nChar->Coords.mZ - 32000 ), nChar->Coords.mZ, ( float )( nChar->Coords.mX - 32000 ), nChar->Coords.mX ); - if ( mRawItemID & 1023 ) - Console->Print( "using item %d (0x%08x)", mRawItemID, mRawItemID ); - else - Console->Print( "using item %d (0x%08x) [dat entry %d (0x%08x)]", mRawItemID, mRawItemID, mRawItemID / 1024 - 1, mRawItemID / 1024 - 1 ); - } - - if ( nClient->GetDebugMode( DBG_ITEMID ) ) - { - if ( mRawItemID & 1023 ) - snprintf( DbgMessage, 128, "using item [raw: %d (0x%08x)]", mRawItemID, mRawItemID ); - else - snprintf( DbgMessage, 128, "using item %d (0x%08x) [raw: %d (0x%08x)]", mRawItemID / 1024 - 1, mRawItemID / 1024 - 1, mRawItemID, mRawItemID ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - } - - PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() ); - if ( CurrentWorld ) - { - if ( WorldActors->IsDynamicActor( mRawItemID ) == true ) - { - tHandleDynamicActor = true; - if ( gDevDebug ) - Console->Print( "%s Dynamic actor found, processing...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - } - - if ( mRawItemID & 1023 && tHandleDynamicActor == false ) // non-furniture objects - { - if ( mRawItemID > 0x80 ) // maybe door - { - if ( nClient->GetDebugMode( DBG_ITEMID ) ) - { - snprintf( DbgMessage, 128, "Door : %d", mRawItemID - 0x80 ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - } - const PDoorTemplate* tDoor = CurrentWorld->GetDoor( mRawItemID - 0x80 ); - if ( tDoor ) - { - if ( tDoor->IsTriggeredDoor() ) - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - else - { - if ( gDevDebug ) - Console->Print( "%s Opening %s door %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ( tDoor->IsDoubleDoor() ? "double" : "simple" ), mRawItemID - 0x80 ); - tmpMsg = MsgBuilder->BuildDoorOpenMsg( mRawItemID, tDoor->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - } - } - if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // else might be PC, NPC, VHC - { - if ( gDevDebug ) - Console->Print( "%s Clicking on char, npc or vhc %d (%x) - time = %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID, GameServer->GetGameTime() ); - - if ( PSpawnedVehicles::IsPotentialSpawnedVehicle( mRawItemID ) ) - { - bool vhcFound = false; - - if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere - { - PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mRawItemID ); - if ( tVhc ) - { - if ( gDevDebug ) - Console->Print( "%s Using vhc %d (0x%04x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID ); - vhcFound = true; - - if ( tVhc->GetInformation().GetOwnerCharId() == nChar->GetID() ) // Requester is the owner - { - PUdpVhcUse::DoFreeSitting( nClient, tVhc, mRawItemID ); - } - else // Requester is not the owner - { - if ( tVhc->GetNumSeats() == 1 ) // single seat vhc - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 17, mRawItemID ); // "Not your vhc" msg - nClient->SendUDPMessage( tmpMsg ); - } // multi seats vhc - else if ( ! tVhc->IsCharInside( tVhc->GetInformation().GetOwnerCharId() ) ) - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 18, mRawItemID ); // "Owner not on board" msg - nClient->SendUDPMessage( tmpMsg ); - } - else if ( tVhc->GetNbFreeSeats() == 0 ) - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, mRawItemID ); // "No free seat" msg - nClient->SendUDPMessage( tmpMsg ); - } - else - { - // Send request to owner - PClient* ownerClient = ClientManager->getClientByChar( tVhc->GetInformation().GetOwnerCharId() ); - if ( ownerClient ) - { - PChar* ownerChar = ownerClient->GetChar(); - // We could check for valid allowed access before adding a new one - uint32_t newReqId = ownerChar->GetVhcAccessRequestList()->Add( nChar->GetID(), tVhc->GetInformation().GetVehicleId() ); - if ( newReqId ) - { - tmpMsg = MsgBuilder->BuildVhcAccessRequestMsg( ownerClient, newReqId, nChar->GetID(), nClient->GetID(), tVhc->GetInformation().GetVehicleId() ); - ownerClient->SendUDPMessage( tmpMsg ); - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 19, mRawItemID ); // "req transmitted" msg - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); // Undefined failure / Owner not available - nClient->SendUDPMessage( tmpMsg ); - } - } - } - //////// Msg100 id - //22 can't use that seat - } - else if (( nChar->GetLocation() == PWorlds::mNcSubwayWorldId ) && Subway->IsValidSubwayCab( mRawItemID ) && ( nChar->GetSeatInUse() == seat_none ) ) // Entering subway - { - vhcFound = true; - if ( Subway->IsDoorOpen( mRawItemID, GameServer->GetGameTime() ) ) - { - uint8_t freeSeat = Subway->GetFreeSeat( mRawItemID ); - if ( freeSeat && Subway->SetSeatUser( mRawItemID, freeSeat, nChar->GetID() ) ) - { - nChar->SetSeatInUse( seat_subway, mRawItemID, freeSeat ); - tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID, freeSeat ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - // else error: invalid vhc - } // else char alreay sitting - if ( vhcFound ) - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - } - - if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc - { - // Is it a PC ? - PClient* tClient; - if (( tClient = CurrentWorld->GetClientByCharLocalId( mRawItemID ) ) ) - { - /*if(gDevDebug)*/ - Console->Print( "%s clicking on PC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID ); - tmpMsg = MsgBuilder->BuildCharInteractionMenuMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - } - } - - if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc nor a pc - { - //Console->Print(">>> Searching world"); - // Is it a NPC ? - PNPC* targetNPC = 0; - PNPCWorld* currentNPCWorld = NPCManager->GetWorld( nChar->GetLocation() ); - if ( currentNPCWorld ) - { - //Console->Print(">>> Searching NPC (SQL Version)"); - targetNPC = currentNPCWorld->GetNPC( mRawItemID ); - if(!targetNPC) - { - //Console->Print(">>> Searching NPC (DEF Version)"); - // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS! - targetNPC = currentNPCWorld->GetNPC( mRawItemID - 255 ); - } - } - if ( targetNPC ) - { - /*if(gDevDebug)*/ - Console->Print( "%s Player talks to NPC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID ); - //if(gDevDebug) tContainer->Dump(); - - // Well its not "start a conversation" its more "User clicked NPC, do anything with it (Trade, script,...) - targetNPC->StartConversation(nClient); - - //tmpMsg = MsgBuilder->BuildTraderItemListMsg( nClient, mRawItemID ); - //tmpMsg->Dump(); - //nClient->FragmentAndSendUDPMessage( tmpMsg, 0xac ); - } - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - } - } - else // furniture objects - { - const PFurnitureItemTemplate* tFurnitureTemplate = NULL; - const PDefWorldModel* tFurnitureModel = NULL; - if ( tHandleDynamicActor == false ) - { - // We have an STATIC ACTOR, which means we DONT KNOW the FUNCTION VALUE from pak_worldmodel.def yet - // (the setentry one). So we need to get it over the .dat file: - - // Dat files have smaller IDs - ItemID = mRawItemID / 1024 - 1; - - // Now grab the template from .dat file - tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( ItemID ); - - // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc - tFurnitureModel = CurrentWorld->GetFurnitureItemModel( ItemID ); - } - else - { - // We have an DYNAMIC ACTOR, which means we DO KNOW the FUNCTION VALUE (stored in SQL). - - // First, assign the RawID to the "real" itemID, which is used for several objects to identify them clientside - ItemID = mRawItemID; - - // Now get the get the function value: - int tFunctionVal = WorldActors->GetWorldActorFunctionID( mRawItemID ); - - // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc - tFurnitureModel = GameDefs->WorldModels()->GetDef( tFunctionVal ); - - if ( gDevDebug ) - Console->Print( "%s Processing dynmic actor %d with Functionvalue %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, tFunctionVal ); - } - - if ( tFurnitureModel ) // valid active furniture (else invalid or passive furniture) - { - if ( nClient->GetDebugMode( DBG_ITEMID ) ) - { - snprintf( DbgMessage, 128, "Item : %s", tFurnitureModel->GetName().c_str() ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - } - - if ( tFurnitureModel->GetUseFlags() & ufChair ) - { - uint32_t cSeatObjectId; - PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId ); - if (( cSeatType == seat_none ) || ( cSeatType == seat_chair ) ) - { - if ( CurrentWorld->CharUseChair( nClient->GetLocalID(), ItemID ) ) - { - if ( gDevDebug ) - Console->Print( "%s Localchar %d was previously using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId ); - if (( cSeatType ) && ( cSeatObjectId != ItemID ) ) - { - CurrentWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId ); - } - nChar->SetSeatInUse( seat_chair, ItemID ); - if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) - { - tFurnitureTemplate->GetFrontPos( &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) ); - //(nChar->Coords).mLR = tFurnitureTemplate->GetFrontLR(); - } - else - { - WorldActors->GetFrontPos( mRawItemID, &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) ); - //(nChar->Coords).mLR = WorldActors->GetFrontLR(); - } - - tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); // "Already in use" msg - nClient->SendUDPMessage( tmpMsg ); - } - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - } - else - { - if ( gDevDebug ) - Console->Print( "%s Item function type: %d value: %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue() ); - - DbgMessage[0] = 0; - switch ( tFurnitureModel->GetFunctionType() ) - { - case 6: //Respawn Station (GenRep) - { - uint32_t nLocation = nChar->GetLocation(); - uint16_t nEntity; - if ( Worlds->IsPotentialAppartement( nLocation ) ) - { - nLocation = 0xffffffff; // (uint32_t)-1; - nEntity = 0xffff; //(uint16_t)-1; - } - else - { - //nEntity = MySQL->GetWorldItemOption(mRawItemID/256, nLocation, 1); - // This is a kind of nearly-not-hardcoded-hack ... - int nEntityInt = 0; - if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) - { - nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), tFurnitureTemplate->GetLinkedObjectID() ); - } - else - { - nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), WorldActors->GetLinkedObjectID( mRawItemID ) ); - } - - nEntity = ( nEntityInt < 0 ? 0xffff : ( uint16_t )nEntityInt ); - } - - tmpMsg = MsgBuilder->BuildCharUseGenrepMsg( nClient, mRawItemID, nLocation, nEntity ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 7: //GoGuardian - { - tmpMsg = MsgBuilder->BuildCharUseGogoMsg( nClient ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 9: //Appartement Eingang - { - tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, tFurnitureModel->GetFunctionValue() ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 10: //Appartement Ein/Ausgang - { - tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, 0 ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 15: //HOLOMATCH EXIT - { - // temp hack + wrong entity... guess it works same as function 20 - uint32_t HoloNum = nChar->GetLocation() - 90000; // value 1 to 16, to transalte to 540..547 550..557 for worldmodel.def - - const PDefWorldModel* tHoloExitModel = GameDefs->WorldModels()->GetDef( 539 + HoloNum + ( HoloNum > 8 ? 2 : 0 ) ); - if ( tHoloExitModel && ( tHoloExitModel->GetFunctionType() == 14 ) ) // we use the Holomatch entry. Takes care of bad zone id - { - const PDefAppPlace* nAppPlace = GameDefs->AppPlaces()->GetDef( tHoloExitModel->GetFunctionValue() ); - if ( nAppPlace ) - { - uint32_t Location = nAppPlace->GetExitWorldID(); - uint16_t Entity = nAppPlace->GetExitWorldEntity(); - uint8_t SewerLevel = 0; - - tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, 0 ); //mRawItemID - nClient->SendUDPMessage( tmpMsg ); - if ( gDevDebug ) - Console->Print( "%s Holoexit: Client[%d] Char[%s] moving to zone %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() ); - if ( gDevDebug ) - Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel ); - } - else - { - Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() ); - } - } - else - { - Console->Print( "%s Client[%d] Char[%s] invalid holoentry used %d", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() ); - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 18: // "WORLDCHANGEACTOR" - case 20: // "DATFILE WORLDCHANGE ACTOR" - case 29: //Underground Exit - { - const PDefAppPlace* nAppPlace; - if ( tFurnitureModel->GetFunctionType() == 29 ) - { - nAppPlace = GameDefs->AppPlaces()->GetDef( nChar->GetLocation() ); // special for UG exit - } - else - { - nAppPlace = GameDefs->AppPlaces()->GetDef( tFurnitureModel->GetFunctionValue() ); - } - if ( nAppPlace ) - { - uint32_t Location = nAppPlace->GetExitWorldID(); - uint16_t Entity = nAppPlace->GetExitWorldEntity(); - uint8_t SewerLevel = 0; - //if(((tFurnitureModel->GetFunctionType() == 20) && nAppPlace->GetSewerLevel()) || (tFurnitureModel->GetFunctionType() == 29)) - if (( tFurnitureModel->GetFunctionType() == 20 ) || ( tFurnitureModel->GetFunctionType() == 29 ) ) - { - SewerLevel = 1; - } - - tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, mRawItemID ); //mRawItemID - nClient->SendUDPMessage( tmpMsg ); - if ( gDevDebug ) - { - Console->Print( "%s Dungeon in/out: Client[%d] Char[%s] moving to zone %d, %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() ); - Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel ); - Console->Print( "%s Function: %d, Value: %d - Sewer level in appplaces.def for this point: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue(), nAppPlace->GetSewerLevel() ); - Console->Print( "%s Worldmodel id: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetID() ); - } - } - else - { - Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() ); - // send a "refused" msg ? - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - //nextAnalyser = new PUdpCharJump(mDecodeData); - break; - } - - case 2: //Terminal - case 3: //Outfitter - case 16: //HOLOMATCH REFRESH - case 17: //HOLOMATCH HEAL & Recreation units - case 26: //Outpost Switch - { - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 31: //Venture Warp Station - { - tmpMsg = MsgBuilder->BuildCharUseVentureWarpMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 28: //Fahrzeug Depot Interface - { - tmpMsg = MsgBuilder->BuildCharUseVhcTerminalMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 11: //Appartement Klingel/�ffner - { - if ( Appartements->CanFreelyEnter( nChar, nChar->GetLocation() ) ) - { - if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) - { - if ( tFurnitureTemplate->GetLinkedObjectID() ) - { - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - if ( WorldActors->GetLinkedObjectID( mRawItemID ) ) - { - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - } - else - { - tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 5 ); // Ring - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 12: //Standard Button - { - if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) - { - if ( tFurnitureTemplate->GetLinkedObjectID() ) - { - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - if ( WorldActors->GetLinkedObjectID( mRawItemID ) ) - { - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 13: //Hack Button - { - if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) - { - if ( tFurnitureTemplate->GetLinkedObjectID() ) - { - if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons - { - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked! - nClient->SendUDPMessage( tmpMsg ); - } - - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID ); - if ( linkobjID ) - { - if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons - { - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked! - nClient->SendUDPMessage( tmpMsg ); - } - - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - case 23: //EINTRITTSGELD BUTTON - { - if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) - { - if ( tFurnitureTemplate->GetLinkedObjectID() ) - { - uint32_t OldCash = nChar->GetCash(); - uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue(); - if ( OldCash >= DoorFee ) - { - uint32_t NewCash = nChar->SetCash( OldCash - DoorFee ); - PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash ); - nClient->SendUDPMessage( tmpMsg_cash ); - tmpMsg_cash = NULL; - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money! - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID ); - if ( linkobjID ) - { - uint32_t OldCash = nChar->GetCash(); - uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue(); - if ( OldCash >= DoorFee ) - { - uint32_t NewCash = nChar->SetCash( OldCash - DoorFee ); - PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash ); - nClient->SendUDPMessage( tmpMsg_cash ); - tmpMsg_cash = NULL; - tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money! - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 1: //Itemcontainer - { - // TODO: Add check if container is already open / Make containers persistent - // PContainer* tContainer = World->GetContainer(mRawItemID); - PContainer* tContainer = new PContainerAutoCompactOnClose( INV_CABINET_MAXSLOTS ); - int functionVal = tFurnitureModel->GetFunctionValue(); - if ( functionVal <= 5 ) // force full random for cabinets for item testing - functionVal = -1; - tContainer->RandomFill( INV_CABINET_MAXSLOTS, functionVal ); - - /*nItem = new PItem(19, 1, 250, 250, 250, 250, 250, 250); - if(nItem->GetItemID()); - tContainer->AddItem(nItem);*/ - if ( gDevDebug ) Console->Print( "%s Temporary container created", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - //if(gDevDebug) tContainer->Dump(); - if ( tContainer->StartUse( nChar->GetID() ) ) - { - nChar->SetContainerInExclusiveUse( tContainer ); - tmpMsg = MsgBuilder->BuildCharOpenContainerMsg( nClient, mRawItemID, tContainer ); - //tmpMsg->Dump(); - nClient->FragmentAndSendUDPMessage( tmpMsg, 0x05 ); - } - else - { - tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 10 ); - nClient->SendUDPMessage( tmpMsg ); - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 32: // Text message - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, ( uint8_t )( 255 & tFurnitureModel->GetFunctionValue() ), mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - // Temp placeholder implementations ============================ - case 4: //Trader - { - snprintf( DbgMessage, 128, "That's a trader" ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 5: //Mineral - { - snprintf( DbgMessage, 128, "That's some minerals" ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 8: //Hackterminal - { - snprintf( DbgMessage, 128, "That's a hacking terminal" ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 14: //HOLOMATCH ENTRANCE - { - snprintf( DbgMessage, 128, "That's an holomatch entrance" ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 19: //CLANTERMINAL - { - snprintf( DbgMessage, 128, "That's a clan terminal" ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 25: //EXPLOSIVE - { - snprintf( DbgMessage, 128, "That's explosive !" ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - case 0: //May be roadsign if touchable - { - if ( ( tFurnitureModel->GetUseFlags() & ufTouchable ) ) // Touchable ? - { - snprintf( DbgMessage, 128, "You're at %s", tFurnitureModel->GetName().c_str() ); - Chat->send( nClient, CHAT_GM, "Information", DbgMessage ); - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - // else we continue to undefined - } - case 27: //Old goguardian - //case 21: //LOCATION FOR 20 - //case 22: // - case 24: //TUTORIALEXIT - //case 30: //Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle) - { - tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); - nClient->SendUDPMessage( tmpMsg ); - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - break; - } - - default: - break; - } - } - } - else - { - if ( gDevDebug ) - Console->Print( "%s Item not known from world template (maybe seen as PASSIVE ?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - } - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - } - else - { - Console->Print( RED, BLACK, "[ERROR] PUdpUseObject::DoAction : No World defined for client %d (char %d)", nClient->GetID(), nChar->GetID() ); - mDecodeData->mState = DECODE_ACTION_FAILED | DECODE_ACTION_DONE | DECODE_FINISHED; - } - - return true; -} - -/**** PUdpCloseItemContainer ****/ - -PUdpCloseItemContainer::PUdpCloseItemContainer( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x27"; -} - -PUdpMsgAnalyser* PUdpCloseItemContainer::Analyse() -{ - mDecodeData->mName << "=Closing item container"; - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpCloseItemContainer::DoAction() -{ -// PClient* nClient = mDecodeData->mClient; -// PChar* nChar = nClient->GetChar(); - - PChar* nChar = mDecodeData->mClient->GetChar(); - PContainer* tContainer = nChar->GetContainerInExclusiveUse(); - if ( tContainer ) - { - nChar->SetContainerInExclusiveUse( NULL ); - tContainer->EndUse( nChar->GetID() ); - if ( ! tContainer->GetOwnerId() ) - { - delete tContainer; - if ( gDevDebug ) Console->Print( "%s Temporary container deleted", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); - } - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +uint32_t gVhcId = 0x3ff; + +/**** PUdpVhcMove ****/ + +PUdpUseObject::PUdpUseObject( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x17"; +} + +PUdpMsgAnalyser* PUdpUseObject::Analyse() +{ + mDecodeData->mName << "=Object use"; + + mRawItemID = mDecodeData->mMessage->U32Data( mDecodeData->Sub0x13Start + 8 ); + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpUseObject::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* nChar = nClient->GetChar(); + uint32_t ItemID; + char DbgMessage[128]; + PMessage* tmpMsg; + + bool tHandleDynamicActor = false; + + /*PMessage* cMsg = mDecodeData->mMessage; + uint32_t ClientTime = cMsg->U32Data(mDecodeData->Sub0x13Start+2); + + tmpMsg = MsgBuilder->BuildPingMsg(mDecodeData->mClient, ClientTime); + mDecodeData->mClient->SendUDPMessage(tmpMsg);*/ + + nChar->SetLastUsedObject( mRawItemID ); + + if ( nClient->IsInRemoveActorMode() == true ) + { + if ( WorldActors->IsDynamicActor( mRawItemID ) == true ) + { + WorldActors->DelWorldActor( nClient, mRawItemID ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; + } + else + Chat->send( nClient, CHAT_DIRECT, "System", "This is not an dynamic worldactor. To remove it please type @remove " ); + } + + if ( gDevDebug ) + { + Console->Print( "Char at y=%f (0x%04x) z=%f (0x%04x) x=%f (0x%04x)", ( float )( nChar->Coords.mY - 32000 ), nChar->Coords.mY, ( float )( nChar->Coords.mZ - 32000 ), nChar->Coords.mZ, ( float )( nChar->Coords.mX - 32000 ), nChar->Coords.mX ); + if ( mRawItemID & 1023 ) + Console->Print( "using item %d (0x%08x)", mRawItemID, mRawItemID ); + else + Console->Print( "using item %d (0x%08x) [dat entry %d (0x%08x)]", mRawItemID, mRawItemID, mRawItemID / 1024 - 1, mRawItemID / 1024 - 1 ); + } + + if ( nClient->GetDebugMode( DBG_ITEMID ) ) + { + if ( mRawItemID & 1023 ) + snprintf( DbgMessage, 128, "using item [raw: %d (0x%08x)]", mRawItemID, mRawItemID ); + else + snprintf( DbgMessage, 128, "using item %d (0x%08x) [raw: %d (0x%08x)]", mRawItemID / 1024 - 1, mRawItemID / 1024 - 1, mRawItemID, mRawItemID ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + } + + PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() ); + if ( CurrentWorld ) + { + if ( WorldActors->IsDynamicActor( mRawItemID ) == true ) + { + tHandleDynamicActor = true; + if ( gDevDebug ) + Console->Print( "%s Dynamic actor found, processing...", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + } + + if ( mRawItemID & 1023 && tHandleDynamicActor == false ) // non-furniture objects + { + if ( mRawItemID > 0x80 ) // maybe door + { + if ( nClient->GetDebugMode( DBG_ITEMID ) ) + { + snprintf( DbgMessage, 128, "Door : %d", mRawItemID - 0x80 ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + } + const PDoorTemplate* tDoor = CurrentWorld->GetDoor( mRawItemID - 0x80 ); + if ( tDoor ) + { + if ( tDoor->IsTriggeredDoor() ) + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + else + { + if ( gDevDebug ) + Console->Print( "%s Opening %s door %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), ( tDoor->IsDoubleDoor() ? "double" : "simple" ), mRawItemID - 0x80 ); + tmpMsg = MsgBuilder->BuildDoorOpenMsg( mRawItemID, tDoor->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + } + } + if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // else might be PC, NPC, VHC + { + if ( gDevDebug ) + Console->Print( "%s Clicking on char, npc or vhc %d (%x) - time = %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID, GameServer->GetGameTime() ); + + if ( PSpawnedVehicles::IsPotentialSpawnedVehicle( mRawItemID ) ) + { + bool vhcFound = false; + + if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere + { + PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mRawItemID ); + if ( tVhc ) + { + if ( gDevDebug ) + Console->Print( "%s Using vhc %d (0x%04x)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, mRawItemID ); + vhcFound = true; + + if ( tVhc->GetInformation().GetOwnerCharId() == nChar->GetID() ) // Requester is the owner + { + PUdpVhcUse::DoFreeSitting( nClient, tVhc, mRawItemID ); + } + else // Requester is not the owner + { + if ( tVhc->GetNumSeats() == 1 ) // single seat vhc + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 17, mRawItemID ); // "Not your vhc" msg + nClient->SendUDPMessage( tmpMsg ); + } // multi seats vhc + else if ( ! tVhc->IsCharInside( tVhc->GetInformation().GetOwnerCharId() ) ) + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 18, mRawItemID ); // "Owner not on board" msg + nClient->SendUDPMessage( tmpMsg ); + } + else if ( tVhc->GetNbFreeSeats() == 0 ) + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, mRawItemID ); // "No free seat" msg + nClient->SendUDPMessage( tmpMsg ); + } + else + { + // Send request to owner + PClient* ownerClient = ClientManager->getClientByChar( tVhc->GetInformation().GetOwnerCharId() ); + if ( ownerClient ) + { + PChar* ownerChar = ownerClient->GetChar(); + // We could check for valid allowed access before adding a new one + uint32_t newReqId = ownerChar->GetVhcAccessRequestList()->Add( nChar->GetID(), tVhc->GetInformation().GetVehicleId() ); + if ( newReqId ) + { + tmpMsg = MsgBuilder->BuildVhcAccessRequestMsg( ownerClient, newReqId, nChar->GetID(), nClient->GetID(), tVhc->GetInformation().GetVehicleId() ); + ownerClient->SendUDPMessage( tmpMsg ); + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 19, mRawItemID ); // "req transmitted" msg + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); // Undefined failure / Owner not available + nClient->SendUDPMessage( tmpMsg ); + } + } + } + //////// Msg100 id + //22 can't use that seat + } + else if (( nChar->GetLocation() == PWorlds::mNcSubwayWorldId ) && Subway->IsValidSubwayCab( mRawItemID ) && ( nChar->GetSeatInUse() == seat_none ) ) // Entering subway + { + vhcFound = true; + if ( Subway->IsDoorOpen( mRawItemID, GameServer->GetGameTime() ) ) + { + uint8_t freeSeat = Subway->GetFreeSeat( mRawItemID ); + if ( freeSeat && Subway->SetSeatUser( mRawItemID, freeSeat, nChar->GetID() ) ) + { + nChar->SetSeatInUse( seat_subway, mRawItemID, freeSeat ); + tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID, freeSeat ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 6, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + // else error: invalid vhc + } // else char alreay sitting + if ( vhcFound ) + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + } + + if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc + { + // Is it a PC ? + PClient* tClient; + if (( tClient = CurrentWorld->GetClientByCharLocalId( mRawItemID ) ) ) + { + /*if(gDevDebug)*/ + Console->Print( "%s clicking on PC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID ); + tmpMsg = MsgBuilder->BuildCharInteractionMenuMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + } + } + + if ( !( mDecodeData->mState & DECODE_ACTION_DONE ) ) // not a vhc nor a pc + { + //Console->Print(">>> Searching world"); + // Is it a NPC ? + PNPC* targetNPC = 0; + PNPCWorld* currentNPCWorld = NPCManager->GetWorld( nChar->GetLocation() ); + if ( currentNPCWorld ) + { + //Console->Print(">>> Searching NPC (SQL Version)"); + targetNPC = currentNPCWorld->GetNPC( mRawItemID ); + if(!targetNPC) + { + //Console->Print(">>> Searching NPC (DEF Version)"); + // Note to myself: This is UGLY!!!! and BAD!!! but it works for now. CHANGE THIS! + targetNPC = currentNPCWorld->GetNPC( mRawItemID - 255 ); + } + } + if ( targetNPC ) + { + /*if(gDevDebug)*/ + Console->Print( "%s Player talks to NPC %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID ); + //if(gDevDebug) tContainer->Dump(); + + // Well its not "start a conversation" its more "User clicked NPC, do anything with it (Trade, script,...) + targetNPC->StartConversation(nClient); + + //tmpMsg = MsgBuilder->BuildTraderItemListMsg( nClient, mRawItemID ); + //tmpMsg->Dump(); + //nClient->FragmentAndSendUDPMessage( tmpMsg, 0xac ); + } + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + } + } + else // furniture objects + { + const PFurnitureItemTemplate* tFurnitureTemplate = NULL; + const PDefWorldModel* tFurnitureModel = NULL; + if ( tHandleDynamicActor == false ) + { + // We have an STATIC ACTOR, which means we DONT KNOW the FUNCTION VALUE from pak_worldmodel.def yet + // (the setentry one). So we need to get it over the .dat file: + + // Dat files have smaller IDs + ItemID = mRawItemID / 1024 - 1; + + // Now grab the template from .dat file + tFurnitureTemplate = CurrentWorld->GetFurnitureItemTemplate( ItemID ); + + // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc + tFurnitureModel = CurrentWorld->GetFurnitureItemModel( ItemID ); + } + else + { + // We have an DYNAMIC ACTOR, which means we DO KNOW the FUNCTION VALUE (stored in SQL). + + // First, assign the RawID to the "real" itemID, which is used for several objects to identify them clientside + ItemID = mRawItemID; + + // Now get the get the function value: + int tFunctionVal = WorldActors->GetWorldActorFunctionID( mRawItemID ); + + // Then get the FUNCTION VALUE as furniture model so we can access its subvalues etc + tFurnitureModel = GameDefs->WorldModels()->GetDef( tFunctionVal ); + + if ( gDevDebug ) + Console->Print( "%s Processing dynmic actor %d with Functionvalue %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mRawItemID, tFunctionVal ); + } + + if ( tFurnitureModel ) // valid active furniture (else invalid or passive furniture) + { + if ( nClient->GetDebugMode( DBG_ITEMID ) ) + { + snprintf( DbgMessage, 128, "Item : %s", tFurnitureModel->GetName().c_str() ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + } + + if ( tFurnitureModel->GetUseFlags() & ufChair ) + { + uint32_t cSeatObjectId; + PSeatType cSeatType = nChar->GetSeatInUse( &cSeatObjectId ); + if (( cSeatType == seat_none ) || ( cSeatType == seat_chair ) ) + { + if ( CurrentWorld->CharUseChair( nClient->GetLocalID(), ItemID ) ) + { + if ( gDevDebug ) + Console->Print( "%s Localchar %d was previously using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nClient->GetLocalID(), cSeatObjectId ); + if (( cSeatType ) && ( cSeatObjectId != ItemID ) ) + { + CurrentWorld->CharLeaveChair( nClient->GetLocalID(), cSeatObjectId ); + } + nChar->SetSeatInUse( seat_chair, ItemID ); + if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) + { + tFurnitureTemplate->GetFrontPos( &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) ); + //(nChar->Coords).mLR = tFurnitureTemplate->GetFrontLR(); + } + else + { + WorldActors->GetFrontPos( mRawItemID, &( nChar->Coords.mX ), &( nChar->Coords.mY ), &( nChar->Coords.mZ ) ); + //(nChar->Coords).mLR = WorldActors->GetFrontLR(); + } + + tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mRawItemID ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); // "Already in use" msg + nClient->SendUDPMessage( tmpMsg ); + } + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + } + else + { + if ( gDevDebug ) + Console->Print( "%s Item function type: %d value: %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue() ); + + DbgMessage[0] = 0; + switch ( tFurnitureModel->GetFunctionType() ) + { + case 6: //Respawn Station (GenRep) + { + uint32_t nLocation = nChar->GetLocation(); + uint16_t nEntity; + if ( Worlds->IsPotentialAppartement( nLocation ) ) + { + nLocation = 0xffffffff; // (uint32_t)-1; + nEntity = 0xffff; //(uint16_t)-1; + } + else + { + //nEntity = MySQL->GetWorldItemOption(mRawItemID/256, nLocation, 1); + // This is a kind of nearly-not-hardcoded-hack ... + int nEntityInt = 0; + if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) + { + nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), tFurnitureTemplate->GetLinkedObjectID() ); + } + else + { + nEntityInt = GameDefs->Respawns()->GetRespawnEntity( nChar->GetLocation(), WorldActors->GetLinkedObjectID( mRawItemID ) ); + } + + nEntity = ( nEntityInt < 0 ? 0xffff : ( uint16_t )nEntityInt ); + } + + tmpMsg = MsgBuilder->BuildCharUseGenrepMsg( nClient, mRawItemID, nLocation, nEntity ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 7: //GoGuardian + { + tmpMsg = MsgBuilder->BuildCharUseGogoMsg( nClient ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 9: //Appartement Eingang + { + tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, tFurnitureModel->GetFunctionValue() ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 10: //Appartement Ein/Ausgang + { + tmpMsg = MsgBuilder->BuildCharUseLiftMsg( nClient, mRawItemID, 0 ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 15: //HOLOMATCH EXIT + { + // temp hack + wrong entity... guess it works same as function 20 + uint32_t HoloNum = nChar->GetLocation() - 90000; // value 1 to 16, to transalte to 540..547 550..557 for worldmodel.def + + const PDefWorldModel* tHoloExitModel = GameDefs->WorldModels()->GetDef( 539 + HoloNum + ( HoloNum > 8 ? 2 : 0 ) ); + if ( tHoloExitModel && ( tHoloExitModel->GetFunctionType() == 14 ) ) // we use the Holomatch entry. Takes care of bad zone id + { + const PDefAppPlace* nAppPlace = GameDefs->AppPlaces()->GetDef( tHoloExitModel->GetFunctionValue() ); + if ( nAppPlace ) + { + uint32_t Location = nAppPlace->GetExitWorldID(); + uint16_t Entity = nAppPlace->GetExitWorldEntity(); + uint8_t SewerLevel = 0; + + tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, 0 ); //mRawItemID + nClient->SendUDPMessage( tmpMsg ); + if ( gDevDebug ) + Console->Print( "%s Holoexit: Client[%d] Char[%s] moving to zone %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() ); + if ( gDevDebug ) + Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel ); + } + else + { + Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() ); + } + } + else + { + Console->Print( "%s Client[%d] Char[%s] invalid holoentry used %d", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() ); + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 18: // "WORLDCHANGEACTOR" + case 20: // "DATFILE WORLDCHANGE ACTOR" + case 29: //Underground Exit + { + const PDefAppPlace* nAppPlace; + if ( tFurnitureModel->GetFunctionType() == 29 ) + { + nAppPlace = GameDefs->AppPlaces()->GetDef( nChar->GetLocation() ); // special for UG exit + } + else + { + nAppPlace = GameDefs->AppPlaces()->GetDef( tFurnitureModel->GetFunctionValue() ); + } + if ( nAppPlace ) + { + uint32_t Location = nAppPlace->GetExitWorldID(); + uint16_t Entity = nAppPlace->GetExitWorldEntity(); + uint8_t SewerLevel = 0; + //if(((tFurnitureModel->GetFunctionType() == 20) && nAppPlace->GetSewerLevel()) || (tFurnitureModel->GetFunctionType() == 29)) + if (( tFurnitureModel->GetFunctionType() == 20 ) || ( tFurnitureModel->GetFunctionType() == 29 ) ) + { + SewerLevel = 1; + } + + tmpMsg = MsgBuilder->BuildChangeLocationMsg( nClient, Location, Entity, SewerLevel, mRawItemID ); //mRawItemID + nClient->SendUDPMessage( tmpMsg ); + if ( gDevDebug ) + { + Console->Print( "%s Dungeon in/out: Client[%d] Char[%s] moving to zone %d, %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nClient->GetID(), nChar->GetName().c_str(), Location, nAppPlace->GetName().c_str() ); + Console->Print( "%s Location=%d Entity=%d Level=%d", Console->ColorText( CYAN, BLACK, "[Debug]" ), Location, Entity, SewerLevel ); + Console->Print( "%s Function: %d, Value: %d - Sewer level in appplaces.def for this point: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetFunctionType(), tFurnitureModel->GetFunctionValue(), nAppPlace->GetSewerLevel() ); + Console->Print( "%s Worldmodel id: %d", Console->ColorText( CYAN, BLACK, "[Debug]" ), tFurnitureModel->GetID() ); + } + } + else + { + Console->Print( "%s Client[%d] Char[%s] invalid destination %d (appplaces.def)", Console->ColorText( RED, BLACK, "[Warning]" ), nClient->GetID(), nChar->GetName().c_str(), tFurnitureModel->GetFunctionValue() ); + // send a "refused" msg ? + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + //nextAnalyser = new PUdpCharJump(mDecodeData); + break; + } + + case 2: //Terminal + case 3: //Outfitter + case 16: //HOLOMATCH REFRESH + case 17: //HOLOMATCH HEAL & Recreation units + case 26: //Outpost Switch + { + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 31: //Venture Warp Station + { + tmpMsg = MsgBuilder->BuildCharUseVentureWarpMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 28: //Fahrzeug Depot Interface + { + tmpMsg = MsgBuilder->BuildCharUseVhcTerminalMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 11: //Appartement Klingel/�ffner + { + if ( Appartements->CanFreelyEnter( nChar, nChar->GetLocation() ) ) + { + if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) + { + if ( tFurnitureTemplate->GetLinkedObjectID() ) + { + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + if ( WorldActors->GetLinkedObjectID( mRawItemID ) ) + { + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + } + else + { + tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 5 ); // Ring + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 12: //Standard Button + { + if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) + { + if ( tFurnitureTemplate->GetLinkedObjectID() ) + { + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + if ( WorldActors->GetLinkedObjectID( mRawItemID ) ) + { + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + WorldActors->GetLinkedObjectID( mRawItemID ), CurrentWorld->GetDoor( WorldActors->GetLinkedObjectID( mRawItemID ) )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 13: //Hack Button + { + if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) + { + if ( tFurnitureTemplate->GetLinkedObjectID() ) + { + if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons + { + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked! + nClient->SendUDPMessage( tmpMsg ); + } + + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID ); + if ( linkobjID ) + { + if ( nClient->GetAccountLevel() >= PAL_GM ) // Allow GameMasters and higher to just bypass HackButtons + { + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 106 ); // Damn, locked! + nClient->SendUDPMessage( tmpMsg ); + } + + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + case 23: //EINTRITTSGELD BUTTON + { + if ( tHandleDynamicActor == false && tFurnitureTemplate != NULL ) + { + if ( tFurnitureTemplate->GetLinkedObjectID() ) + { + uint32_t OldCash = nChar->GetCash(); + uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue(); + if ( OldCash >= DoorFee ) + { + uint32_t NewCash = nChar->SetCash( OldCash - DoorFee ); + PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash ); + nClient->SendUDPMessage( tmpMsg_cash ); + tmpMsg_cash = NULL; + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + tFurnitureTemplate->GetLinkedObjectID(), CurrentWorld->GetDoor( tFurnitureTemplate->GetLinkedObjectID() )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money! + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + uint32_t linkobjID = WorldActors->GetLinkedObjectID( mRawItemID ); + if ( linkobjID ) + { + uint32_t OldCash = nChar->GetCash(); + uint32_t DoorFee = ( uint32_t )tFurnitureModel->GetFunctionValue(); + if ( OldCash >= DoorFee ) + { + uint32_t NewCash = nChar->SetCash( OldCash - DoorFee ); + PMessage* tmpMsg_cash = MsgBuilder->BuildCharMoneyUpdateMsg( nClient, NewCash ); + nClient->SendUDPMessage( tmpMsg_cash ); + tmpMsg_cash = NULL; + tmpMsg = MsgBuilder->BuildDoorOpenMsg( 0x80 + linkobjID, CurrentWorld->GetDoor( linkobjID )->IsDoubleDoor() ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildTextIniMsg( nClient, 6, 12 ); // You dont have enough money! + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 1: //Itemcontainer + { + // TODO: Add check if container is already open / Make containers persistent + // PContainer* tContainer = World->GetContainer(mRawItemID); + PContainer* tContainer = new PContainerAutoCompactOnClose( INV_CABINET_MAXSLOTS ); + int functionVal = tFurnitureModel->GetFunctionValue(); + if ( functionVal <= 5 ) // force full random for cabinets for item testing + functionVal = -1; + tContainer->RandomFill( INV_CABINET_MAXSLOTS, functionVal ); + + /*nItem = new PItem(19, 1, 250, 250, 250, 250, 250, 250); + if(nItem->GetItemID()); + tContainer->AddItem(nItem);*/ + if ( gDevDebug ) Console->Print( "%s Temporary container created", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + //if(gDevDebug) tContainer->Dump(); + if ( tContainer->StartUse( nChar->GetID() ) ) + { + nChar->SetContainerInExclusiveUse( tContainer ); + tmpMsg = MsgBuilder->BuildCharOpenContainerMsg( nClient, mRawItemID, tContainer ); + //tmpMsg->Dump(); + nClient->FragmentAndSendUDPMessage( tmpMsg, 0x05 ); + } + else + { + tmpMsg = MsgBuilder->BuildFurnitureActivateMsg( nClient, mRawItemID, 10 ); + nClient->SendUDPMessage( tmpMsg ); + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 32: // Text message + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, ( uint8_t )( 255 & tFurnitureModel->GetFunctionValue() ), mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + // Temp placeholder implementations ============================ + case 4: //Trader + { + snprintf( DbgMessage, 128, "That's a trader" ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 5: //Mineral + { + snprintf( DbgMessage, 128, "That's some minerals" ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 8: //Hackterminal + { + snprintf( DbgMessage, 128, "That's a hacking terminal" ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 14: //HOLOMATCH ENTRANCE + { + snprintf( DbgMessage, 128, "That's an holomatch entrance" ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 19: //CLANTERMINAL + { + snprintf( DbgMessage, 128, "That's a clan terminal" ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 25: //EXPLOSIVE + { + snprintf( DbgMessage, 128, "That's explosive !" ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + case 0: //May be roadsign if touchable + { + if ( ( tFurnitureModel->GetUseFlags() & ufTouchable ) ) // Touchable ? + { + snprintf( DbgMessage, 128, "You're at %s", tFurnitureModel->GetName().c_str() ); + Chat->send( nClient, CHAT_GM, "Information", DbgMessage ); + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + // else we continue to undefined + } + case 27: //Old goguardian + //case 21: //LOCATION FOR 20 + //case 22: // + case 24: //TUTORIALEXIT + //case 30: //Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle) + { + tmpMsg = MsgBuilder->BuildCharUseFurnitureMsg( nClient, mRawItemID ); + nClient->SendUDPMessage( tmpMsg ); + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + break; + } + + default: + break; + } + } + } + else + { + if ( gDevDebug ) + Console->Print( "%s Item not known from world template (maybe seen as PASSIVE ?)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + } + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + } + else + { + Console->Print( RED, BLACK, "[ERROR] PUdpUseObject::DoAction : No World defined for client %d (char %d)", nClient->GetID(), nChar->GetID() ); + mDecodeData->mState = DECODE_ACTION_FAILED | DECODE_ACTION_DONE | DECODE_FINISHED; + } + + return true; +} + +/**** PUdpCloseItemContainer ****/ + +PUdpCloseItemContainer::PUdpCloseItemContainer( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x27"; +} + +PUdpMsgAnalyser* PUdpCloseItemContainer::Analyse() +{ + mDecodeData->mName << "=Closing item container"; + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpCloseItemContainer::DoAction() +{ +// PClient* nClient = mDecodeData->mClient; +// PChar* nChar = nClient->GetChar(); + + PChar* nChar = mDecodeData->mClient->GetChar(); + PContainer* tContainer = nChar->GetContainerInExclusiveUse(); + if ( tContainer ) + { + nChar->SetContainerInExclusiveUse( NULL ); + tContainer->EndUse( nChar->GetID() ); + if ( ! tContainer->GetOwnerId() ) + { + delete tContainer; + if ( gDevDebug ) Console->Print( "%s Temporary container deleted", Console->ColorText( CYAN, BLACK, "[DEBUG]" ) ); + } + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpUseObject.hxx b/TinNS/Source/GameServer/Decoder/UdpUseObject.hxx index 0b22681..d701157 100644 --- a/TinNS/Source/GameServer/Decoder/UdpUseObject.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpUseObject.hxx @@ -1,25 +1,25 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpUseObject : public PUdpMsgAnalyser { -private: - uint32_t mRawItemID; - - void OldHandler(); // Temp during migration only - -public: - PUdpUseObject(PMsgDecodeData *nDecodeData); - //~PUdpUseObject(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpCloseItemContainer : public PUdpMsgAnalyser { -public: - PUdpCloseItemContainer(PMsgDecodeData *nDecodeData); - //~PUdpCloseItemContainer(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpUseObject : public PUdpMsgAnalyser { +private: + uint32_t mRawItemID; + + void OldHandler(); // Temp during migration only + +public: + PUdpUseObject(PMsgDecodeData *nDecodeData); + //~PUdpUseObject(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpCloseItemContainer : public PUdpMsgAnalyser { +public: + PUdpCloseItemContainer(PMsgDecodeData *nDecodeData); + //~PUdpCloseItemContainer(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpVehicle.cxx b/TinNS/Source/GameServer/Decoder/UdpVehicle.cxx index a593eca..efcbec6 100644 --- a/TinNS/Source/GameServer/Decoder/UdpVehicle.cxx +++ b/TinNS/Source/GameServer/Decoder/UdpVehicle.cxx @@ -1,410 +1,410 @@ -#include "GameServer/Decoder/Includes.hxx" -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PUdpVhcMove ****/ - -PUdpVhcMove::PUdpVhcMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x32"; -} - -PUdpMsgAnalyser* PUdpVhcMove::Analyse() -{ - mDecodeData->mName << "=Vhc move"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 ); - - *nMsg >> mVhcLocalId; - *nMsg >> mMoveType; // 0 for subway/chair, 3 for vhc, 7 in nc2.2 - *nMsg >> mNewY; - *nMsg >> mNewZ; - *nMsg >> mNewX; - *nMsg >> mNewUD; // neutral :=0x7f, > := upward, < := downward - *nMsg >> mNewLR; - *nMsg >> mNewRoll; // neutral := 0x7fff > := bank left, < := bank right - *nMsg >> mUnk1; - *nMsg >> mFF; - *nMsg >> mAction; -//0 = not moving -//&01 = Left -//&02 = Right -//&04 = Forward -//&08 = Back -//&10 = Shoot button -//&20 = Pushing down -//&40 = Pulling up -// - /* - --- rolling front+left - 13 b0 00 02 bf - 15 - 32 - c9 03 =short VhcId - 07 - c3 66 37 8b 47 6e 80 2a 88 70 27 22 - 81 - 01 00 - ff = speed% ? - 05 = forward+left ? - => srv resp - 13 6b 01 bd bf - 18 - 03 6a 01 32 c9 03 07 8b 66 37 8b d9 6d 80 e0 8f - ea 27 22 81 01 00 ff 05 - 0c - 03 6b 01 1f 01 00 30 5e 79 36 87 87 - 13 - 32 c9 03 03 8b 66 38 8b d9 6d 7f 2a 88 92 7f 01 00 00 05 - 0b - 20 ed 03 5d 5a c8 8d 9b 7b c2 00 - - --- stopped - 13 88 01 da bf - 13 - 32 - c9 03 =short VhcId - 03 - 05 - 66 36 8b 90 6d 7f 5b 9d 00 - 80 - 01 00 - 00 = speed% ? - 00 = no move - - */ - if ( gDevDebug ) - { - Console->Print( YELLOW, BLACK, "[DEBUG] VHC move type %d - objid %d", mMoveType, mVhcLocalId ); - //nMsg->Dump(); - Console->Print( "X=%d Y=%d Z=%d Act=%d", mNewX - 768, mNewY - 768, mNewZ - 768, mAction ); - Console->Print( "LR=%d UD=%d Ro=%d Unk=%d Act=%02x ff=%x", mNewLR, mNewUD, mNewRoll, mUnk1, mAction, mFF ); - Console->Print( "Msg len: %d", nMsg->U8Data( mDecodeData->Sub0x13Start ) ); - } - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpVhcMove::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords); - PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() ); - - if ( CurrentWorld ) - { - PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVhcLocalId ); - if ( tVhc ) - { - //Todo: calc & mem Speed & Accel vectors - PVhcCoordinates nPos; - nPos.SetPosition( mNewY - 768, mNewZ - 768, mNewX - 768, mNewUD, mNewLR, mNewRoll, mAction, mUnk1, mFF ); - tVhc->SetPosition( &nPos ); - PMessage* tmpMsg = MsgBuilder->BuildVhcPosUpdate2Msg( tVhc ); - ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient ); - - tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( tVhc ); - ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient ); - - if( CurrentWorld->CheckVhcNeedZoning( &nPos ) ) - { - uint32_t destWorldId; - PVhcCoordinates destPos; - - if (( destWorldId = CurrentWorld->GetVhcZoningDestination( tVhc, &destPos ) ) ) - { - if ( nClient->GetDebugMode( DBG_LOCATION ) ) - { - uint8_t pH = 0; - uint8_t pV = 0; - Worlds->GetWorldmapFromWorldId( destWorldId, pH, pV ); - char DbgMessage[128]; - snprintf( DbgMessage, 128, "Vhc zoning to zone %c%02d (id %d)", ( 'a' + pV ), pH, destWorldId ); - Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); - } - - DoVhcZoning( tVhc, nClient->GetChar()->GetLocation(), destWorldId, &destPos ); - } - } - } - else - Console->Print( RED, BLACK, "[Error] PUdpVhcMove: Inexistant vhc Id %d", mVhcLocalId ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - -// Failures are not managed yet -bool PUdpVhcMove::DoVhcZoning( PSpawnedVehicle* currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates* destPos ) -{ - uint32_t seatedCharsId[8]; - uint32_t vhcGlobalId = currVhc->GetVehicleId(); - uint32_t vhcLocalId = currVhc->GetLocalId(); - PVhcCoordinates currCoords = currVhc->GetPosition(); - uint8_t numSeats = currVhc->GetNumSeats(); - uint32_t sittingCharId; - PClient* sittingClient; - PClient* sittingClients[8]; - PMessage* tmpMsg; - - for ( uint8_t i = 0; i < numSeats; ++i ) - { - // Save seated chars list - seatedCharsId[i] = sittingCharId = currVhc->GetSeatUser( i ); - - if ( sittingCharId ) - { - sittingClients[i] = sittingClient = ClientManager->getClientByChar( sittingCharId ); - // Tag each client as zoning to avoid transient side effects - sittingClient->SetZoning(); - sittingClient->SetVhcZoning(); - // Trigger zoning - //tmpMsg = MsgBuilder->BuildGenrepZoningMsg( sittingClient, destWorldId, 0 ); // unknown value // 0x62bc or 0x2d4e - //sittingClient->SendUDPMessage( tmpMsg ); - // We send the unseat msg to the corresponding client only. - sittingClient->GetChar()->Coords.SetPosition( currCoords.GetY(), currCoords.GetZ(), currCoords.GetX() ); - tmpMsg = MsgBuilder->BuildCharExitSeatMsg( sittingClient ); - sittingClient->FillInUDP_ID( tmpMsg ); - sittingClient->SendUDPMessage( tmpMsg ); - } - else - sittingClients[i] = 0; - } - - // Unspawn vhc instance from local world - Vehicles->UnspawnVehicle( vhcGlobalId ); - tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( vhcLocalId ); - ClientManager->UDPBroadcast( tmpMsg, currWorldId ); - - // Spawn vhc instance in destWorld - PSpawnedVehicle* destVhc = Vehicles->SpawnVehicle( vhcGlobalId, destWorldId, destPos ); - if ( destVhc ) - { - tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( destVhc ); - ClientManager->UDPBroadcast( tmpMsg, destWorldId ); - - vhcLocalId = destVhc->GetLocalId(); - - // Update chars seat in use and restore vhc used seats - PChar* sittingChar; - for ( uint8_t i = 0; i < numSeats; ++i ) - { - if (( sittingClient = sittingClients[i] ) ) - { - //if ( gDevDebug ) - Console->Print( "%s PUdpVhcMove::DoVhcZoning : Char %d sitting on vhc %d, seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), seatedCharsId[i], vhcLocalId, i ); - sittingChar = sittingClient->GetChar(); - sittingChar->SetSeatInUse( seat_vhc, vhcLocalId, i ); - sittingChar->Coords.SetPosition( destPos->GetY(), destPos->GetZ(), destPos->GetX() ); - destVhc->SetSeatUser( i, seatedCharsId[i] ); - } - } - } - else - { - for ( uint8_t i = 0; i < numSeats; ++i ) - { - if ( sittingClients[i] ) - { - sittingClients[i]->GetChar()->SetSeatInUse( seat_none ); - } - } - - return false; - } - - return true; - -} - -/**** PUdpVhcUse ****/ - -PUdpVhcUse::PUdpVhcUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x0f"; -} - -PUdpMsgAnalyser* PUdpVhcUse::Analyse() -{ - mDecodeData->mName << "=Try enter vhc"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 ); - *nMsg >> mVehicleID; // uint32_t - *nMsg >> mVehicleSeat; - - if ( gDevDebug ) - Console->Print( "%s Localid %d trying to enter vhc %d on seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mVehicleID, mVehicleSeat ); - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpVhcUse::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - PChar* nChar = nClient->GetChar(); - PMessage* tmpMsg; - - if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere - { - PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() ); - if ( CurrentWorld ) - { - PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID ); - if ( tVhc ) - { - if ( tVhc->SetSeatUser( mVehicleSeat, nChar->GetID() ) ) // Char was able to sit - { - nChar->SetSeatInUse( seat_vhc, mVehicleID, mVehicleSeat ); - tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mVehicleID, mVehicleSeat ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mVehicleID ); // Already in use - nClient->SendUDPMessage( tmpMsg ); - } - } - } - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - -void PUdpVhcUse::DoFreeSitting( PClient* nClient, PSpawnedVehicle* nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId ) -{ - PMessage* tmpMsg; - - if (( nVhc->GetNbFreeSeats() > 1 ) && ( nSeatId > nVhc->GetNumSeats() ) ) - { - uint8_t freeSeats = nVhc->GetFreeSeatsFlags(); - tmpMsg = MsgBuilder->BuildCharUseVhcMsg( nClient, nRawVhcLocalId, nVhc->GetInformation().GetVehicleType(), freeSeats ); - nClient->SendUDPMessage( tmpMsg ); // Open seat selection window - } - else - { - if ( nSeatId <= nVhc->GetNumSeats() ) - { - if ( nVhc->GetSeatUser( nSeatId ) ) - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, nRawVhcLocalId ); // Already in use - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - nSeatId = nVhc->GetFirstFreeSeat(); - - if ( nSeatId != 255 ) - { - if ( nVhc->SetSeatUser( nSeatId, nClient->GetChar()->GetID() ) ) // Char was able to sit - { - nClient->GetChar()->SetSeatInUse( seat_vhc, nRawVhcLocalId, nSeatId ); - tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nRawVhcLocalId, nSeatId ); - ClientManager->UDPBroadcast( tmpMsg, nClient ); - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, nRawVhcLocalId ); // Undefined failure - nClient->SendUDPMessage( tmpMsg ); - } - } - else - { - tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, nRawVhcLocalId ); // "No free seat" msg - nClient->SendUDPMessage( tmpMsg ); - } - } - } -} - -/**** PUdpSubwayUpdate ****/ - -PUdpSubwayUpdate::PUdpSubwayUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x00"; -} - -PUdpMsgAnalyser* PUdpSubwayUpdate::Analyse() -{ - uint8_t Dumb; - - mDecodeData->mName << "=Subway update"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 ); - - *nMsg >> mVehicleID; - *nMsg >> Dumb; - *nMsg >> mPosition; - *nMsg >> mDoorOpened; - - if ( gDevDebug ) - Console->Print( "%s Subway update 0x%4x : pos 0x%4x, status 0x%2x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, mPosition, mDoorOpened ); - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpSubwayUpdate::DoAction() -{ - /* No real use for that ? - Subway->UpdateInfo(mVehicleID, mPosition, mDoorOpened); - - PMessage* tmpMsg = MsgBuilder->BuildSubwaySingleUpdateMsg(mVehicleID, mPosition, mDoorOpened); - ClientManager->UDPBroadcast(tmpMsg, mDecodeData->mClient); - */ - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} - -/**** PUdpRequestVhcInfo ****/ - -PUdpRequestVhcInfo::PUdpRequestVhcInfo( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) -{ - nDecodeData->mName << "/0x27"; -} - -PUdpMsgAnalyser* PUdpRequestVhcInfo::Analyse() -{ - mDecodeData->mName << "=Request seatable object info"; - - PMessage* nMsg = mDecodeData->mMessage; - nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 ); - - *nMsg >> mVehicleID; - - if ( gDevDebug ) - Console->Print( "%s Request Seatable Info for 0x%04x :", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID ); - - mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; - return this; -} - -bool PUdpRequestVhcInfo::DoAction() -{ - PClient* nClient = mDecodeData->mClient; - //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords); - PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() ); - - if ( CurrentWorld ) - { - PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID ); - if ( tVhc ) - { - if ( gDevDebug ) - Console->Print("%s Sending Info for vhcId 0x%04x : type %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, tVhc->GetInformation().GetVehicleType() ); - PMessage* tmpMsg = MsgBuilder->BuildVhcInfoMsg( nClient, tVhc ); - nClient->SendUDPMessage( tmpMsg ); - } - else - Console->Print( RED, BLACK, "[Error] PUdpRequestVhcInfo: Inexistant vhc Id %d", mVehicleID ); - } - - mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; - return true; -} +#include "GameServer/Decoder/Includes.hxx" +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PUdpVhcMove ****/ + +PUdpVhcMove::PUdpVhcMove( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x32"; +} + +PUdpMsgAnalyser* PUdpVhcMove::Analyse() +{ + mDecodeData->mName << "=Vhc move"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 ); + + *nMsg >> mVhcLocalId; + *nMsg >> mMoveType; // 0 for subway/chair, 3 for vhc, 7 in nc2.2 + *nMsg >> mNewY; + *nMsg >> mNewZ; + *nMsg >> mNewX; + *nMsg >> mNewUD; // neutral :=0x7f, > := upward, < := downward + *nMsg >> mNewLR; + *nMsg >> mNewRoll; // neutral := 0x7fff > := bank left, < := bank right + *nMsg >> mUnk1; + *nMsg >> mFF; + *nMsg >> mAction; +//0 = not moving +//&01 = Left +//&02 = Right +//&04 = Forward +//&08 = Back +//&10 = Shoot button +//&20 = Pushing down +//&40 = Pulling up +// + /* + --- rolling front+left + 13 b0 00 02 bf + 15 + 32 + c9 03 =short VhcId + 07 + c3 66 37 8b 47 6e 80 2a 88 70 27 22 + 81 + 01 00 + ff = speed% ? + 05 = forward+left ? + => srv resp + 13 6b 01 bd bf + 18 + 03 6a 01 32 c9 03 07 8b 66 37 8b d9 6d 80 e0 8f + ea 27 22 81 01 00 ff 05 + 0c + 03 6b 01 1f 01 00 30 5e 79 36 87 87 + 13 + 32 c9 03 03 8b 66 38 8b d9 6d 7f 2a 88 92 7f 01 00 00 05 + 0b + 20 ed 03 5d 5a c8 8d 9b 7b c2 00 + + --- stopped + 13 88 01 da bf + 13 + 32 + c9 03 =short VhcId + 03 + 05 + 66 36 8b 90 6d 7f 5b 9d 00 + 80 + 01 00 + 00 = speed% ? + 00 = no move + + */ + if ( gDevDebug ) + { + Console->Print( YELLOW, BLACK, "[DEBUG] VHC move type %d - objid %d", mMoveType, mVhcLocalId ); + //nMsg->Dump(); + Console->Print( "X=%d Y=%d Z=%d Act=%d", mNewX - 768, mNewY - 768, mNewZ - 768, mAction ); + Console->Print( "LR=%d UD=%d Ro=%d Unk=%d Act=%02x ff=%x", mNewLR, mNewUD, mNewRoll, mUnk1, mAction, mFF ); + Console->Print( "Msg len: %d", nMsg->U8Data( mDecodeData->Sub0x13Start ) ); + } + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpVhcMove::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords); + PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() ); + + if ( CurrentWorld ) + { + PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVhcLocalId ); + if ( tVhc ) + { + //Todo: calc & mem Speed & Accel vectors + PVhcCoordinates nPos; + nPos.SetPosition( mNewY - 768, mNewZ - 768, mNewX - 768, mNewUD, mNewLR, mNewRoll, mAction, mUnk1, mFF ); + tVhc->SetPosition( &nPos ); + PMessage* tmpMsg = MsgBuilder->BuildVhcPosUpdate2Msg( tVhc ); + ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient ); + + tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( tVhc ); + ClientManager->UDPBroadcast( tmpMsg, mDecodeData->mClient ); + + if( CurrentWorld->CheckVhcNeedZoning( &nPos ) ) + { + uint32_t destWorldId; + PVhcCoordinates destPos; + + if (( destWorldId = CurrentWorld->GetVhcZoningDestination( tVhc, &destPos ) ) ) + { + if ( nClient->GetDebugMode( DBG_LOCATION ) ) + { + uint8_t pH = 0; + uint8_t pV = 0; + Worlds->GetWorldmapFromWorldId( destWorldId, pH, pV ); + char DbgMessage[128]; + snprintf( DbgMessage, 128, "Vhc zoning to zone %c%02d (id %d)", ( 'a' + pV ), pH, destWorldId ); + Chat->send( nClient, CHAT_GM, "Debug", DbgMessage ); + } + + DoVhcZoning( tVhc, nClient->GetChar()->GetLocation(), destWorldId, &destPos ); + } + } + } + else + Console->Print( RED, BLACK, "[Error] PUdpVhcMove: Inexistant vhc Id %d", mVhcLocalId ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + +// Failures are not managed yet +bool PUdpVhcMove::DoVhcZoning( PSpawnedVehicle* currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates* destPos ) +{ + uint32_t seatedCharsId[8]; + uint32_t vhcGlobalId = currVhc->GetVehicleId(); + uint32_t vhcLocalId = currVhc->GetLocalId(); + PVhcCoordinates currCoords = currVhc->GetPosition(); + uint8_t numSeats = currVhc->GetNumSeats(); + uint32_t sittingCharId; + PClient* sittingClient; + PClient* sittingClients[8]; + PMessage* tmpMsg; + + for ( uint8_t i = 0; i < numSeats; ++i ) + { + // Save seated chars list + seatedCharsId[i] = sittingCharId = currVhc->GetSeatUser( i ); + + if ( sittingCharId ) + { + sittingClients[i] = sittingClient = ClientManager->getClientByChar( sittingCharId ); + // Tag each client as zoning to avoid transient side effects + sittingClient->SetZoning(); + sittingClient->SetVhcZoning(); + // Trigger zoning + //tmpMsg = MsgBuilder->BuildGenrepZoningMsg( sittingClient, destWorldId, 0 ); // unknown value // 0x62bc or 0x2d4e + //sittingClient->SendUDPMessage( tmpMsg ); + // We send the unseat msg to the corresponding client only. + sittingClient->GetChar()->Coords.SetPosition( currCoords.GetY(), currCoords.GetZ(), currCoords.GetX() ); + tmpMsg = MsgBuilder->BuildCharExitSeatMsg( sittingClient ); + sittingClient->FillInUDP_ID( tmpMsg ); + sittingClient->SendUDPMessage( tmpMsg ); + } + else + sittingClients[i] = 0; + } + + // Unspawn vhc instance from local world + Vehicles->UnspawnVehicle( vhcGlobalId ); + tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg( vhcLocalId ); + ClientManager->UDPBroadcast( tmpMsg, currWorldId ); + + // Spawn vhc instance in destWorld + PSpawnedVehicle* destVhc = Vehicles->SpawnVehicle( vhcGlobalId, destWorldId, destPos ); + if ( destVhc ) + { + tmpMsg = MsgBuilder->BuildVhcPosUpdateMsg( destVhc ); + ClientManager->UDPBroadcast( tmpMsg, destWorldId ); + + vhcLocalId = destVhc->GetLocalId(); + + // Update chars seat in use and restore vhc used seats + PChar* sittingChar; + for ( uint8_t i = 0; i < numSeats; ++i ) + { + if (( sittingClient = sittingClients[i] ) ) + { + //if ( gDevDebug ) + Console->Print( "%s PUdpVhcMove::DoVhcZoning : Char %d sitting on vhc %d, seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), seatedCharsId[i], vhcLocalId, i ); + sittingChar = sittingClient->GetChar(); + sittingChar->SetSeatInUse( seat_vhc, vhcLocalId, i ); + sittingChar->Coords.SetPosition( destPos->GetY(), destPos->GetZ(), destPos->GetX() ); + destVhc->SetSeatUser( i, seatedCharsId[i] ); + } + } + } + else + { + for ( uint8_t i = 0; i < numSeats; ++i ) + { + if ( sittingClients[i] ) + { + sittingClients[i]->GetChar()->SetSeatInUse( seat_none ); + } + } + + return false; + } + + return true; + +} + +/**** PUdpVhcUse ****/ + +PUdpVhcUse::PUdpVhcUse( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x0f"; +} + +PUdpMsgAnalyser* PUdpVhcUse::Analyse() +{ + mDecodeData->mName << "=Try enter vhc"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 12 ); + *nMsg >> mVehicleID; // uint32_t + *nMsg >> mVehicleSeat; + + if ( gDevDebug ) + Console->Print( "%s Localid %d trying to enter vhc %d on seat %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mDecodeData->mClient->GetLocalID(), mVehicleID, mVehicleSeat ); + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpVhcUse::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + PChar* nChar = nClient->GetChar(); + PMessage* tmpMsg; + + if ( nChar->GetSeatInUse() == seat_none ) // Refuse if Char is already sitting somewhere + { + PWorld* CurrentWorld = Worlds->GetWorld( nChar->GetLocation() ); + if ( CurrentWorld ) + { + PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID ); + if ( tVhc ) + { + if ( tVhc->SetSeatUser( mVehicleSeat, nChar->GetID() ) ) // Char was able to sit + { + nChar->SetSeatInUse( seat_vhc, mVehicleID, mVehicleSeat ); + tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, mVehicleID, mVehicleSeat ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, mVehicleID ); // Already in use + nClient->SendUDPMessage( tmpMsg ); + } + } + } + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + +void PUdpVhcUse::DoFreeSitting( PClient* nClient, PSpawnedVehicle* nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId ) +{ + PMessage* tmpMsg; + + if (( nVhc->GetNbFreeSeats() > 1 ) && ( nSeatId > nVhc->GetNumSeats() ) ) + { + uint8_t freeSeats = nVhc->GetFreeSeatsFlags(); + tmpMsg = MsgBuilder->BuildCharUseVhcMsg( nClient, nRawVhcLocalId, nVhc->GetInformation().GetVehicleType(), freeSeats ); + nClient->SendUDPMessage( tmpMsg ); // Open seat selection window + } + else + { + if ( nSeatId <= nVhc->GetNumSeats() ) + { + if ( nVhc->GetSeatUser( nSeatId ) ) + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 1, nRawVhcLocalId ); // Already in use + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + nSeatId = nVhc->GetFirstFreeSeat(); + + if ( nSeatId != 255 ) + { + if ( nVhc->SetSeatUser( nSeatId, nClient->GetChar()->GetID() ) ) // Char was able to sit + { + nClient->GetChar()->SetSeatInUse( seat_vhc, nRawVhcLocalId, nSeatId ); + tmpMsg = MsgBuilder->BuildCharUseSeatMsg( nClient, nRawVhcLocalId, nSeatId ); + ClientManager->UDPBroadcast( tmpMsg, nClient ); + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 0, nRawVhcLocalId ); // Undefined failure + nClient->SendUDPMessage( tmpMsg ); + } + } + else + { + tmpMsg = MsgBuilder->BuildText100Msg( nClient, 5, nRawVhcLocalId ); // "No free seat" msg + nClient->SendUDPMessage( tmpMsg ); + } + } + } +} + +/**** PUdpSubwayUpdate ****/ + +PUdpSubwayUpdate::PUdpSubwayUpdate( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x00"; +} + +PUdpMsgAnalyser* PUdpSubwayUpdate::Analyse() +{ + uint8_t Dumb; + + mDecodeData->mName << "=Subway update"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 ); + + *nMsg >> mVehicleID; + *nMsg >> Dumb; + *nMsg >> mPosition; + *nMsg >> mDoorOpened; + + if ( gDevDebug ) + Console->Print( "%s Subway update 0x%4x : pos 0x%4x, status 0x%2x", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, mPosition, mDoorOpened ); + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpSubwayUpdate::DoAction() +{ + /* No real use for that ? + Subway->UpdateInfo(mVehicleID, mPosition, mDoorOpened); + + PMessage* tmpMsg = MsgBuilder->BuildSubwaySingleUpdateMsg(mVehicleID, mPosition, mDoorOpened); + ClientManager->UDPBroadcast(tmpMsg, mDecodeData->mClient); + */ + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} + +/**** PUdpRequestVhcInfo ****/ + +PUdpRequestVhcInfo::PUdpRequestVhcInfo( PMsgDecodeData* nDecodeData ) : PUdpMsgAnalyser( nDecodeData ) +{ + nDecodeData->mName << "/0x27"; +} + +PUdpMsgAnalyser* PUdpRequestVhcInfo::Analyse() +{ + mDecodeData->mName << "=Request seatable object info"; + + PMessage* nMsg = mDecodeData->mMessage; + nMsg->SetNextByteOffset( mDecodeData->Sub0x13Start + 2 ); + + *nMsg >> mVehicleID; + + if ( gDevDebug ) + Console->Print( "%s Request Seatable Info for 0x%04x :", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID ); + + mDecodeData->mState = DECODE_ACTION_READY | DECODE_FINISHED; + return this; +} + +bool PUdpRequestVhcInfo::DoAction() +{ + PClient* nClient = mDecodeData->mClient; + //PCharCoordinates* nCoords = &(nClient->GetChar()->Coords); + PWorld* CurrentWorld = Worlds->GetWorld( nClient->GetChar()->GetLocation() ); + + if ( CurrentWorld ) + { + PSpawnedVehicle* tVhc = CurrentWorld->GetSpawnedVehicles()->GetVehicle( mVehicleID ); + if ( tVhc ) + { + if ( gDevDebug ) + Console->Print("%s Sending Info for vhcId 0x%04x : type %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), mVehicleID, tVhc->GetInformation().GetVehicleType() ); + PMessage* tmpMsg = MsgBuilder->BuildVhcInfoMsg( nClient, tVhc ); + nClient->SendUDPMessage( tmpMsg ); + } + else + Console->Print( RED, BLACK, "[Error] PUdpRequestVhcInfo: Inexistant vhc Id %d", mVehicleID ); + } + + mDecodeData->mState = DECODE_ACTION_DONE | DECODE_FINISHED; + return true; +} diff --git a/TinNS/Source/GameServer/Decoder/UdpVehicle.hxx b/TinNS/Source/GameServer/Decoder/UdpVehicle.hxx index bd93524..fbcf06a 100644 --- a/TinNS/Source/GameServer/Decoder/UdpVehicle.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpVehicle.hxx @@ -1,66 +1,66 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PSpawnedVehicle; -class PVhcCoordinates; - -class PUdpVhcMove : public PUdpMsgAnalyser { -private: - uint16_t mVhcLocalId; - uint16_t mNewY; - uint16_t mNewZ; - uint16_t mNewX; - uint16_t mNewLR; - uint16_t mNewRoll; - uint16_t mUnk1; // always 0x0001 ? - uint8_t mMoveType; - uint8_t mNewUD; - uint8_t mFF; // always 0xff ? - uint8_t mAction; // &1 = Left, &2 = Right, &4 = Forward, &8 = Backward - -public: - PUdpVhcMove(PMsgDecodeData *nDecodeData); - //~PUdpVhcMove(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - bool DoVhcZoning(PSpawnedVehicle *currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates *destPos); -}; - -class PUdpVhcUse : public PUdpMsgAnalyser { -private: - uint32_t mVehicleID; - uint8_t mVehicleSeat; - -public: - PUdpVhcUse(PMsgDecodeData *nDecodeData); - //~PUdpVhcUse(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - static void DoFreeSitting(PClient *nClient, PSpawnedVehicle *nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId = 254); -}; - -class PUdpSubwayUpdate : public PUdpMsgAnalyser { -private: - uint32_t mVehicleID; - uint16_t mPosition; - uint8_t mDoorOpened; - -public: - PUdpSubwayUpdate(PMsgDecodeData *nDecodeData); - //~PUdpSubwayUpdate(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpRequestVhcInfo : public PUdpMsgAnalyser { -private: - uint32_t mVehicleID; - -public: - PUdpRequestVhcInfo(PMsgDecodeData *nDecodeData); - //~PUdpRequestVhcInfo(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PSpawnedVehicle; +class PVhcCoordinates; + +class PUdpVhcMove : public PUdpMsgAnalyser { +private: + uint16_t mVhcLocalId; + uint16_t mNewY; + uint16_t mNewZ; + uint16_t mNewX; + uint16_t mNewLR; + uint16_t mNewRoll; + uint16_t mUnk1; // always 0x0001 ? + uint8_t mMoveType; + uint8_t mNewUD; + uint8_t mFF; // always 0xff ? + uint8_t mAction; // &1 = Left, &2 = Right, &4 = Forward, &8 = Backward + +public: + PUdpVhcMove(PMsgDecodeData *nDecodeData); + //~PUdpVhcMove(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + bool DoVhcZoning(PSpawnedVehicle *currVhc, uint32_t currWorldId, uint32_t destWorldId, PVhcCoordinates *destPos); +}; + +class PUdpVhcUse : public PUdpMsgAnalyser { +private: + uint32_t mVehicleID; + uint8_t mVehicleSeat; + +public: + PUdpVhcUse(PMsgDecodeData *nDecodeData); + //~PUdpVhcUse(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + static void DoFreeSitting(PClient *nClient, PSpawnedVehicle *nVhc, uint32_t nRawVhcLocalId, uint8_t nSeatId = 254); +}; + +class PUdpSubwayUpdate : public PUdpMsgAnalyser { +private: + uint32_t mVehicleID; + uint16_t mPosition; + uint8_t mDoorOpened; + +public: + PUdpSubwayUpdate(PMsgDecodeData *nDecodeData); + //~PUdpSubwayUpdate(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpRequestVhcInfo : public PUdpMsgAnalyser { +private: + uint32_t mVehicleID; + +public: + PUdpRequestVhcInfo(PMsgDecodeData *nDecodeData); + //~PUdpRequestVhcInfo(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Decoder/UdpZoning.hxx b/TinNS/Source/GameServer/Decoder/UdpZoning.hxx index 9722fb3..f5f814c 100644 --- a/TinNS/Source/GameServer/Decoder/UdpZoning.hxx +++ b/TinNS/Source/GameServer/Decoder/UdpZoning.hxx @@ -1,80 +1,80 @@ -#pragma once - -#include -#include "GameServer/Decoder/UdpAnalyser.hxx" - -class PUdpZoning1 : public PUdpMsgAnalyser { -private: - uint32_t mNewLocation; - uint16_t mNewEntity; - uint8_t mUnknown; - -public: - PUdpZoning1(PMsgDecodeData *nDecodeData); - //~PUdpZoning1(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpZoning2 : public PUdpMsgAnalyser { -public: - PUdpZoning2(PMsgDecodeData *nDecodeData); - //~PUdpZoning2(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpGenrepZoning : public PUdpMsgAnalyser { -private: - uint32_t mNewLocation; - uint16_t mNewEntity; - -public: - PUdpGenrepZoning(PMsgDecodeData *nDecodeData); - //~PUdpGenrepZoning(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - static bool DoEffectiveZoning(PClient *nClient, uint32_t nNewLocation, uint16_t nNewEntity); -}; - -class PUdpAptGRZoning : public PUdpMsgAnalyser { -public: - PUdpAptGRZoning(PMsgDecodeData *nDecodeData); - //~PUdpAptGRZoning(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); - static bool DoEffectiveZoning(PClient *nClient); -}; - -class PUdpAddGenrepToList : public PUdpMsgAnalyser { -private: - uint32_t mLocation; - uint16_t mEntity; - -public: - PUdpAddGenrepToList(PMsgDecodeData *nDecodeData); - //~PUdpAddGenrepToList(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - -class PUdpAppartmentAccess : public PUdpMsgAnalyser { -private: - uint16_t mAppartmentPlace; - char *mPassword; - -public: - PUdpAppartmentAccess(PMsgDecodeData *nDecodeData); - //~PUdpAppartmentAccess(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; - - -class PUdpEndOfZoning : public PUdpMsgAnalyser { -public: - PUdpEndOfZoning(PMsgDecodeData *nDecodeData); - //~PUdpEndOfZoning(); - PUdpMsgAnalyser *Analyse(); - bool DoAction(); -}; +#pragma once + +#include +#include "GameServer/Decoder/UdpAnalyser.hxx" + +class PUdpZoning1 : public PUdpMsgAnalyser { +private: + uint32_t mNewLocation; + uint16_t mNewEntity; + uint8_t mUnknown; + +public: + PUdpZoning1(PMsgDecodeData *nDecodeData); + //~PUdpZoning1(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpZoning2 : public PUdpMsgAnalyser { +public: + PUdpZoning2(PMsgDecodeData *nDecodeData); + //~PUdpZoning2(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpGenrepZoning : public PUdpMsgAnalyser { +private: + uint32_t mNewLocation; + uint16_t mNewEntity; + +public: + PUdpGenrepZoning(PMsgDecodeData *nDecodeData); + //~PUdpGenrepZoning(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + static bool DoEffectiveZoning(PClient *nClient, uint32_t nNewLocation, uint16_t nNewEntity); +}; + +class PUdpAptGRZoning : public PUdpMsgAnalyser { +public: + PUdpAptGRZoning(PMsgDecodeData *nDecodeData); + //~PUdpAptGRZoning(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); + static bool DoEffectiveZoning(PClient *nClient); +}; + +class PUdpAddGenrepToList : public PUdpMsgAnalyser { +private: + uint32_t mLocation; + uint16_t mEntity; + +public: + PUdpAddGenrepToList(PMsgDecodeData *nDecodeData); + //~PUdpAddGenrepToList(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + +class PUdpAppartmentAccess : public PUdpMsgAnalyser { +private: + uint16_t mAppartmentPlace; + char *mPassword; + +public: + PUdpAppartmentAccess(PMsgDecodeData *nDecodeData); + //~PUdpAppartmentAccess(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; + + +class PUdpEndOfZoning : public PUdpMsgAnalyser { +public: + PUdpEndOfZoning(PMsgDecodeData *nDecodeData); + //~PUdpEndOfZoning(); + PUdpMsgAnalyser *Analyse(); + bool DoAction(); +}; diff --git a/TinNS/Source/GameServer/Definitions/AppartementPlaces.cxx b/TinNS/Source/GameServer/Definitions/AppartementPlaces.cxx index fa6078a..581ccd4 100644 --- a/TinNS/Source/GameServer/Definitions/AppartementPlaces.cxx +++ b/TinNS/Source/GameServer/Definitions/AppartementPlaces.cxx @@ -1,35 +1,35 @@ -#include "GameServer/Definitions/Includes.hxx" - -PDefAppPlace::PDefAppPlace() -{ -} - -bool PDefAppPlace::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0: // setentry - continue; - - case 1: // index - mIndex = atoi(i->c_str()); break; - - case 2: // name - mName = *i; break; - - case 3: // Exit World - mExitWorldID = atoi(i->c_str()); break; - - case 4: // Exit World entity - mExitWorldEntity = atoi(i->c_str()); break; - - case 5: // Sewer level - mSewerLevel = atoi(i->c_str()); break; - } - } - - return true; -} +#include "GameServer/Definitions/Includes.hxx" + +PDefAppPlace::PDefAppPlace() +{ +} + +bool PDefAppPlace::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0: // setentry + continue; + + case 1: // index + mIndex = atoi(i->c_str()); break; + + case 2: // name + mName = *i; break; + + case 3: // Exit World + mExitWorldID = atoi(i->c_str()); break; + + case 4: // Exit World entity + mExitWorldEntity = atoi(i->c_str()); break; + + case 5: // Sewer level + mSewerLevel = atoi(i->c_str()); break; + } + } + + return true; +} diff --git a/TinNS/Source/GameServer/Definitions/AppartementPlaces.hxx b/TinNS/Source/GameServer/Definitions/AppartementPlaces.hxx index 18d0268..f575958 100644 --- a/TinNS/Source/GameServer/Definitions/AppartementPlaces.hxx +++ b/TinNS/Source/GameServer/Definitions/AppartementPlaces.hxx @@ -1,25 +1,25 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefAppPlace : public PDef { -private : - //int32_t mIndex; - std::string mName; - int32_t mExitWorldID; - int32_t mExitWorldEntity; - int32_t mSewerLevel; - -public : - PDefAppPlace(); - //~PDefAppPlace(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline int32_t GetExitWorldID() const { return mExitWorldID; } - inline int32_t GetExitWorldEntity() const { return mExitWorldEntity; } - inline int32_t GetSewerLevel() const { return mSewerLevel; } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefAppPlace : public PDef { +private : + //int32_t mIndex; + std::string mName; + int32_t mExitWorldID; + int32_t mExitWorldEntity; + int32_t mSewerLevel; + +public : + PDefAppPlace(); + //~PDefAppPlace(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline int32_t GetExitWorldID() const { return mExitWorldID; } + inline int32_t GetExitWorldEntity() const { return mExitWorldEntity; } + inline int32_t GetSewerLevel() const { return mSewerLevel; } +}; diff --git a/TinNS/Source/GameServer/Definitions/Appartements.cxx b/TinNS/Source/GameServer/Definitions/Appartements.cxx index 9f37a69..c17da33 100644 --- a/TinNS/Source/GameServer/Definitions/Appartements.cxx +++ b/TinNS/Source/GameServer/Definitions/Appartements.cxx @@ -1,50 +1,50 @@ -#include "GameServer/Definitions/Includes.hxx" - -PDefAppartement::PDefAppartement() -{ -} - -bool PDefAppartement::LoadFromDef(PTokenList *Tokens) -{ - mFaction = 0; - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0: // setentry - continue; - - case 1: // index - mIndex = atoi(i->c_str()); break; - - case 2: // name - mName = *i; break; - - case 3: // world name - mWorldName = *i; break; - - case 4: // value - mValue = atoi(i->c_str()); break; - - case 5: // number of places - mPlaceCount = atoi(i->c_str()); break; - - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - mPlace[Idx-6] = atoi(i->c_str()); break; - - case 14: // faction if base appartement - mFaction = atoi(i->c_str()); break; - } - } -//Console->Print("%04d:%s file:%s val:%d places:%d pl1:%d pl2:%d pl8:%d faction:%d", -// mIndex, mName.c_str(), mWorldName.c_str(), mValue, mPlaceCount, mPlace[0], mPlace[1], mPlace[7], mFaction); - return true; -} +#include "GameServer/Definitions/Includes.hxx" + +PDefAppartement::PDefAppartement() +{ +} + +bool PDefAppartement::LoadFromDef(PTokenList *Tokens) +{ + mFaction = 0; + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0: // setentry + continue; + + case 1: // index + mIndex = atoi(i->c_str()); break; + + case 2: // name + mName = *i; break; + + case 3: // world name + mWorldName = *i; break; + + case 4: // value + mValue = atoi(i->c_str()); break; + + case 5: // number of places + mPlaceCount = atoi(i->c_str()); break; + + case 6: + case 7: + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + mPlace[Idx-6] = atoi(i->c_str()); break; + + case 14: // faction if base appartement + mFaction = atoi(i->c_str()); break; + } + } +//Console->Print("%04d:%s file:%s val:%d places:%d pl1:%d pl2:%d pl8:%d faction:%d", +// mIndex, mName.c_str(), mWorldName.c_str(), mValue, mPlaceCount, mPlace[0], mPlace[1], mPlace[7], mFaction); + return true; +} diff --git a/TinNS/Source/GameServer/Definitions/Appartements.hxx b/TinNS/Source/GameServer/Definitions/Appartements.hxx index 58dd293..fccd9ee 100644 --- a/TinNS/Source/GameServer/Definitions/Appartements.hxx +++ b/TinNS/Source/GameServer/Definitions/Appartements.hxx @@ -1,37 +1,37 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" -#include "GameServer/Definitions/Map.hxx" - -class PDefAppartement : public PDef { -private: - //int32_t mIndex; - std::string mName; - std::string mWorldName; - int32_t mValue; - int32_t mPlaceCount; - int32_t mPlace[8]; - int32_t mFaction; - -public: - PDefAppartement(); - //~PDefAppartement(); - - bool LoadFromDef(PTokenList *Tokens); - - inline int32_t GetID() const { return mIndex; } - inline const std::string &GetName() const { return mName; } - inline const std::string &GetWorldName() const { return mWorldName; } - inline int32_t GetValue() const { return mValue; } - inline int32_t GetPlaceCount() const { return mPlaceCount; } - inline int32_t GetPlace(int32_t nIdx) const { return ( (nIdx < mPlaceCount) ? mPlace[nIdx] : 0 ); } - inline int32_t GetFaction() const { return mFaction; } -}; - -class PDefAppartementsMap : public PDefMap { -public: - inline std::map::const_iterator ConstIteratorBegin() const { return mDefs.begin(); } - inline std::map::const_iterator ConstIteratorEnd() const { return mDefs.end(); } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" +#include "GameServer/Definitions/Map.hxx" + +class PDefAppartement : public PDef { +private: + //int32_t mIndex; + std::string mName; + std::string mWorldName; + int32_t mValue; + int32_t mPlaceCount; + int32_t mPlace[8]; + int32_t mFaction; + +public: + PDefAppartement(); + //~PDefAppartement(); + + bool LoadFromDef(PTokenList *Tokens); + + inline int32_t GetID() const { return mIndex; } + inline const std::string &GetName() const { return mName; } + inline const std::string &GetWorldName() const { return mWorldName; } + inline int32_t GetValue() const { return mValue; } + inline int32_t GetPlaceCount() const { return mPlaceCount; } + inline int32_t GetPlace(int32_t nIdx) const { return ( (nIdx < mPlaceCount) ? mPlace[nIdx] : 0 ); } + inline int32_t GetFaction() const { return mFaction; } +}; + +class PDefAppartementsMap : public PDefMap { +public: + inline std::map::const_iterator ConstIteratorBegin() const { return mDefs.begin(); } + inline std::map::const_iterator ConstIteratorEnd() const { return mDefs.end(); } +}; diff --git a/TinNS/Source/GameServer/Definitions/CharacterKinds.cxx b/TinNS/Source/GameServer/Definitions/CharacterKinds.cxx index 4ee96b9..74aae52 100644 --- a/TinNS/Source/GameServer/Definitions/CharacterKinds.cxx +++ b/TinNS/Source/GameServer/Definitions/CharacterKinds.cxx @@ -1,152 +1,152 @@ -#include -#include "GameServer/Definitions/Includes.hxx" -#include "GameServer/Includes.hxx" - -// charkinds are character templates used for player char creation - -PDefCharKind::PDefCharKind() -{ - mSkillInfo = 0; - memset(mInventory, 0, sizeof(mInventory)); -} - -PDefCharKind::~PDefCharKind() -{ - delete [] mSkillInfo; - for(PSkillPtsMap::const_iterator i=mSkillPts.begin(); i!=mSkillPts.end(); i++) - delete i->second; - for(PSubSkillPtsMap::const_iterator i=mSubSkillPts.begin(); i!=mSubSkillPts.end(); i++) - delete i->second; - for(PStartLevelMap::const_iterator i=mStartLevels.begin(); i!=mStartLevels.end(); i++) - delete i->second; -} - -bool PDefCharKind::LoadFromDef(PTokenList *Tokens) -{ - int NumSkills = GameDefs->Skills()->GetNumDefs(); - //int NumSubSkills = GameDefs->SubSkills()->GetNumDefs(); - - int SkillInfoStart = 4; - int TrainPtsStart = SkillInfoStart+NumSkills*3; - int LevelsStart = TrainPtsStart + 32*2; - int MoneyStart = LevelsStart + 16*2; - int InventoryStart = MoneyStart+1; - - mSkillInfo = new PSkillInfo[NumSkills]; - - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0 : // setentry - continue; - - case 1 : - mIndex = atoi(i->c_str()); break; - - case 2 : - mName = *i; break; - - case 3 : - mType = atoi(i->c_str()); break; - - } - - if((Idx >= SkillInfoStart) && (Idx < TrainPtsStart)) // skill info - { - int SkillIdx = (Idx-SkillInfoStart)/3; - int Value = atoi(i->c_str()); - - // start, max, grow per skill - switch((Idx-SkillInfoStart)%3) - { - case 0 : mSkillInfo[SkillIdx].mStart = Value; break; - case 1 : mSkillInfo[SkillIdx].mMax = Value; break; - case 2 : mSkillInfo[SkillIdx].mGrow = Value; break; - } - } else - // 32 skill/subskill train pts - if((Idx >= TrainPtsStart) && (Idx < LevelsStart)) - { - static int SkillIndex = 0; - int Index = Idx-TrainPtsStart; - if((Index&1)==0) - { - SkillIndex = atoi(i->c_str()); - } else - { - if(SkillIndex >= 1000) // skill - { - const PDefSkill *Skill = GameDefs->Skills()->GetDef(SkillIndex-1000); - if(Skill) - { - int Index = Skill->GetIndex()-1; - PSkillPtsInfo *CurrentSkillPts = new PSkillPtsInfo(); - CurrentSkillPts->mSkill = Index; - CurrentSkillPts->mPoints = atoi(i->c_str()); - mSkillPts.insert(std::make_pair(Index, CurrentSkillPts)); - } else - { - if(SkillIndex-1000 != 0) - Console->Print("Charkind def: invalid skill index %i", SkillIndex-1000); - } - } else // subskill - { - const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(SkillIndex); - if(SubSkill) - { - int Index = SubSkill->GetIndex()-1; - PSubSkillPtsInfo *CurrentSubSkillPts = new PSubSkillPtsInfo(); - CurrentSubSkillPts->mSubSkill = Index; - CurrentSubSkillPts->mPoints = atoi(i->c_str()); - mSubSkillPts.insert(std::make_pair(Index, CurrentSubSkillPts)); - } else - { - if(SkillIndex != 0) - Console->Print("Charkind def: invalid subskill index %i", SkillIndex); - } - } - } - } else - // 16 subskill start levels - if((Idx >= LevelsStart) && (Idx < MoneyStart)) - { - static int LevelIndex = 0; - int Index = Idx-NumSkills*3+4+(32*2); - if((Index&1)==0) - { - LevelIndex = atoi(i->c_str()); - } else - { - if(LevelIndex > 0) - { - const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(LevelIndex); - if(SubSkill) - { - PStartLevelInfo *Level = new PStartLevelInfo(); - Level->mSubSkill = SubSkill->GetIndex(); - Level->mLevel = atoi(i->c_str()); - mStartLevels.insert(std::make_pair(Level->mSubSkill, Level)); - } else - { - Console->Print("Charkind def: invalid subskill index %i", LevelIndex); - } - } - } - } else - // money - if((Idx >= MoneyStart) && (Idx < InventoryStart)) - { - mMoney = atoi(i->c_str()); - } else - // inventory - if((Idx >= InventoryStart) && (Idx < InventoryStart+8)) - { - mInventory[Idx-InventoryStart] = atoi(i->c_str()); - } - } - - return true; -} - +#include +#include "GameServer/Definitions/Includes.hxx" +#include "GameServer/Includes.hxx" + +// charkinds are character templates used for player char creation + +PDefCharKind::PDefCharKind() +{ + mSkillInfo = 0; + memset(mInventory, 0, sizeof(mInventory)); +} + +PDefCharKind::~PDefCharKind() +{ + delete [] mSkillInfo; + for(PSkillPtsMap::const_iterator i=mSkillPts.begin(); i!=mSkillPts.end(); i++) + delete i->second; + for(PSubSkillPtsMap::const_iterator i=mSubSkillPts.begin(); i!=mSubSkillPts.end(); i++) + delete i->second; + for(PStartLevelMap::const_iterator i=mStartLevels.begin(); i!=mStartLevels.end(); i++) + delete i->second; +} + +bool PDefCharKind::LoadFromDef(PTokenList *Tokens) +{ + int NumSkills = GameDefs->Skills()->GetNumDefs(); + //int NumSubSkills = GameDefs->SubSkills()->GetNumDefs(); + + int SkillInfoStart = 4; + int TrainPtsStart = SkillInfoStart+NumSkills*3; + int LevelsStart = TrainPtsStart + 32*2; + int MoneyStart = LevelsStart + 16*2; + int InventoryStart = MoneyStart+1; + + mSkillInfo = new PSkillInfo[NumSkills]; + + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0 : // setentry + continue; + + case 1 : + mIndex = atoi(i->c_str()); break; + + case 2 : + mName = *i; break; + + case 3 : + mType = atoi(i->c_str()); break; + + } + + if((Idx >= SkillInfoStart) && (Idx < TrainPtsStart)) // skill info + { + int SkillIdx = (Idx-SkillInfoStart)/3; + int Value = atoi(i->c_str()); + + // start, max, grow per skill + switch((Idx-SkillInfoStart)%3) + { + case 0 : mSkillInfo[SkillIdx].mStart = Value; break; + case 1 : mSkillInfo[SkillIdx].mMax = Value; break; + case 2 : mSkillInfo[SkillIdx].mGrow = Value; break; + } + } else + // 32 skill/subskill train pts + if((Idx >= TrainPtsStart) && (Idx < LevelsStart)) + { + static int SkillIndex = 0; + int Index = Idx-TrainPtsStart; + if((Index&1)==0) + { + SkillIndex = atoi(i->c_str()); + } else + { + if(SkillIndex >= 1000) // skill + { + const PDefSkill *Skill = GameDefs->Skills()->GetDef(SkillIndex-1000); + if(Skill) + { + int Index = Skill->GetIndex()-1; + PSkillPtsInfo *CurrentSkillPts = new PSkillPtsInfo(); + CurrentSkillPts->mSkill = Index; + CurrentSkillPts->mPoints = atoi(i->c_str()); + mSkillPts.insert(std::make_pair(Index, CurrentSkillPts)); + } else + { + if(SkillIndex-1000 != 0) + Console->Print("Charkind def: invalid skill index %i", SkillIndex-1000); + } + } else // subskill + { + const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(SkillIndex); + if(SubSkill) + { + int Index = SubSkill->GetIndex()-1; + PSubSkillPtsInfo *CurrentSubSkillPts = new PSubSkillPtsInfo(); + CurrentSubSkillPts->mSubSkill = Index; + CurrentSubSkillPts->mPoints = atoi(i->c_str()); + mSubSkillPts.insert(std::make_pair(Index, CurrentSubSkillPts)); + } else + { + if(SkillIndex != 0) + Console->Print("Charkind def: invalid subskill index %i", SkillIndex); + } + } + } + } else + // 16 subskill start levels + if((Idx >= LevelsStart) && (Idx < MoneyStart)) + { + static int LevelIndex = 0; + int Index = Idx-NumSkills*3+4+(32*2); + if((Index&1)==0) + { + LevelIndex = atoi(i->c_str()); + } else + { + if(LevelIndex > 0) + { + const PDefSubSkill *SubSkill = GameDefs->SubSkills()->GetDef(LevelIndex); + if(SubSkill) + { + PStartLevelInfo *Level = new PStartLevelInfo(); + Level->mSubSkill = SubSkill->GetIndex(); + Level->mLevel = atoi(i->c_str()); + mStartLevels.insert(std::make_pair(Level->mSubSkill, Level)); + } else + { + Console->Print("Charkind def: invalid subskill index %i", LevelIndex); + } + } + } + } else + // money + if((Idx >= MoneyStart) && (Idx < InventoryStart)) + { + mMoney = atoi(i->c_str()); + } else + // inventory + if((Idx >= InventoryStart) && (Idx < InventoryStart+8)) + { + mInventory[Idx-InventoryStart] = atoi(i->c_str()); + } + } + + return true; +} + diff --git a/TinNS/Source/GameServer/Definitions/CharacterKinds.hxx b/TinNS/Source/GameServer/Definitions/CharacterKinds.hxx index 4f86772..ecfe19d 100644 --- a/TinNS/Source/GameServer/Definitions/CharacterKinds.hxx +++ b/TinNS/Source/GameServer/Definitions/CharacterKinds.hxx @@ -1,82 +1,82 @@ -#pragma once - -#include -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -struct PSkillInfo { - int32_t mStart; - int32_t mMax; - int32_t mGrow; - - inline PSkillInfo() - { - mStart = mMax = mGrow = 0; - } -}; - -struct PSkillPtsInfo { - int32_t mSkill; - int32_t mPoints; - - inline PSkillPtsInfo() - { - mSkill = mPoints = 0; - } -}; - -struct PSubSkillPtsInfo { - int32_t mSubSkill; - int32_t mPoints; - - inline PSubSkillPtsInfo() - { - mSubSkill = mPoints = 0; - } -}; - -struct PStartLevelInfo { - int32_t mSubSkill; - int32_t mLevel; - - inline PStartLevelInfo() - { - mSubSkill = mLevel = 0; - } - -}; - -class PDefCharKind : public PDef { -private: - typedef std::map PSkillPtsMap; - typedef std::map PSubSkillPtsMap; - typedef std::map PStartLevelMap; - - //int32_t mIndex; - std::string mName; - int32_t mType; - - // TODO: shouldnt this be a map? - PSkillInfo *mSkillInfo; - - PSkillPtsMap mSkillPts; - PSubSkillPtsMap mSubSkillPts; - PStartLevelMap mStartLevels; - int32_t mMoney; - uint32_t mInventory[8]; - -public: - PDefCharKind(); - ~PDefCharKind(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline int32_t GetType() const { return mType; } - inline const PSkillInfo &GetSkillInfo(int32_t Skill) const { return mSkillInfo[Skill-1]; } - - inline int32_t GetStartMoney() const { return mMoney; } - inline uint32_t GetStartInventory(uint8_t Index) const { return ((Index < 7) ? mInventory[Index] : 0); } - // TODO: mission get() functions -}; +#pragma once + +#include +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +struct PSkillInfo { + int32_t mStart; + int32_t mMax; + int32_t mGrow; + + inline PSkillInfo() + { + mStart = mMax = mGrow = 0; + } +}; + +struct PSkillPtsInfo { + int32_t mSkill; + int32_t mPoints; + + inline PSkillPtsInfo() + { + mSkill = mPoints = 0; + } +}; + +struct PSubSkillPtsInfo { + int32_t mSubSkill; + int32_t mPoints; + + inline PSubSkillPtsInfo() + { + mSubSkill = mPoints = 0; + } +}; + +struct PStartLevelInfo { + int32_t mSubSkill; + int32_t mLevel; + + inline PStartLevelInfo() + { + mSubSkill = mLevel = 0; + } + +}; + +class PDefCharKind : public PDef { +private: + typedef std::map PSkillPtsMap; + typedef std::map PSubSkillPtsMap; + typedef std::map PStartLevelMap; + + //int32_t mIndex; + std::string mName; + int32_t mType; + + // TODO: shouldnt this be a map? + PSkillInfo *mSkillInfo; + + PSkillPtsMap mSkillPts; + PSubSkillPtsMap mSubSkillPts; + PStartLevelMap mStartLevels; + int32_t mMoney; + uint32_t mInventory[8]; + +public: + PDefCharKind(); + ~PDefCharKind(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline int32_t GetType() const { return mType; } + inline const PSkillInfo &GetSkillInfo(int32_t Skill) const { return mSkillInfo[Skill-1]; } + + inline int32_t GetStartMoney() const { return mMoney; } + inline uint32_t GetStartInventory(uint8_t Index) const { return ((Index < 7) ? mInventory[Index] : 0); } + // TODO: mission get() functions +}; diff --git a/TinNS/Source/GameServer/Definitions/Characters.cxx b/TinNS/Source/GameServer/Definitions/Characters.cxx index 95b2ddf..3e27efc 100644 --- a/TinNS/Source/GameServer/Definitions/Characters.cxx +++ b/TinNS/Source/GameServer/Definitions/Characters.cxx @@ -1,55 +1,55 @@ -#include "GameServer/Definitions/Includes.hxx" - -// characters.def contains all ingame characters (player types, npc's, monsters) - -PDefCharacter::PDefCharacter() -{ - mIndex = -1; - mName = "unknown"; - mModel = -1; -} - -bool PDefCharacter::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0 : // setentry - continue; - - case 1 : - mIndex = atoi(i->c_str()); break; - - case 2 : - mName = *i; break; - - case 3 : - mModel = atoi(i->c_str()); break; - - case 4 : // 0 - continue; - - case 5 : - mHead = atoi(i->c_str()); break; - - case 6 : - mTorso = atoi(i->c_str()); break; - - case 7 : - mLegs = atoi(i->c_str()); break; - - case 8 : - mColor = atoi(i->c_str()); break; - - case 9 : - mBrightness = atoi(i->c_str()); break; - } - - if(Idx==9) - return true; - } - - return false; -} +#include "GameServer/Definitions/Includes.hxx" + +// characters.def contains all ingame characters (player types, npc's, monsters) + +PDefCharacter::PDefCharacter() +{ + mIndex = -1; + mName = "unknown"; + mModel = -1; +} + +bool PDefCharacter::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0 : // setentry + continue; + + case 1 : + mIndex = atoi(i->c_str()); break; + + case 2 : + mName = *i; break; + + case 3 : + mModel = atoi(i->c_str()); break; + + case 4 : // 0 + continue; + + case 5 : + mHead = atoi(i->c_str()); break; + + case 6 : + mTorso = atoi(i->c_str()); break; + + case 7 : + mLegs = atoi(i->c_str()); break; + + case 8 : + mColor = atoi(i->c_str()); break; + + case 9 : + mBrightness = atoi(i->c_str()); break; + } + + if(Idx==9) + return true; + } + + return false; +} diff --git a/TinNS/Source/GameServer/Definitions/Characters.hxx b/TinNS/Source/GameServer/Definitions/Characters.hxx index 3abc2c0..f65e971 100644 --- a/TinNS/Source/GameServer/Definitions/Characters.hxx +++ b/TinNS/Source/GameServer/Definitions/Characters.hxx @@ -1,31 +1,31 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefCharacter : public PDef { -private: - //int32_t mIndex; - std::string mName; - int32_t mModel; - int32_t mHead; - int32_t mTorso; - int32_t mLegs; - int32_t mColor; - int32_t mBrightness; - -public: - PDefCharacter(); - //~PDefCharacter(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline int32_t GetModel() const { return mModel; } - inline int32_t GetHead() const { return mHead; } - inline int32_t GetTorso() const { return mTorso; } - inline int32_t GetLegs() const { return mLegs; } - inline int32_t GetColor() const { return mColor; } - inline int32_t GetBrightness() const { return mBrightness; } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefCharacter : public PDef { +private: + //int32_t mIndex; + std::string mName; + int32_t mModel; + int32_t mHead; + int32_t mTorso; + int32_t mLegs; + int32_t mColor; + int32_t mBrightness; + +public: + PDefCharacter(); + //~PDefCharacter(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline int32_t GetModel() const { return mModel; } + inline int32_t GetHead() const { return mHead; } + inline int32_t GetTorso() const { return mTorso; } + inline int32_t GetLegs() const { return mLegs; } + inline int32_t GetColor() const { return mColor; } + inline int32_t GetBrightness() const { return mBrightness; } +}; diff --git a/TinNS/Source/GameServer/Definitions/Factions.cxx b/TinNS/Source/GameServer/Definitions/Factions.cxx index 2e5ab9a..c4a8822 100644 --- a/TinNS/Source/GameServer/Definitions/Factions.cxx +++ b/TinNS/Source/GameServer/Definitions/Factions.cxx @@ -1,56 +1,56 @@ -#include -#include "GameServer/Definitions/Includes.hxx" - -PDefFaction::PDefFaction() -{ - memset(mRelations, 0, sizeof(mRelations)); // ... array members supposed to by auto-initialized by C++ -} - -bool PDefFaction::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - // setfracc 19 "Monster" -1024 0 0 -1024 -1024 -1024 -1 - switch(Idx) - { - case 0 : // setfrac - continue; - - case 1 : - mIndex = atol(i->c_str()); break; - - case 2 : - mName = *i; - CleanUpString(&mName); - break; - - case 3 : - mStartValue = atol(i->c_str()); break; - - case 4: - mAffected = atol(i->c_str())!=0; break; - - case 5: - mSL = atol(i->c_str()); break; - - default : - { - if(Idx-6 < NUMFACTIONS) - mRelations[Idx-6] = atol(i->c_str()); break; - } - } - } - - return true; -} - -int PDefFaction::GetRelation(int Faction) const -{ - // faction 0 has no relations - if(Faction <= 0 || Faction > NUMFACTIONS) - return 0; - - return mRelations[Faction-1]; -} - +#include +#include "GameServer/Definitions/Includes.hxx" + +PDefFaction::PDefFaction() +{ + memset(mRelations, 0, sizeof(mRelations)); // ... array members supposed to by auto-initialized by C++ +} + +bool PDefFaction::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + // setfracc 19 "Monster" -1024 0 0 -1024 -1024 -1024 -1 + switch(Idx) + { + case 0 : // setfrac + continue; + + case 1 : + mIndex = atol(i->c_str()); break; + + case 2 : + mName = *i; + CleanUpString(&mName); + break; + + case 3 : + mStartValue = atol(i->c_str()); break; + + case 4: + mAffected = atol(i->c_str())!=0; break; + + case 5: + mSL = atol(i->c_str()); break; + + default : + { + if(Idx-6 < NUMFACTIONS) + mRelations[Idx-6] = atol(i->c_str()); break; + } + } + } + + return true; +} + +int PDefFaction::GetRelation(int Faction) const +{ + // faction 0 has no relations + if(Faction <= 0 || Faction > NUMFACTIONS) + return 0; + + return mRelations[Faction-1]; +} + diff --git a/TinNS/Source/GameServer/Definitions/Factions.hxx b/TinNS/Source/GameServer/Definitions/Factions.hxx index 22f35a4..c3190dd 100644 --- a/TinNS/Source/GameServer/Definitions/Factions.hxx +++ b/TinNS/Source/GameServer/Definitions/Factions.hxx @@ -1,28 +1,28 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -static const int32_t NUMFACTIONS = 20; // for faction relations only - -class PDefFaction : public PDef { -private : - //int32_t mIndex; - std::string mName; - int32_t mStartValue; - bool mAffected; - int32_t mSL; - int32_t mRelations[NUMFACTIONS]; -public : - PDefFaction(); - //~PDefFaction(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline int32_t GetStartValue() const { return mStartValue; } - inline bool GetAffected() const { return mAffected; } - inline int32_t GetSL() const { return mSL; }; - int32_t GetRelation(int32_t Faction) const; -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +static const int32_t NUMFACTIONS = 20; // for faction relations only + +class PDefFaction : public PDef { +private : + //int32_t mIndex; + std::string mName; + int32_t mStartValue; + bool mAffected; + int32_t mSL; + int32_t mRelations[NUMFACTIONS]; +public : + PDefFaction(); + //~PDefFaction(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline int32_t GetStartValue() const { return mStartValue; } + inline bool GetAffected() const { return mAffected; } + inline int32_t GetSL() const { return mSL; }; + int32_t GetRelation(int32_t Faction) const; +}; diff --git a/TinNS/Source/GameServer/Definitions/GameDefinitions.cxx b/TinNS/Source/GameServer/Definitions/GameDefinitions.cxx index b056c3b..4c68725 100644 --- a/TinNS/Source/GameServer/Definitions/GameDefinitions.cxx +++ b/TinNS/Source/GameServer/Definitions/GameDefinitions.cxx @@ -1,65 +1,65 @@ -#include "GameServer/Definitions/Includes.hxx" - -/* - -------------------------------------------------------------------- - WARNING: - When adding new .def support, don't forget to add required stuff in PGameDefs::Init() - (compiler won't complain if you don't add that) - -------------------------------------------------------------------- - - NOTA: as PGameDefs uses the PDefParser class, which uses the PFileSystem and PFile classes, - files are searched in the same way as the NC client does: - - first try to load the file in unpacked form from the given directory, - - else tries to load the file in packed form from the given directory, - appending pak_ to its name, - - else tries to load the packed file from the .pak archive which name is - derived from the last part of the path. -*/ - -PGameDefs::PGameDefs() {} -PGameDefs::~PGameDefs() {} - -bool PGameDefs::Init() -{ - Console->Print( "Initializing game defs..." ); - bool Res = true; - - Res |= mActionModsDefs.Load ("Action mods", "defs/actionmod.def"); - Res |= mAmmosDefs.Load ("Ammos", "defs/ammo.def"); - Res |= mAppartementsDefs.Load ("Apartments", "defs/appartements.def"); - Res |= mAppPlacesDefs.Load ("App Places", "defs/appplaces.def"); - Res |= mBlueprintPiecesDefs.Load ("Blueprint pieces", "defs/blueprintpieces.def"); - Res |= mCharsDefs.Load ("Chars", "defs/characters.def"); - Res |= mCharActionsDefs.Load ("Char actions", "defs/charaction.def"); - Res |= mDamagesDefs.Load ("Damage", "defs/damage.def"); - Res |= mDrugsDefs.Load ("Drugs", "defs/drugs.def"); - Res |= mFactionsDefs.Load ("Factions", "defs/fractions.def"); - //Res |= mHacksDefs.Load ("Hack", "defs/hack.def"); - Res |= mImplantsDefs.Load ("Implants", "defs/implants.def"); - Res |= mItemContainersDefs.Load ("Item containers", "defs/itemcontainer.def"); - Res |= mItemModsDefs.Load ("Item mods", "defs/itemmod.def"); - Res |= mItemRestrictionsDefs.Load ("Item restrictions", "defs/itemres.def"); - Res |= mItemsDefs.Load ("Items", "defs/items.def"); - Res |= mMissionsDefs.Load ("Missions", "defs/missionbase.def"); - Res |= mNpcArmorsDefs.Load ("NPC Armors", "defs/npcarmor.def"); - Res |= mNpcGroupSpawnsDefs.Load ("NPC group spawns", "defs/npcgroupspawn.def"); - Res |= mNpcsDefs.Load ("NPC", "defs/npc.def"); - Res |= mOutpostsDefs.Load ("Outposts", "defs/outposts.def"); - Res |= mRecyclesDefs.Load ("Recycles", "defs/recycles.def"); - Res |= mRespawnsDefs.Load ("Respawns", "defs/respawn.def"); - Res |= mShotsDefs.Load ("Shots", "defs/shots.def"); - Res |= mSubSkillsDefs.Load ("Subskills", "defs/subskill.def"); // Loading before skills is required - Res |= mSkillsDefs.Load ("Skills", "defs/skills.def"); - Res |= mCharKindsDefs.Load ("Char kinds", "defs/charkinds.def"); // Loading after skills is required - Res |= mTradersDefs.Load ("Traders", "defs/trader.def"); - Res |= mVhcsDefs.Load ("Vehicles", "defs/vehicles.def"); - Res |= mVhcSeatsDefs.Load ("Vehicle seats", "defs/vehiclesits.def"); - Res |= mWeaponsDefs.Load ("Weapons", "defs/weapons.def"); - Res |= mWeathersDefs.Load ("Weathers", "defs/weather.def"); - Res |= mWorldsDefs.Load ("Worldinfo", "defs/worldinfo.def"); - Res |= mWorldFilesDefs.Load ("World files", "worlds/worlds.ini"); - Res |= mWorldModelsDefs.Load ("World models", "defs/worldmodel.def"); - Res |= mScriptDefs.Load ("Script defs", "defs/scripts.def"); - - return ( Res ); -} +#include "GameServer/Definitions/Includes.hxx" + +/* + -------------------------------------------------------------------- + WARNING: + When adding new .def support, don't forget to add required stuff in PGameDefs::Init() + (compiler won't complain if you don't add that) + -------------------------------------------------------------------- + + NOTA: as PGameDefs uses the PDefParser class, which uses the PFileSystem and PFile classes, + files are searched in the same way as the NC client does: + - first try to load the file in unpacked form from the given directory, + - else tries to load the file in packed form from the given directory, + appending pak_ to its name, + - else tries to load the packed file from the .pak archive which name is + derived from the last part of the path. +*/ + +PGameDefs::PGameDefs() {} +PGameDefs::~PGameDefs() {} + +bool PGameDefs::Init() +{ + Console->Print( "Initializing game defs..." ); + bool Res = true; + + Res |= mActionModsDefs.Load ("Action mods", "defs/actionmod.def"); + Res |= mAmmosDefs.Load ("Ammos", "defs/ammo.def"); + Res |= mAppartementsDefs.Load ("Apartments", "defs/appartements.def"); + Res |= mAppPlacesDefs.Load ("App Places", "defs/appplaces.def"); + Res |= mBlueprintPiecesDefs.Load ("Blueprint pieces", "defs/blueprintpieces.def"); + Res |= mCharsDefs.Load ("Chars", "defs/characters.def"); + Res |= mCharActionsDefs.Load ("Char actions", "defs/charaction.def"); + Res |= mDamagesDefs.Load ("Damage", "defs/damage.def"); + Res |= mDrugsDefs.Load ("Drugs", "defs/drugs.def"); + Res |= mFactionsDefs.Load ("Factions", "defs/fractions.def"); + //Res |= mHacksDefs.Load ("Hack", "defs/hack.def"); + Res |= mImplantsDefs.Load ("Implants", "defs/implants.def"); + Res |= mItemContainersDefs.Load ("Item containers", "defs/itemcontainer.def"); + Res |= mItemModsDefs.Load ("Item mods", "defs/itemmod.def"); + Res |= mItemRestrictionsDefs.Load ("Item restrictions", "defs/itemres.def"); + Res |= mItemsDefs.Load ("Items", "defs/items.def"); + Res |= mMissionsDefs.Load ("Missions", "defs/missionbase.def"); + Res |= mNpcArmorsDefs.Load ("NPC Armors", "defs/npcarmor.def"); + Res |= mNpcGroupSpawnsDefs.Load ("NPC group spawns", "defs/npcgroupspawn.def"); + Res |= mNpcsDefs.Load ("NPC", "defs/npc.def"); + Res |= mOutpostsDefs.Load ("Outposts", "defs/outposts.def"); + Res |= mRecyclesDefs.Load ("Recycles", "defs/recycles.def"); + Res |= mRespawnsDefs.Load ("Respawns", "defs/respawn.def"); + Res |= mShotsDefs.Load ("Shots", "defs/shots.def"); + Res |= mSubSkillsDefs.Load ("Subskills", "defs/subskill.def"); // Loading before skills is required + Res |= mSkillsDefs.Load ("Skills", "defs/skills.def"); + Res |= mCharKindsDefs.Load ("Char kinds", "defs/charkinds.def"); // Loading after skills is required + Res |= mTradersDefs.Load ("Traders", "defs/trader.def"); + Res |= mVhcsDefs.Load ("Vehicles", "defs/vehicles.def"); + Res |= mVhcSeatsDefs.Load ("Vehicle seats", "defs/vehiclesits.def"); + Res |= mWeaponsDefs.Load ("Weapons", "defs/weapons.def"); + Res |= mWeathersDefs.Load ("Weathers", "defs/weather.def"); + Res |= mWorldsDefs.Load ("Worldinfo", "defs/worldinfo.def"); + Res |= mWorldFilesDefs.Load ("World files", "worlds/worlds.ini"); + Res |= mWorldModelsDefs.Load ("World models", "defs/worldmodel.def"); + Res |= mScriptDefs.Load ("Script defs", "defs/scripts.def"); + + return ( Res ); +} diff --git a/TinNS/Source/GameServer/Definitions/GameDefinitions.hxx b/TinNS/Source/GameServer/Definitions/GameDefinitions.hxx index d1de8d8..cc004b3 100644 --- a/TinNS/Source/GameServer/Definitions/GameDefinitions.hxx +++ b/TinNS/Source/GameServer/Definitions/GameDefinitions.hxx @@ -1,154 +1,154 @@ -#pragma once - -#include -#include "GameServer/Definitions/Definition.hxx" -#include "GameServer/Definitions/Implants.hxx" -#include "GameServer/Definitions/ItemContainer.hxx" -#include "GameServer/Definitions/ItemMod.hxx" -#include "GameServer/Definitions/ItemRes.hxx" -#include "GameServer/Definitions/Items.hxx" -#include "GameServer/Definitions/Mission.hxx" -#include "GameServer/Definitions/NpcArmor.hxx" -#include "GameServer/Definitions/NpcGroupSpawn.hxx" -#include "GameServer/Definitions/Npc.hxx" -#include "GameServer/Definitions/Outposts.hxx" -#include "GameServer/Definitions/Recycles.hxx" -#include "GameServer/Definitions/Respawn.hxx" -#include "GameServer/Definitions/Scripts.hxx" -#include "GameServer/Definitions/Shots.hxx" -#include "GameServer/Definitions/Skills.hxx" -#include "GameServer/Definitions/SubSkills.hxx" -#include "GameServer/Definitions/Trader.hxx" -#include "GameServer/Definitions/Vehicles.hxx" -#include "GameServer/Definitions/VehicleSits.hxx" -#include "GameServer/Definitions/Weapons.hxx" -#include "GameServer/Definitions/Weather.hxx" -#include "GameServer/Definitions/WorldFile.hxx" -#include "GameServer/Definitions/WorldModels.hxx" -#include "GameServer/Definitions/Worlds.hxx" - -typedef PDefMap PDefActionModsMap; -typedef PDefMap PDefAmmosMap; -class PDefAppartementsMap; // Derived classe for addition of specific members -typedef PDefMap PDefAppPlacesMap; // No derived class needed here -typedef PDefMap PDefBlueprintPiecesMap; -typedef PDefMap PDefCharactersMap; -typedef PDefMap PDefCharActionsMap; -typedef PDefMap PDefCharKindsMap; -typedef PDefMap PDefDamagesMap; -typedef PDefMap PDefDrugsMap; -typedef PDefMap PDefFactionsMap; -//typedef PDefMap PDefHacksMap; // File not used by KK -typedef PDefMap PDefImplantsMap; -typedef PDefMap PDefItemContainersMap; -typedef PDefMap PDefItemModsMap; -typedef PDefMap PDefItemRestrictionsMap; -class PDefItemsMap; -typedef PDefMap PDefMissionsMap; -typedef PDefMap PDefNpcArmorsMap; -typedef PDefMap PDefNpcGroupSpawnsMap; -typedef PDefMap PDefNpcsMap; -typedef PDefMap PDefOutpostsMap; -typedef PDefMap PDefRecyclesMap; -class PDefRespawnsMap; -typedef PDefMap PDefShotsMap; -typedef PDefMap PDefSkillsMap; -typedef PDefMap PDefSubSkillsMap; -typedef PDefMap PDefTradersMap; -typedef PDefMap PDefVhcsMap; -typedef PDefMap PDefVhcSeatsMap; -typedef PDefMap PDefWeaponsMap; -typedef PDefMap PDefWeathersMap; -typedef PDefMap PDefWorldsMap; -class PDefWorldFilesMap; -typedef PDefMap PDefWorldModelsMap; - -class PDefScriptsMap; -//typedef PDefMap PDefScriptsMap; -// ___Add new entries here in alpĥabetical order___ - - -class PGameDefs { -private: - PDefActionModsMap mActionModsDefs; - PDefAmmosMap mAmmosDefs; - PDefAppartementsMap mAppartementsDefs; - PDefAppPlacesMap mAppPlacesDefs; - PDefBlueprintPiecesMap mBlueprintPiecesDefs; - PDefCharactersMap mCharsDefs; - PDefCharActionsMap mCharActionsDefs; - PDefCharKindsMap mCharKindsDefs; - PDefDamagesMap mDamagesDefs; - PDefDrugsMap mDrugsDefs; - PDefFactionsMap mFactionsDefs; - //PDefHacksMap mHacksDefs; - PDefImplantsMap mImplantsDefs; - PDefItemContainersMap mItemContainersDefs; - PDefItemModsMap mItemModsDefs; - PDefItemRestrictionsMap mItemRestrictionsDefs; - PDefItemsMap mItemsDefs; - PDefMissionsMap mMissionsDefs; - PDefNpcArmorsMap mNpcArmorsDefs; - PDefNpcGroupSpawnsMap mNpcGroupSpawnsDefs; - PDefNpcsMap mNpcsDefs; - PDefOutpostsMap mOutpostsDefs; - PDefRecyclesMap mRecyclesDefs; - PDefRespawnsMap mRespawnsDefs; - PDefShotsMap mShotsDefs; - PDefSkillsMap mSkillsDefs; - PDefSubSkillsMap mSubSkillsDefs; - PDefTradersMap mTradersDefs; - PDefVhcsMap mVhcsDefs; - PDefVhcSeatsMap mVhcSeatsDefs; - PDefWeaponsMap mWeaponsDefs; - PDefWeathersMap mWeathersDefs; - PDefWorldsMap mWorldsDefs; - PDefWorldFilesMap mWorldFilesDefs; - PDefWorldModelsMap mWorldModelsDefs; - PDefScriptsMap mScriptDefs; - // ___Add new entries here___ - -public: - PGameDefs(); - ~PGameDefs(); - - bool Init(); - - inline const PDefActionModsMap* ActionMods() const { return &mActionModsDefs; } - inline const PDefAmmosMap* Ammos() const { return &mAmmosDefs; } - inline const PDefAppartementsMap* Appartements() const { return &mAppartementsDefs; } - inline const PDefAppPlacesMap* AppPlaces() const { return &mAppPlacesDefs; } - inline const PDefBlueprintPiecesMap* BlueprintPieces() const { return &mBlueprintPiecesDefs; } - inline const PDefCharactersMap* Chars() const { return &mCharsDefs; } - inline const PDefCharActionsMap* CharActions() const { return &mCharActionsDefs; } - inline const PDefCharKindsMap* CharKinds() const { return &mCharKindsDefs; } - inline const PDefDamagesMap* Damages() const { return &mDamagesDefs; } - inline const PDefDrugsMap* Drugs() const { return &mDrugsDefs; } - inline const PDefFactionsMap* Factions() const { return &mFactionsDefs; } - //inline const PDefHacksMap* Hacks() const { return &mHacksDefs; } - inline const PDefImplantsMap* Implants() const { return &mImplantsDefs;} - inline const PDefItemContainersMap* ItemContainers() const { return &mItemContainersDefs; } - inline const PDefItemModsMap* ItemMods() const { return &mItemModsDefs; } - inline const PDefItemRestrictionsMap* ItemRestrictions() const { return & mItemRestrictionsDefs; } - inline const PDefItemsMap* Items() const { return &mItemsDefs; } - inline const PDefMissionsMap* Missions() const { return &mMissionsDefs; } - inline const PDefNpcArmorsMap* NpcArmors() const { return & mNpcArmorsDefs; } - inline const PDefNpcGroupSpawnsMap* GroupSpawns() const { return &mNpcGroupSpawnsDefs; } - inline const PDefNpcsMap* Npcs() const { return &mNpcsDefs; } - inline const PDefOutpostsMap* Outposts() const { return &mOutpostsDefs; } - inline const PDefRecyclesMap* Recycles() const { return &mRecyclesDefs; } - inline const PDefRespawnsMap* Respawns() const { return &mRespawnsDefs; } - inline const PDefShotsMap* Shots() const { return &mShotsDefs; } - inline const PDefSkillsMap* Skills() const { return &mSkillsDefs; } - inline const PDefSubSkillsMap* SubSkills() const { return &mSubSkillsDefs; } - inline const PDefTradersMap* Traders() const { return &mTradersDefs; } - inline const PDefVhcsMap* Vhcs() const { return &mVhcsDefs; } - inline const PDefVhcSeatsMap* VhcSeats() const { return &mVhcSeatsDefs; } - inline const PDefWeaponsMap* Weapons() const { return &mWeaponsDefs; } - inline const PDefWeathersMap* Weathers() const { return &mWeathersDefs; } - inline const PDefWorldsMap* Worlds() const { return &mWorldsDefs; } - inline const PDefWorldFilesMap* WorldFiles() const { return &mWorldFilesDefs; } - inline const PDefWorldModelsMap* WorldModels() const { return &mWorldModelsDefs; } - inline const PDefScriptsMap* Scripts() const { return &mScriptDefs; } - // ___Add new entries here___ -}; +#pragma once + +#include +#include "GameServer/Definitions/Definition.hxx" +#include "GameServer/Definitions/Implants.hxx" +#include "GameServer/Definitions/ItemContainer.hxx" +#include "GameServer/Definitions/ItemMod.hxx" +#include "GameServer/Definitions/ItemRes.hxx" +#include "GameServer/Definitions/Items.hxx" +#include "GameServer/Definitions/Mission.hxx" +#include "GameServer/Definitions/NpcArmor.hxx" +#include "GameServer/Definitions/NpcGroupSpawn.hxx" +#include "GameServer/Definitions/Npc.hxx" +#include "GameServer/Definitions/Outposts.hxx" +#include "GameServer/Definitions/Recycles.hxx" +#include "GameServer/Definitions/Respawn.hxx" +#include "GameServer/Definitions/Scripts.hxx" +#include "GameServer/Definitions/Shots.hxx" +#include "GameServer/Definitions/Skills.hxx" +#include "GameServer/Definitions/SubSkills.hxx" +#include "GameServer/Definitions/Trader.hxx" +#include "GameServer/Definitions/Vehicles.hxx" +#include "GameServer/Definitions/VehicleSits.hxx" +#include "GameServer/Definitions/Weapons.hxx" +#include "GameServer/Definitions/Weather.hxx" +#include "GameServer/Definitions/WorldFile.hxx" +#include "GameServer/Definitions/WorldModels.hxx" +#include "GameServer/Definitions/Worlds.hxx" + +typedef PDefMap PDefActionModsMap; +typedef PDefMap PDefAmmosMap; +class PDefAppartementsMap; // Derived classe for addition of specific members +typedef PDefMap PDefAppPlacesMap; // No derived class needed here +typedef PDefMap PDefBlueprintPiecesMap; +typedef PDefMap PDefCharactersMap; +typedef PDefMap PDefCharActionsMap; +typedef PDefMap PDefCharKindsMap; +typedef PDefMap PDefDamagesMap; +typedef PDefMap PDefDrugsMap; +typedef PDefMap PDefFactionsMap; +//typedef PDefMap PDefHacksMap; // File not used by KK +typedef PDefMap PDefImplantsMap; +typedef PDefMap PDefItemContainersMap; +typedef PDefMap PDefItemModsMap; +typedef PDefMap PDefItemRestrictionsMap; +class PDefItemsMap; +typedef PDefMap PDefMissionsMap; +typedef PDefMap PDefNpcArmorsMap; +typedef PDefMap PDefNpcGroupSpawnsMap; +typedef PDefMap PDefNpcsMap; +typedef PDefMap PDefOutpostsMap; +typedef PDefMap PDefRecyclesMap; +class PDefRespawnsMap; +typedef PDefMap PDefShotsMap; +typedef PDefMap PDefSkillsMap; +typedef PDefMap PDefSubSkillsMap; +typedef PDefMap PDefTradersMap; +typedef PDefMap PDefVhcsMap; +typedef PDefMap PDefVhcSeatsMap; +typedef PDefMap PDefWeaponsMap; +typedef PDefMap PDefWeathersMap; +typedef PDefMap PDefWorldsMap; +class PDefWorldFilesMap; +typedef PDefMap PDefWorldModelsMap; + +class PDefScriptsMap; +//typedef PDefMap PDefScriptsMap; +// ___Add new entries here in alpĥabetical order___ + + +class PGameDefs { +private: + PDefActionModsMap mActionModsDefs; + PDefAmmosMap mAmmosDefs; + PDefAppartementsMap mAppartementsDefs; + PDefAppPlacesMap mAppPlacesDefs; + PDefBlueprintPiecesMap mBlueprintPiecesDefs; + PDefCharactersMap mCharsDefs; + PDefCharActionsMap mCharActionsDefs; + PDefCharKindsMap mCharKindsDefs; + PDefDamagesMap mDamagesDefs; + PDefDrugsMap mDrugsDefs; + PDefFactionsMap mFactionsDefs; + //PDefHacksMap mHacksDefs; + PDefImplantsMap mImplantsDefs; + PDefItemContainersMap mItemContainersDefs; + PDefItemModsMap mItemModsDefs; + PDefItemRestrictionsMap mItemRestrictionsDefs; + PDefItemsMap mItemsDefs; + PDefMissionsMap mMissionsDefs; + PDefNpcArmorsMap mNpcArmorsDefs; + PDefNpcGroupSpawnsMap mNpcGroupSpawnsDefs; + PDefNpcsMap mNpcsDefs; + PDefOutpostsMap mOutpostsDefs; + PDefRecyclesMap mRecyclesDefs; + PDefRespawnsMap mRespawnsDefs; + PDefShotsMap mShotsDefs; + PDefSkillsMap mSkillsDefs; + PDefSubSkillsMap mSubSkillsDefs; + PDefTradersMap mTradersDefs; + PDefVhcsMap mVhcsDefs; + PDefVhcSeatsMap mVhcSeatsDefs; + PDefWeaponsMap mWeaponsDefs; + PDefWeathersMap mWeathersDefs; + PDefWorldsMap mWorldsDefs; + PDefWorldFilesMap mWorldFilesDefs; + PDefWorldModelsMap mWorldModelsDefs; + PDefScriptsMap mScriptDefs; + // ___Add new entries here___ + +public: + PGameDefs(); + ~PGameDefs(); + + bool Init(); + + inline const PDefActionModsMap* ActionMods() const { return &mActionModsDefs; } + inline const PDefAmmosMap* Ammos() const { return &mAmmosDefs; } + inline const PDefAppartementsMap* Appartements() const { return &mAppartementsDefs; } + inline const PDefAppPlacesMap* AppPlaces() const { return &mAppPlacesDefs; } + inline const PDefBlueprintPiecesMap* BlueprintPieces() const { return &mBlueprintPiecesDefs; } + inline const PDefCharactersMap* Chars() const { return &mCharsDefs; } + inline const PDefCharActionsMap* CharActions() const { return &mCharActionsDefs; } + inline const PDefCharKindsMap* CharKinds() const { return &mCharKindsDefs; } + inline const PDefDamagesMap* Damages() const { return &mDamagesDefs; } + inline const PDefDrugsMap* Drugs() const { return &mDrugsDefs; } + inline const PDefFactionsMap* Factions() const { return &mFactionsDefs; } + //inline const PDefHacksMap* Hacks() const { return &mHacksDefs; } + inline const PDefImplantsMap* Implants() const { return &mImplantsDefs;} + inline const PDefItemContainersMap* ItemContainers() const { return &mItemContainersDefs; } + inline const PDefItemModsMap* ItemMods() const { return &mItemModsDefs; } + inline const PDefItemRestrictionsMap* ItemRestrictions() const { return & mItemRestrictionsDefs; } + inline const PDefItemsMap* Items() const { return &mItemsDefs; } + inline const PDefMissionsMap* Missions() const { return &mMissionsDefs; } + inline const PDefNpcArmorsMap* NpcArmors() const { return & mNpcArmorsDefs; } + inline const PDefNpcGroupSpawnsMap* GroupSpawns() const { return &mNpcGroupSpawnsDefs; } + inline const PDefNpcsMap* Npcs() const { return &mNpcsDefs; } + inline const PDefOutpostsMap* Outposts() const { return &mOutpostsDefs; } + inline const PDefRecyclesMap* Recycles() const { return &mRecyclesDefs; } + inline const PDefRespawnsMap* Respawns() const { return &mRespawnsDefs; } + inline const PDefShotsMap* Shots() const { return &mShotsDefs; } + inline const PDefSkillsMap* Skills() const { return &mSkillsDefs; } + inline const PDefSubSkillsMap* SubSkills() const { return &mSubSkillsDefs; } + inline const PDefTradersMap* Traders() const { return &mTradersDefs; } + inline const PDefVhcsMap* Vhcs() const { return &mVhcsDefs; } + inline const PDefVhcSeatsMap* VhcSeats() const { return &mVhcSeatsDefs; } + inline const PDefWeaponsMap* Weapons() const { return &mWeaponsDefs; } + inline const PDefWeathersMap* Weathers() const { return &mWeathersDefs; } + inline const PDefWorldsMap* Worlds() const { return &mWorldsDefs; } + inline const PDefWorldFilesMap* WorldFiles() const { return &mWorldFilesDefs; } + inline const PDefWorldModelsMap* WorldModels() const { return &mWorldModelsDefs; } + inline const PDefScriptsMap* Scripts() const { return &mScriptDefs; } + // ___Add new entries here___ +}; diff --git a/TinNS/Source/GameServer/Definitions/Hack.cxx b/TinNS/Source/GameServer/Definitions/Hack.cxx index 202b60e..0c059db 100644 --- a/TinNS/Source/GameServer/Definitions/Hack.cxx +++ b/TinNS/Source/GameServer/Definitions/Hack.cxx @@ -1,27 +1,27 @@ -#include "GameServer/Definitions/Includes.hxx" - -PDefHack::PDefHack() -{ -} - -bool PDefHack::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0: // setentry - continue ; - - - case 1: // index - mIndex = atoi(i->c_str()); break; - - - } - } - - return true; -} - +#include "GameServer/Definitions/Includes.hxx" + +PDefHack::PDefHack() +{ +} + +bool PDefHack::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0: // setentry + continue ; + + + case 1: // index + mIndex = atoi(i->c_str()); break; + + + } + } + + return true; +} + diff --git a/TinNS/Source/GameServer/Definitions/Hack.hxx b/TinNS/Source/GameServer/Definitions/Hack.hxx index 1a6b90a..8045e15 100644 --- a/TinNS/Source/GameServer/Definitions/Hack.hxx +++ b/TinNS/Source/GameServer/Definitions/Hack.hxx @@ -1,16 +1,16 @@ -#pragma once - -#include "GameServer/Definitions/Definition.hxx" - -class PDefHack : public PDef { -private: - //int mIndex; - //qui aggiungere valori -public: - PDefHack(); - //~PDefHack(); - - bool LoadFromDef(PTokenList *Tokens); - - //qui aggiungere funzioni per i gets -}; +#pragma once + +#include "GameServer/Definitions/Definition.hxx" + +class PDefHack : public PDef { +private: + //int mIndex; + //qui aggiungere valori +public: + PDefHack(); + //~PDefHack(); + + bool LoadFromDef(PTokenList *Tokens); + + //qui aggiungere funzioni per i gets +}; diff --git a/TinNS/Source/GameServer/Definitions/Items.cxx b/TinNS/Source/GameServer/Definitions/Items.cxx index ab1ab49..2b8e54e 100644 --- a/TinNS/Source/GameServer/Definitions/Items.cxx +++ b/TinNS/Source/GameServer/Definitions/Items.cxx @@ -1,215 +1,215 @@ -#include "GameServer/Definitions/Includes.hxx" - -#define GAMEDEFS_DEFITEMSMAXSEQ 100 - -PDefItems::PDefItems() -{ - //mIndex = 0; - mModel = 0; - mType = 0; - mValue1 = 0; - mValue2 = 0; - mValue3 = 0; - //mBmNum = 0; - //mmBmNumIndex = 0; - mSizeX = 1; - mSizeY = 1; - //mSmallbmnum = 0; - mWeight = 0; - mStackable = 0; - mFillWeight = 0; - mQualifier = 0; - mGfxMods = 0; - mItemGroupID = 0; - mTextDescID = 0; - mBasePrice = 0; - mTechlevel = 0; - mItemflags = 0; - // std::mShortname = ""; -} - -bool PDefItems::LoadFromDef( PTokenList *Tokens ) -{ - int Idx = 0; - for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ ) - { - switch ( Idx ) - { - case 0: // setentry - continue; - case 1: // index - mIndex = atoi( i->c_str() ); break; - case 2: // name - mName = *i; break; - case 3: - mModel = atoi(i->c_str()); // used for IG display - break; - case 4: - mType = atoi( i->c_str() ); break; - case 5: - mValue1 = atoi( i->c_str() ); break; - case 6: - mValue2 = atoi( i->c_str() ); break; - case 7: - mValue3 = atoi( i->c_str() ); break; - case 8: - // mBmNum = atoi(i->c_str()); // used IG for inventory display - break; - case 9: - // mmBmNumIndex = atoi(i->c_str()); // used IG for inventory display - break; - case 10: - mSizeX = atoi( i->c_str() ); break; - case 11: - mSizeY = atoi( i->c_str() ); break; - case 12: - // mSmallbmnum = atoi(i->c_str()); // used IG for inventory display - break; - case 13: - mWeight = atof( i->c_str() ); break; - case 14: - mStackable = atoi( i->c_str() ); break; - case 15: - mFillWeight = atof( i->c_str() ); break; - case 16: - mQualifier = atoi( i->c_str() ); break; - case 17: - mGfxMods = atoi( i->c_str() ); break; - case 18: - mItemGroupID = atoi( i->c_str() ); break; - case 19: - mTextDescID = atoi( i->c_str() ); break; - case 20: - mBasePrice = atoi( i->c_str() ); break; - case 21: - mTechlevel = atoi( i->c_str() ); break; - case 22: - mItemflags = atoi( i->c_str() ); break; - case 23: - // mShortname = *i; // used IG for display on inventories Icons - break; - } - } - - return true; -} - - -PDefItemsMap::PDefItemsMap() -{ - mMapItCache = NULL; - mMapItCacheCount = 0; - mMaxItemGroupId = -1; -} - -PDefItemsMap::~PDefItemsMap() -{ - delete [] mMapItCache; -} - -void PDefItemsMap::BuildMapItCache() -{ - int CacheEntryIdx = 0; - int EntrySeqIdx = 1; - - mMapItCacheCount = 1 + ( mDefs.size() / GAMEDEFS_DEFITEMSMAXSEQ ); - - if ( mMapItCacheCount ) - { - if( mMapItCache ) - { - delete [] mMapItCache; - } - mMapItCache = new std::map::const_iterator[mMapItCacheCount]; - mMapItCache[CacheEntryIdx++] = mDefs.begin(); - - std::map::const_iterator It = mDefs.begin(); - while ( It != mDefs.end() ) - { - if ( EntrySeqIdx++ == GAMEDEFS_DEFITEMSMAXSEQ ) - { - mMapItCache[CacheEntryIdx++] = It; - EntrySeqIdx = 1; - } - It++; - } - } -} - -void PDefItemsMap::BuildItemGroups() -{ - //std::map > mItemGroups; - // Implementation more complicated than needed but avoid too many realloc - - // Group size conting - std::map groupSize; - for ( std::map::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ ) - groupSize[ i->second->GetItemGroupID() ]++; - - // Item group vectors size reservation - mItemGroups.clear(); - for ( std::map::const_iterator i = groupSize.begin(); i != groupSize.end(); i++ ) - { - mItemGroups[i->first].reserve(i->second); - if(i->first > mMaxItemGroupId) - mMaxItemGroupId = i->first; - //Console->Print("Item group %d : %d items", i->first, i->second); - } - - // Effective groups building - for ( std::map::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ ) - mItemGroups[ i->second->GetItemGroupID() ].push_back(i->first); // i->first is ItemIndex -} - -bool PDefItemsMap::Load(const char* nName, const char* nFilename) -{ - if( PDefMap::Load( nName, nFilename) ) - { - BuildMapItCache(); - BuildItemGroups(); - return ( true ); - } - else - return ( false ); -} - -const PDefItems* PDefItemsMap::GetDefBySeqIndex( int nSeqIndex ) const -{ - int CacheEntryIdx = nSeqIndex / GAMEDEFS_DEFITEMSMAXSEQ; - if ( CacheEntryIdx >= mMapItCacheCount ) - return NULL; - - std::map::const_iterator It = mMapItCache[CacheEntryIdx]; - int EntrySeqIdx = CacheEntryIdx * GAMEDEFS_DEFITEMSMAXSEQ; - - while (( EntrySeqIdx < nSeqIndex ) && ( It != mDefs.end() ) ) - { - EntrySeqIdx++; - It++; - } - - if (( EntrySeqIdx == nSeqIndex ) && ( It != mDefs.end() ) ) - { - return It->second; - } - else - return NULL; -} - -int PDefItemsMap::GetRandomItemIdFromGroup( int nGroupId ) const -{ - if( (nGroupId >= 0) && (nGroupId <= mMaxItemGroupId) ) - { - std::map >::const_iterator selectedEntry = mItemGroups.find(nGroupId); - if(selectedEntry != mItemGroups.end()) - { - int groupSize = selectedEntry->second.size(); - if( groupSize ) - { - return selectedEntry->second[GetRandom(groupSize - 1, 0)]; - } - } - } - - return 0; -} +#include "GameServer/Definitions/Includes.hxx" + +#define GAMEDEFS_DEFITEMSMAXSEQ 100 + +PDefItems::PDefItems() +{ + //mIndex = 0; + mModel = 0; + mType = 0; + mValue1 = 0; + mValue2 = 0; + mValue3 = 0; + //mBmNum = 0; + //mmBmNumIndex = 0; + mSizeX = 1; + mSizeY = 1; + //mSmallbmnum = 0; + mWeight = 0; + mStackable = 0; + mFillWeight = 0; + mQualifier = 0; + mGfxMods = 0; + mItemGroupID = 0; + mTextDescID = 0; + mBasePrice = 0; + mTechlevel = 0; + mItemflags = 0; + // std::mShortname = ""; +} + +bool PDefItems::LoadFromDef( PTokenList *Tokens ) +{ + int Idx = 0; + for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ ) + { + switch ( Idx ) + { + case 0: // setentry + continue; + case 1: // index + mIndex = atoi( i->c_str() ); break; + case 2: // name + mName = *i; break; + case 3: + mModel = atoi(i->c_str()); // used for IG display + break; + case 4: + mType = atoi( i->c_str() ); break; + case 5: + mValue1 = atoi( i->c_str() ); break; + case 6: + mValue2 = atoi( i->c_str() ); break; + case 7: + mValue3 = atoi( i->c_str() ); break; + case 8: + // mBmNum = atoi(i->c_str()); // used IG for inventory display + break; + case 9: + // mmBmNumIndex = atoi(i->c_str()); // used IG for inventory display + break; + case 10: + mSizeX = atoi( i->c_str() ); break; + case 11: + mSizeY = atoi( i->c_str() ); break; + case 12: + // mSmallbmnum = atoi(i->c_str()); // used IG for inventory display + break; + case 13: + mWeight = atof( i->c_str() ); break; + case 14: + mStackable = atoi( i->c_str() ); break; + case 15: + mFillWeight = atof( i->c_str() ); break; + case 16: + mQualifier = atoi( i->c_str() ); break; + case 17: + mGfxMods = atoi( i->c_str() ); break; + case 18: + mItemGroupID = atoi( i->c_str() ); break; + case 19: + mTextDescID = atoi( i->c_str() ); break; + case 20: + mBasePrice = atoi( i->c_str() ); break; + case 21: + mTechlevel = atoi( i->c_str() ); break; + case 22: + mItemflags = atoi( i->c_str() ); break; + case 23: + // mShortname = *i; // used IG for display on inventories Icons + break; + } + } + + return true; +} + + +PDefItemsMap::PDefItemsMap() +{ + mMapItCache = NULL; + mMapItCacheCount = 0; + mMaxItemGroupId = -1; +} + +PDefItemsMap::~PDefItemsMap() +{ + delete [] mMapItCache; +} + +void PDefItemsMap::BuildMapItCache() +{ + int CacheEntryIdx = 0; + int EntrySeqIdx = 1; + + mMapItCacheCount = 1 + ( mDefs.size() / GAMEDEFS_DEFITEMSMAXSEQ ); + + if ( mMapItCacheCount ) + { + if( mMapItCache ) + { + delete [] mMapItCache; + } + mMapItCache = new std::map::const_iterator[mMapItCacheCount]; + mMapItCache[CacheEntryIdx++] = mDefs.begin(); + + std::map::const_iterator It = mDefs.begin(); + while ( It != mDefs.end() ) + { + if ( EntrySeqIdx++ == GAMEDEFS_DEFITEMSMAXSEQ ) + { + mMapItCache[CacheEntryIdx++] = It; + EntrySeqIdx = 1; + } + It++; + } + } +} + +void PDefItemsMap::BuildItemGroups() +{ + //std::map > mItemGroups; + // Implementation more complicated than needed but avoid too many realloc + + // Group size conting + std::map groupSize; + for ( std::map::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ ) + groupSize[ i->second->GetItemGroupID() ]++; + + // Item group vectors size reservation + mItemGroups.clear(); + for ( std::map::const_iterator i = groupSize.begin(); i != groupSize.end(); i++ ) + { + mItemGroups[i->first].reserve(i->second); + if(i->first > mMaxItemGroupId) + mMaxItemGroupId = i->first; + //Console->Print("Item group %d : %d items", i->first, i->second); + } + + // Effective groups building + for ( std::map::const_iterator i = mDefs.begin(); i != mDefs.end(); i++ ) + mItemGroups[ i->second->GetItemGroupID() ].push_back(i->first); // i->first is ItemIndex +} + +bool PDefItemsMap::Load(const char* nName, const char* nFilename) +{ + if( PDefMap::Load( nName, nFilename) ) + { + BuildMapItCache(); + BuildItemGroups(); + return ( true ); + } + else + return ( false ); +} + +const PDefItems* PDefItemsMap::GetDefBySeqIndex( int nSeqIndex ) const +{ + int CacheEntryIdx = nSeqIndex / GAMEDEFS_DEFITEMSMAXSEQ; + if ( CacheEntryIdx >= mMapItCacheCount ) + return NULL; + + std::map::const_iterator It = mMapItCache[CacheEntryIdx]; + int EntrySeqIdx = CacheEntryIdx * GAMEDEFS_DEFITEMSMAXSEQ; + + while (( EntrySeqIdx < nSeqIndex ) && ( It != mDefs.end() ) ) + { + EntrySeqIdx++; + It++; + } + + if (( EntrySeqIdx == nSeqIndex ) && ( It != mDefs.end() ) ) + { + return It->second; + } + else + return NULL; +} + +int PDefItemsMap::GetRandomItemIdFromGroup( int nGroupId ) const +{ + if( (nGroupId >= 0) && (nGroupId <= mMaxItemGroupId) ) + { + std::map >::const_iterator selectedEntry = mItemGroups.find(nGroupId); + if(selectedEntry != mItemGroups.end()) + { + int groupSize = selectedEntry->second.size(); + if( groupSize ) + { + return selectedEntry->second[GetRandom(groupSize - 1, 0)]; + } + } + } + + return 0; +} diff --git a/TinNS/Source/GameServer/Definitions/Items.hxx b/TinNS/Source/GameServer/Definitions/Items.hxx index 0bf6903..bfe4576 100644 --- a/TinNS/Source/GameServer/Definitions/Items.hxx +++ b/TinNS/Source/GameServer/Definitions/Items.hxx @@ -1,77 +1,77 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefItems : public PDef { -private: - //int32_t mIndex;//1 - std::string mName;//2 - int32_t mModel; // used for IG display - int32_t mType; - int32_t mValue1; - int32_t mValue2; - int32_t mValue3; - // int32_t mBmNum; // used IG for inventory display - // int32_t mmBmNumIndex; // used IG for inventory display - int32_t mSizeX; - int32_t mSizeY; - // int32_t mSmallbmnum; // used IG for inventory display - float mWeight; - int32_t mStackable; - float mFillWeight; - int32_t mQualifier; - int32_t mGfxMods; - int32_t mItemGroupID; - int32_t mTextDescID; - int32_t mBasePrice; - int32_t mTechlevel; - int32_t mItemflags; - // std::mShortname; // used IG for display on inventories Icons - -public: - PDefItems(); - //~PDefItems(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline int32_t GetModel() const { return mModel; } - inline int32_t GetType() const { return mType; } - inline int32_t GetValue1() const { return mValue1; } - inline int32_t GetValue2() const { return mValue2; } - inline int32_t GetValue3() const { return mValue3; } - inline int32_t GetSizeX() const { return mSizeX; } - inline int32_t GetSizeY() const { return mSizeY; } - inline float GetWeight() const { return mWeight; } - inline bool IsStackable() const { return (mStackable == 1); } - inline float GetFillWeight() const { return mFillWeight; } - inline int32_t GetQualifier() const { return mQualifier; } - inline int32_t GetGfxMods() const { return mGfxMods; } - inline int32_t GetItemGroupID() const { return mItemGroupID; } - inline int32_t GetTextDescID() const { return mTextDescID; } - inline int32_t GetBasePrice() const { return mBasePrice; } - inline int32_t GetTechlevel() const { return mTechlevel; } - inline int32_t GetItemflags() const { return mItemflags; } -}; - -class PDefItemsMap : public PDefMap { -private: - std::map::const_iterator* mMapItCache; - int32_t mMapItCacheCount; - std::map > mItemGroups; - int32_t mMaxItemGroupId; - void BuildMapItCache(); - void BuildItemGroups(); - -public: - PDefItemsMap(); - ~PDefItemsMap(); - bool Load(const char* nName, const char* nFilename); - const PDefItems* GetDefBySeqIndex( int32_t nSeqIndex ) const; - int32_t GetRandomItemIdFromGroup( int32_t nGroupId ) const; - - inline std::map::const_iterator ConstIteratorBegin() const { return mDefs.begin(); } - inline std::map::const_iterator ConstIteratorEnd() const { return mDefs.end(); } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefItems : public PDef { +private: + //int32_t mIndex;//1 + std::string mName;//2 + int32_t mModel; // used for IG display + int32_t mType; + int32_t mValue1; + int32_t mValue2; + int32_t mValue3; + // int32_t mBmNum; // used IG for inventory display + // int32_t mmBmNumIndex; // used IG for inventory display + int32_t mSizeX; + int32_t mSizeY; + // int32_t mSmallbmnum; // used IG for inventory display + float mWeight; + int32_t mStackable; + float mFillWeight; + int32_t mQualifier; + int32_t mGfxMods; + int32_t mItemGroupID; + int32_t mTextDescID; + int32_t mBasePrice; + int32_t mTechlevel; + int32_t mItemflags; + // std::mShortname; // used IG for display on inventories Icons + +public: + PDefItems(); + //~PDefItems(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline int32_t GetModel() const { return mModel; } + inline int32_t GetType() const { return mType; } + inline int32_t GetValue1() const { return mValue1; } + inline int32_t GetValue2() const { return mValue2; } + inline int32_t GetValue3() const { return mValue3; } + inline int32_t GetSizeX() const { return mSizeX; } + inline int32_t GetSizeY() const { return mSizeY; } + inline float GetWeight() const { return mWeight; } + inline bool IsStackable() const { return (mStackable == 1); } + inline float GetFillWeight() const { return mFillWeight; } + inline int32_t GetQualifier() const { return mQualifier; } + inline int32_t GetGfxMods() const { return mGfxMods; } + inline int32_t GetItemGroupID() const { return mItemGroupID; } + inline int32_t GetTextDescID() const { return mTextDescID; } + inline int32_t GetBasePrice() const { return mBasePrice; } + inline int32_t GetTechlevel() const { return mTechlevel; } + inline int32_t GetItemflags() const { return mItemflags; } +}; + +class PDefItemsMap : public PDefMap { +private: + std::map::const_iterator* mMapItCache; + int32_t mMapItCacheCount; + std::map > mItemGroups; + int32_t mMaxItemGroupId; + void BuildMapItCache(); + void BuildItemGroups(); + +public: + PDefItemsMap(); + ~PDefItemsMap(); + bool Load(const char* nName, const char* nFilename); + const PDefItems* GetDefBySeqIndex( int32_t nSeqIndex ) const; + int32_t GetRandomItemIdFromGroup( int32_t nGroupId ) const; + + inline std::map::const_iterator ConstIteratorBegin() const { return mDefs.begin(); } + inline std::map::const_iterator ConstIteratorEnd() const { return mDefs.end(); } +}; diff --git a/TinNS/Source/GameServer/Definitions/Parser.cxx b/TinNS/Source/GameServer/Definitions/Parser.cxx index a91e76a..5d1206f 100644 --- a/TinNS/Source/GameServer/Definitions/Parser.cxx +++ b/TinNS/Source/GameServer/Definitions/Parser.cxx @@ -1,121 +1,121 @@ -#include "GameServer/Definitions/Includes.hxx" -#include "GameServer/Includes.hxx" - -PDefParser::PDefParser() -{ -} - -PDefParser::~PDefParser() -{ - for(PDefTokenList::iterator i=mTokens.begin(); i!=mTokens.end(); i++) - delete *i; -} - -bool PDefParser::Parse(const char *File) -{ - PFile *f = Filesystem->Open("", File, Config->GetOption("nc_data_path")); - enum { NOPE, MAYBE, LINE, BLOCK, MAYBE_END } Comment = NOPE; - - if(f) - { - while(!f->Eof()) - { - std::string Str = f->ReadString(); - int Len = Str.length(); - if(Len <= 0) - continue; - - if(Str.substr(0, 3)!="set") - continue; - - //Console->Print("%s", Str.c_str());//NEW was commented , just to be sure of what we are reading - - PTokenList *List = new PTokenList(); - int Start=0, Tokens=0; - bool Quote=false; - for(int i=0; i= Start) - { - List->push_back(std::string(Str.substr(Start, (End-Start)+1))); - Tokens++; - break; - } - Quote=false; - } - if(Comment != BLOCK) - Comment=NOPE; - break; - } - - if(!Quote) - { - if(Comment < LINE && (Str[i]=='\t' || Str[i]==',' || Str[i]==' ' || Str[i]==';' || Str[i]=='|' || i==Len-1)) - { - int End=i-1; - if(End >= Start) - { - List->push_back(std::string(Str.substr(Start, (End-Start)+1))); - Tokens++; - } - Start=i+1; - } - - if(Str[i] <= ' ') - continue; - - if(Str[i]=='*') - { - if(Comment==MAYBE) - Comment=BLOCK; - else - if(Comment==BLOCK) - Comment=MAYBE_END; - } else - if(Str[i]=='/') - { - if(Comment==MAYBE) - { - // second slash, skip rest of line - Comment=LINE; - break; - } else - if(Comment==MAYBE_END) - { - Comment=NOPE; // comment block ends - Start=i+1; - } else - if(Comment != BLOCK) - Comment=MAYBE; // first slash - } else - { - if(Comment==MAYBE) - Comment=NOPE; // stand-alone slash - else - if(Comment==MAYBE_END) - Comment=BLOCK; // comment block did not end - } - } - - if(Str[i]=='"') - Quote ^= true; - } - - if(Tokens > 0) - mTokens.push_back(List); - else - delete List; - } - } else - { - Console->Print("%s PDefParser::Parse: could not open file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), File); - return false; - } - - return true; -} +#include "GameServer/Definitions/Includes.hxx" +#include "GameServer/Includes.hxx" + +PDefParser::PDefParser() +{ +} + +PDefParser::~PDefParser() +{ + for(PDefTokenList::iterator i=mTokens.begin(); i!=mTokens.end(); i++) + delete *i; +} + +bool PDefParser::Parse(const char *File) +{ + PFile *f = Filesystem->Open("", File, Config->GetOption("nc_data_path")); + enum { NOPE, MAYBE, LINE, BLOCK, MAYBE_END } Comment = NOPE; + + if(f) + { + while(!f->Eof()) + { + std::string Str = f->ReadString(); + int Len = Str.length(); + if(Len <= 0) + continue; + + if(Str.substr(0, 3)!="set") + continue; + + //Console->Print("%s", Str.c_str());//NEW was commented , just to be sure of what we are reading + + PTokenList *List = new PTokenList(); + int Start=0, Tokens=0; + bool Quote=false; + for(int i=0; i= Start) + { + List->push_back(std::string(Str.substr(Start, (End-Start)+1))); + Tokens++; + break; + } + Quote=false; + } + if(Comment != BLOCK) + Comment=NOPE; + break; + } + + if(!Quote) + { + if(Comment < LINE && (Str[i]=='\t' || Str[i]==',' || Str[i]==' ' || Str[i]==';' || Str[i]=='|' || i==Len-1)) + { + int End=i-1; + if(End >= Start) + { + List->push_back(std::string(Str.substr(Start, (End-Start)+1))); + Tokens++; + } + Start=i+1; + } + + if(Str[i] <= ' ') + continue; + + if(Str[i]=='*') + { + if(Comment==MAYBE) + Comment=BLOCK; + else + if(Comment==BLOCK) + Comment=MAYBE_END; + } else + if(Str[i]=='/') + { + if(Comment==MAYBE) + { + // second slash, skip rest of line + Comment=LINE; + break; + } else + if(Comment==MAYBE_END) + { + Comment=NOPE; // comment block ends + Start=i+1; + } else + if(Comment != BLOCK) + Comment=MAYBE; // first slash + } else + { + if(Comment==MAYBE) + Comment=NOPE; // stand-alone slash + else + if(Comment==MAYBE_END) + Comment=BLOCK; // comment block did not end + } + } + + if(Str[i]=='"') + Quote ^= true; + } + + if(Tokens > 0) + mTokens.push_back(List); + else + delete List; + } + } else + { + Console->Print("%s PDefParser::Parse: could not open file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), File); + return false; + } + + return true; +} diff --git a/TinNS/Source/GameServer/Definitions/Parser.hxx b/TinNS/Source/GameServer/Definitions/Parser.hxx index c9f3741..818fc84 100644 --- a/TinNS/Source/GameServer/Definitions/Parser.hxx +++ b/TinNS/Source/GameServer/Definitions/Parser.hxx @@ -1,18 +1,18 @@ -#pragma once - -#include -#include - -typedef std::list PTokenList; -typedef std::list PDefTokenList; - -class PDefParser { -private: - PDefTokenList mTokens; - -public: - PDefParser(); - ~PDefParser(); - bool Parse(const char *File); - inline const PDefTokenList &GetTokens() const { return mTokens; } -}; +#pragma once + +#include +#include + +typedef std::list PTokenList; +typedef std::list PDefTokenList; + +class PDefParser { +private: + PDefTokenList mTokens; + +public: + PDefParser(); + ~PDefParser(); + bool Parse(const char *File); + inline const PDefTokenList &GetTokens() const { return mTokens; } +}; diff --git a/TinNS/Source/GameServer/Definitions/Respawn.cxx b/TinNS/Source/GameServer/Definitions/Respawn.cxx index bf992e7..8d8a317 100644 --- a/TinNS/Source/GameServer/Definitions/Respawn.cxx +++ b/TinNS/Source/GameServer/Definitions/Respawn.cxx @@ -1,64 +1,64 @@ -#include "GameServer/Definitions/Includes.hxx" - -PDefRespawn::PDefRespawn() -{ -} - -bool PDefRespawn::LoadFromDef( PTokenList *Tokens ) -{ - int Idx = 0; - for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ ) - { - switch ( Idx ) - { - case 0: // setentry - continue; - - case 1: // index - mIndex = atoi( i->c_str() ); break; - - case 2: // value - mWorldID = atoi( i->c_str() ); break; - - case 3: // value - mEntityID = atoi( i->c_str() ); break; - - case 4: // value - mHazardLevel = atoi( i->c_str() ); break; - - case 5: // name - mName = *i; break; - - case 6: // world name - mFlag = *i; break; - } - } - - return true; -} - -// class PDefRespawnMap defined in gamedefs.h -int PDefRespawnsMap::GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const -{ - uint16_t tOrder = 0; - - for ( std::map::const_iterator it = mDefs.begin(); it != mDefs.end(); it++ ) - { - if (( uint32_t )( it->second->GetWorldID() ) == nWorldID ) - { - ++tOrder; - if (( nWorldID == 1 ) || ( nWorldID == 2 ) ) // hack for zones 1 & 2 - { - if (( 3 - tOrder ) == nGROrder ) - { - return ( it->second->GetEntityID() ); - } - } - else if ( tOrder == nGROrder ) - { - return ( it->second->GetEntityID() ); - } - } - } - return 0; -} +#include "GameServer/Definitions/Includes.hxx" + +PDefRespawn::PDefRespawn() +{ +} + +bool PDefRespawn::LoadFromDef( PTokenList *Tokens ) +{ + int Idx = 0; + for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ ) + { + switch ( Idx ) + { + case 0: // setentry + continue; + + case 1: // index + mIndex = atoi( i->c_str() ); break; + + case 2: // value + mWorldID = atoi( i->c_str() ); break; + + case 3: // value + mEntityID = atoi( i->c_str() ); break; + + case 4: // value + mHazardLevel = atoi( i->c_str() ); break; + + case 5: // name + mName = *i; break; + + case 6: // world name + mFlag = *i; break; + } + } + + return true; +} + +// class PDefRespawnMap defined in gamedefs.h +int PDefRespawnsMap::GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const +{ + uint16_t tOrder = 0; + + for ( std::map::const_iterator it = mDefs.begin(); it != mDefs.end(); it++ ) + { + if (( uint32_t )( it->second->GetWorldID() ) == nWorldID ) + { + ++tOrder; + if (( nWorldID == 1 ) || ( nWorldID == 2 ) ) // hack for zones 1 & 2 + { + if (( 3 - tOrder ) == nGROrder ) + { + return ( it->second->GetEntityID() ); + } + } + else if ( tOrder == nGROrder ) + { + return ( it->second->GetEntityID() ); + } + } + } + return 0; +} diff --git a/TinNS/Source/GameServer/Definitions/Respawn.hxx b/TinNS/Source/GameServer/Definitions/Respawn.hxx index 52b573d..fcaf910 100644 --- a/TinNS/Source/GameServer/Definitions/Respawn.hxx +++ b/TinNS/Source/GameServer/Definitions/Respawn.hxx @@ -1,32 +1,32 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefRespawn : public PDef { -private: - //int32_t mIndex; - int32_t mWorldID; - int32_t mEntityID; // Station ID - int32_t mHazardLevel; - std::string mName; // Description - std::string mFlag; // ??? - -public: - PDefRespawn(); - //~PDefRespawn(); - - bool LoadFromDef(PTokenList *Tokens); - - inline int32_t GetWorldID() const { return mWorldID; } - inline int32_t GetEntityID() const { return mEntityID; } - inline int32_t GetHazardLevel() const { return mHazardLevel; } - inline const std::string &GetName() const { return mName; } - inline const std::string &GetFlag() const { return mFlag; } -}; - -class PDefRespawnsMap : public PDefMap { -public: - int32_t GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const; -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefRespawn : public PDef { +private: + //int32_t mIndex; + int32_t mWorldID; + int32_t mEntityID; // Station ID + int32_t mHazardLevel; + std::string mName; // Description + std::string mFlag; // ??? + +public: + PDefRespawn(); + //~PDefRespawn(); + + bool LoadFromDef(PTokenList *Tokens); + + inline int32_t GetWorldID() const { return mWorldID; } + inline int32_t GetEntityID() const { return mEntityID; } + inline int32_t GetHazardLevel() const { return mHazardLevel; } + inline const std::string &GetName() const { return mName; } + inline const std::string &GetFlag() const { return mFlag; } +}; + +class PDefRespawnsMap : public PDefMap { +public: + int32_t GetRespawnEntity( uint32_t nWorldID, uint16_t nGROrder ) const; +}; diff --git a/TinNS/Source/GameServer/Definitions/Skills.cxx b/TinNS/Source/GameServer/Definitions/Skills.cxx index 14c28c5..a0d208d 100644 --- a/TinNS/Source/GameServer/Definitions/Skills.cxx +++ b/TinNS/Source/GameServer/Definitions/Skills.cxx @@ -1,63 +1,63 @@ -#include -#include "GameServer/Definitions/Includes.hxx" -#include "GameServer/Includes.hxx" - -// skill.def includes skill names and skill/subskill mapping - -PDefSkill::PDefSkill() -{ - mSubSkills = 0; - mNumSubSkills = 0; -} - -PDefSkill::~PDefSkill() -{ - delete [] mSubSkills; -} - -bool PDefSkill::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0 : // setentry - continue; - - case 1 : - mIndex = atol(i->c_str()); break; - - case 2 : - mName = *i; break; - - case 3 : - mShortName = *i; break; - - case 4 : - { - mNumSubSkills = atol(i->c_str()); - mSubSkills = new int[mNumSubSkills]; - std::memset(mSubSkills, 0, sizeof(int)*mNumSubSkills); - break; - } - } - - if(Idx >= 5) - { - mSubSkills[Idx-5] = atoi(i->c_str()); - if(!GameDefs->SubSkills()->GetDef(mSubSkills[Idx-5])) - { - Console->Print("Skill def error: skill %s refers to nonexistant subskill %i", mShortName.c_str(), mSubSkills[Idx-5]); - return false; - } - } - } - - if(Idx-5 != mNumSubSkills) - { - Console->Print("Warning: skill %s has incorrect number of subskills", mShortName.c_str()); - Console->Print(" Expected %i, available %i", mNumSubSkills, Idx-5); - } - return true; -} +#include +#include "GameServer/Definitions/Includes.hxx" +#include "GameServer/Includes.hxx" + +// skill.def includes skill names and skill/subskill mapping + +PDefSkill::PDefSkill() +{ + mSubSkills = 0; + mNumSubSkills = 0; +} + +PDefSkill::~PDefSkill() +{ + delete [] mSubSkills; +} + +bool PDefSkill::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0 : // setentry + continue; + + case 1 : + mIndex = atol(i->c_str()); break; + + case 2 : + mName = *i; break; + + case 3 : + mShortName = *i; break; + + case 4 : + { + mNumSubSkills = atol(i->c_str()); + mSubSkills = new int[mNumSubSkills]; + std::memset(mSubSkills, 0, sizeof(int)*mNumSubSkills); + break; + } + } + + if(Idx >= 5) + { + mSubSkills[Idx-5] = atoi(i->c_str()); + if(!GameDefs->SubSkills()->GetDef(mSubSkills[Idx-5])) + { + Console->Print("Skill def error: skill %s refers to nonexistant subskill %i", mShortName.c_str(), mSubSkills[Idx-5]); + return false; + } + } + } + + if(Idx-5 != mNumSubSkills) + { + Console->Print("Warning: skill %s has incorrect number of subskills", mShortName.c_str()); + Console->Print(" Expected %i, available %i", mNumSubSkills, Idx-5); + } + return true; +} diff --git a/TinNS/Source/GameServer/Definitions/Skills.hxx b/TinNS/Source/GameServer/Definitions/Skills.hxx index dcf42f8..45cc4c1 100644 --- a/TinNS/Source/GameServer/Definitions/Skills.hxx +++ b/TinNS/Source/GameServer/Definitions/Skills.hxx @@ -1,24 +1,24 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefSkill : public PDef { -private: - //int32_t mIndex; - std::string mName; - std::string mShortName; - int32_t mNumSubSkills; - int32_t *mSubSkills; -public: - PDefSkill(); - ~PDefSkill(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline const std::string &GetShortName() const { return mShortName; } - inline int32_t GetNumSubSkills() const { return mNumSubSkills; } - inline int32_t GetSubSkill(int32_t Index) const { return mSubSkills[Index]; } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefSkill : public PDef { +private: + //int32_t mIndex; + std::string mName; + std::string mShortName; + int32_t mNumSubSkills; + int32_t *mSubSkills; +public: + PDefSkill(); + ~PDefSkill(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline const std::string &GetShortName() const { return mShortName; } + inline int32_t GetNumSubSkills() const { return mNumSubSkills; } + inline int32_t GetSubSkill(int32_t Index) const { return mSubSkills[Index]; } +}; diff --git a/TinNS/Source/GameServer/Definitions/SubSkills.cxx b/TinNS/Source/GameServer/Definitions/SubSkills.cxx index ac6512f..87d02d1 100644 --- a/TinNS/Source/GameServer/Definitions/SubSkills.cxx +++ b/TinNS/Source/GameServer/Definitions/SubSkills.cxx @@ -1,54 +1,54 @@ -#include -#include "GameServer/Definitions/Includes.hxx" - -// subskill.def, names and parameters of all subskills - -PDefSubSkill::PDefSubSkill() -{ - mActionModifiers = 0; - mNumActionModifiers = 0; -} - -PDefSubSkill::~PDefSubSkill() -{ - delete [] mActionModifiers; -} - -bool PDefSubSkill::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0 : // setentry - continue; - - case 1 : - mIndex = atoi(i->c_str()); break; - - case 2 : - mName = *i; break; - - case 3 : - mShortName = *i; break; - - case 4 : - mStrengthenFactor = static_cast(atof(i->c_str())); break; - - case 5 : - { - mNumActionModifiers = atoi(i->c_str()); - mActionModifiers = new int[mNumActionModifiers]; - std::memset(mActionModifiers, 0, sizeof(int)*mNumActionModifiers); - break; - } - } - - if(Idx>=6) - mActionModifiers[Idx-6] = atoi(i->c_str()); - } - - return true; -} - +#include +#include "GameServer/Definitions/Includes.hxx" + +// subskill.def, names and parameters of all subskills + +PDefSubSkill::PDefSubSkill() +{ + mActionModifiers = 0; + mNumActionModifiers = 0; +} + +PDefSubSkill::~PDefSubSkill() +{ + delete [] mActionModifiers; +} + +bool PDefSubSkill::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0 : // setentry + continue; + + case 1 : + mIndex = atoi(i->c_str()); break; + + case 2 : + mName = *i; break; + + case 3 : + mShortName = *i; break; + + case 4 : + mStrengthenFactor = static_cast(atof(i->c_str())); break; + + case 5 : + { + mNumActionModifiers = atoi(i->c_str()); + mActionModifiers = new int[mNumActionModifiers]; + std::memset(mActionModifiers, 0, sizeof(int)*mNumActionModifiers); + break; + } + } + + if(Idx>=6) + mActionModifiers[Idx-6] = atoi(i->c_str()); + } + + return true; +} + diff --git a/TinNS/Source/GameServer/Definitions/SubSkills.hxx b/TinNS/Source/GameServer/Definitions/SubSkills.hxx index d2d1195..01dd301 100644 --- a/TinNS/Source/GameServer/Definitions/SubSkills.hxx +++ b/TinNS/Source/GameServer/Definitions/SubSkills.hxx @@ -1,27 +1,27 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefSubSkill : public PDef { -private: - //int32_t mIndex; - std::string mName; - std::string mShortName; - float mStrengthenFactor; - int32_t mNumActionModifiers; - int32_t *mActionModifiers; - -public: - PDefSubSkill(); - ~PDefSubSkill(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline const std::string &GetShortName() const { return mShortName; } - inline float GetStrengthenFactor() const { return mStrengthenFactor; } - inline int32_t GetNumActionModifiers() const { return mNumActionModifiers; } - inline int32_t GetActionModifier(int32_t Index) const { return mActionModifiers[Index]; } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefSubSkill : public PDef { +private: + //int32_t mIndex; + std::string mName; + std::string mShortName; + float mStrengthenFactor; + int32_t mNumActionModifiers; + int32_t *mActionModifiers; + +public: + PDefSubSkill(); + ~PDefSubSkill(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline const std::string &GetShortName() const { return mShortName; } + inline float GetStrengthenFactor() const { return mStrengthenFactor; } + inline int32_t GetNumActionModifiers() const { return mNumActionModifiers; } + inline int32_t GetActionModifier(int32_t Index) const { return mActionModifiers[Index]; } +}; diff --git a/TinNS/Source/GameServer/Definitions/WorldDatParser.cxx b/TinNS/Source/GameServer/Definitions/WorldDatParser.cxx index 86a4354..346a320 100644 --- a/TinNS/Source/GameServer/Definitions/WorldDatParser.cxx +++ b/TinNS/Source/GameServer/Definitions/WorldDatParser.cxx @@ -1,485 +1,485 @@ -#include -#include -#include "GameServer/Definitions/Includes.hxx" -#include "GameServer/Includes.hxx" - -const uint16_t nonDiscardUseFlags = ufTouchable | ufUsable | ufChair | ufToolTarget ; // furniture always to keep even if function type = 0 - -PWorldDatParser::PWorldDatParser() -{ - f = NULL; -} - -PWorldDatParser::~PWorldDatParser() -{ - -} - -int PWorldDatParser::LoadDatFile( const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects, const bool nTestAccesOnly ) -{ - PWorldFileHeader FileHeader; - PSectionHeader SectionHeader; - PSec2ElemHeader Sec2ElemHeader; - - uint32_t FileLen; - uint32_t NextSectionOffset = 0; - uint32_t NextElementOffset; - bool ProcessOK; - - mWorld = nWorld; - mDiscardPassiveObjects = nDiscardPassiveObjects; - - if ( mNCDataPath == "" ) - { - mNCDataPath = Config->GetOption( "nc_data_path" ); - } - - if ( gDevDebug ) - Console->Print( "Reading file %s/%s", mNCDataPath.c_str(), nFilename.c_str() ); - f = Filesystem->Open( "", nFilename.c_str(), mNCDataPath ); - - if ( nTestAccesOnly ) - { - ProcessOK = ( bool )f; - Filesystem->Close( f ); - return ( ProcessOK ? 0 : -1 ); - } - - if ( f ) - { - FileLen = f->GetSize(); - - // Section 1 - if (gDevDebug) - Console->Print( "Reading file header (section 1) ... " ); - f->Read( &FileHeader, sizeof( PWorldFileHeader ) ); - if (( FileHeader.mHeaderSize != 0x00000008 ) - || ( FileHeader.mHeaderSig != 0x000fcfcf ) - || ( FileHeader.mSection != 0x00000001 ) ) - { - if (gDevDebug) - Console->Print( "Read header: %08x / %08x / %08x", FileHeader.mHeaderSize, FileHeader.mHeaderSig, FileHeader.mSection); - Filesystem->Close( f ); - return -2; - } - NextSectionOffset += FileHeader.mHeaderSize + 4; - - // Other Sections - // Header - while ( ! f->Eof() ) - { - f->Seek( NextSectionOffset ); // Make sure we are at the computed offset - if (gDevDebug) - Console->Print( "Reading next section header ... " ); - if (( uint32_t )( f->Read( &SectionHeader, sizeof( PSectionHeader ) ) ) < sizeof( PSectionHeader ) ) - { - Filesystem->Close( f ); - return -3; - } - - if (( SectionHeader.mHeaderSize != 0x0000000c ) || ( SectionHeader.mHeaderSig != 0x0000ffcf ) ) - { - Filesystem->Close( f ); - return -2; - } - - if ( SectionHeader.mSection == 0 ) - { - if (gDevDebug) - Console->Print( "Ending section reached" ); - break; - } - - NextElementOffset = NextSectionOffset + SectionHeader.mHeaderSize + 4; - NextSectionOffset = NextElementOffset + SectionHeader.mDataSize; - if (gDevDebug) - Console->Print( "Processing section %d (size %d)", SectionHeader.mSection, SectionHeader.mDataSize ); - - if ( SectionHeader.mSection == 2 ) - { - //int cnt=0; - if ( gDevDebug ) - Console->Print( "Element Type 3 size: %d or %d", sizeof( PSec2ElemType3a ), sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ) ); - while ( NextElementOffset < NextSectionOffset ) - { - f->Seek( NextElementOffset ); // Make sure we are at the computed offset - - //if ( gDevDebug ) - // Console->Print( "Reading next element header ... " ); - if (( uint32_t )( f->Read( &Sec2ElemHeader, sizeof( PSec2ElemHeader ) ) ) < sizeof( PSec2ElemHeader ) ) - { - Filesystem->Close( f ); - return -3; - } - if (( Sec2ElemHeader.mHeaderSize != 0x0000000c ) || ( Sec2ElemHeader.mHeaderSig != 0x0ffefef1 ) ) - { - Filesystem->Close( f ); - return -2; - } - NextElementOffset += ( Sec2ElemHeader.mHeaderSize + 4 + Sec2ElemHeader.mDataSize ); - //if (gDevDebug) Console->Print("Found element %d of type %d, size %d", ++cnt, Sec2ElemHeader.mElementType, Sec2ElemHeader.mDataSize); - switch ( Sec2ElemHeader.mElementType ) - { - case 1000003: - { - ProcessOK = ProcessSec2ElemType3( Sec2ElemHeader.mDataSize ); - break; - } - case 1000005: - { - ProcessOK = ProcessSec2ElemType5( Sec2ElemHeader.mDataSize ); - break; - } - case 1000006: - { - ProcessOK = ProcessSec2NPCEntry( Sec2ElemHeader.mDataSize ); - break; - } - default: - { - if (gDevDebug) Console->Print( "Ignoring SectionID %d, not supportet yet", Sec2ElemHeader.mElementType ); - ProcessOK = true; - break; - } - } - - if ( !ProcessOK ) - return -4; - } - } - else - { - if ( gDevDebug ) - Console->Print( "Section %d ignored", SectionHeader.mSection ); - continue; - } - - } - - Filesystem->Close( f ); - } - else - { - return -1; - } - - return 0; -} - -bool PWorldDatParser::ProcessSec2ElemType3( uint32_t nSize ) // furniture -{ - PSec2ElemType3a DataA; - PSec2ElemType3b DataB; - const PDefWorldModel* nWorldModel; - std::string nName; - const uint32_t sza = sizeof( PSec2ElemType3a ); - const uint32_t szb = sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ); - - if (( nSize != szb ) && ( nSize != sza ) ) - { - Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType3 (%d read vs %d or %d needed", nSize, sza, szb ); - return false; - } - if (( uint32_t )( f->Read( &DataA, sza ) ) < sza ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3a" ); - return false; - } - if ( nSize == szb ) - { - if (( uint32_t )( f->Read( &DataB, sizeof( PSec2ElemType3b ) ) ) < sizeof( PSec2ElemType3b ) ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3b" ); - return false; - } - } - else - { - DataB.mBoxLowerY = DataB.mBoxLowerZ = DataB.mBoxLowerX = 0; - DataB.mBoxUpperY = DataB.mBoxUpperZ = DataB.mBoxUpperX = 0; - } - - if ( DataA.mWorldmodelID ) - { - nWorldModel = GameDefs->WorldModels()->GetDef( DataA.mWorldmodelID ); - if ( nWorldModel ) - nName = nWorldModel->GetName(); - else - nName = "UNKNOWN"; - } - else - { - nName = "PASSIVE"; - nWorldModel = NULL; - } - - /* if (gDevDebug) { - Console->Print("-------------------------------------------------------"); - Console->Print("%s (%d) : ID %d", nName.c_str(), DataA.mWorldmodelID, DataA.mObjectID); - if (!nWorldModel) Console->Print("y:%f z:%f x:%f model %d", DataA.mPosY , DataA.mPosZ, DataA.mPosX, DataA.mModelID); - Console->Print("Scale:%f Uk2:0x%08x Uk3:0x%08x", DataA.mScale, DataA.mUnknown2, DataA.mUnknown3); - Console->Print("Uk4:0x%08x Uk5:0x%04x", DataA.mUnknown4, DataA.mUnknown5); - //Console->Print("Ly:%f Lz:%f Lx:%f", DataB.mBoxLowerY, DataB.mBoxLowerZ, DataB.mBoxLowerX); - //Console->Print("Uy:%f Uz:%f Ux:%f", DataB.mBoxUpperY, DataB.mBoxUpperZ, DataB.mBoxUpperX); - }*/ - - if (( !nWorldModel || ( !nWorldModel->GetFunctionType() && !( nWorldModel->GetUseFlags() & nonDiscardUseFlags ) ) ) && mDiscardPassiveObjects ) - { - //if ( gDevDebug ) - // Console->Print( "Discarded" ); - return true; - } - - PFurnitureItemTemplate* nItem = new PFurnitureItemTemplate; - nItem->mObjectID = DataA.mObjectID; - - // The commented out values are not loaded from dat file atm because they are not used yet. - nItem->mPosY = DataA.mPosY; // float pos values are kept 0-centered - nItem->mPosZ = DataA.mPosZ; - nItem->mPosX = DataA.mPosX; -// nItem->mRotY = DataA.mRotY; - nItem->mRotZ = DataA.mRotZ; -// nItem->mRotX = DataA.mRotX; -// nItem->mScale = DataA.mScale; -// nItem->mUnknown2 = DataA.mUnknown2; - nItem->mModelID = DataA.mModelID; -// nItem->mUnknown3 = DataA.mUnknown3; -// nItem->mUnknown4 = DataA.mUnknown4; - nItem->mWorldmodelID = DataA.mWorldmodelID; -// nItem->mUnknown5 = DataA.mUnknown5; - -// nItem->mBoxLowerY = DataB.mBoxLowerY; -// nItem->mBoxLowerZ = DataB.mBoxLowerZ; -// nItem->mBoxLowerX = DataB.mBoxLowerX; -// nItem->mBoxUpperY = DataB.mBoxUpperY; -// nItem->mBoxUpperZ = DataB.mBoxUpperZ; -// nItem->mBoxUpperX = DataB.mBoxUpperX; - - nItem->mDefWorldModel = nWorldModel; - /*uint16_t func=nWorldModel->GetFunctionType(); - if((func==18) || (func==20) || (func==29)) - Console->Print("gate model: %d", DataA.mWorldmodelID);*/ - - float Angle = ( 180 + DataA.mRotZ ) * 3.14159 / 180; - float Radius = abs(( int )(( DataB.mBoxUpperX - DataB.mBoxLowerX ) / 2 ) ); - if ( Radius == 0 ) - { - Radius = 10; - } - Radius *= DataA.mScale; - Radius += 5; - - // int pos values are change to match char pos scale (32000 centered) - nItem->mFrontPosY = ( uint16_t )( 32000 + DataA.mPosY + Radius * sinf( Angle ) ); - nItem->mFrontPosZ = ( uint16_t )( 32000 + DataA.mPosZ ); - nItem->mFrontPosX = ( uint16_t )( 32000 + DataA.mPosX + Radius * cosf( Angle ) ); - nItem->mFrontLR = ( uint8_t )( 0.5 * ( DataA.mRotZ + ( DataA.mRotZ < 0 ? 360 : 0 ) ) ); - - mWorld->AddFurnitureItem( nItem ); - - return true; -} - -bool PWorldDatParser::ProcessSec2ElemType5( uint32_t nSize ) // doors -{ - PSec2ElemType5Start Data; - char StringData[64]; - - const PDefWorldModel* nWorldModel; - std::string nName; - char* ActorString; - char* ParamString; - - const uint32_t sza = sizeof( PSec2ElemType5Start ); - - if (( nSize < sza ) ) - { - Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza ); - return false; - } - if (( uint32_t )( f->Read( &Data, sza ) ) < sza ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5start" ); - return false; - } - uint32_t szb = Data.mActorStringSize + Data.mParamStringSize; - - if ( nSize != ( sza + szb ) ) - { - Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza + szb ); - return false; - } - else - { - if ( szb > 64 ) - { - Console->Print( RED, BLACK, "[Warning] String data too long in Sec2ElemType5 End String. End will be ignored" ); - szb = 64; - } - if (( uint32_t )( f->Read( StringData, szb ) ) < szb ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5 End Strings" ); - return false; - } - } - - if ( Data.mWorldmodelID ) - { - nWorldModel = GameDefs->WorldModels()->GetDef( Data.mWorldmodelID ); - if ( nWorldModel ) - nName = nWorldModel->GetName(); - else - nName = "UNKNOWN"; - } - else - { - nName = "PASSIVE"; - nWorldModel = NULL; - } - - StringData[Data.mActorStringSize - 1] = 0; - ActorString = StringData; - StringData[szb - 1] = 0; - ParamString = StringData + Data.mActorStringSize; - /* - if ( gDevDebug ) - { - Console->Print( "-------------------------------------------------------" ); - Console->Print( "Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID ); - Console->Print( "y:%f z:%f x:%f", Data.mPosY , Data.mPosZ, Data.mPosX ); - Console->Print( "Uk1:0x%04x Uk1bis:0x%04x Uk5:0x%04x", Data.mUnknown1, Data.mUnknown1bis, Data.mUnknown5 ); - Console->Print( "Type=%s Param=%s", ActorString, ParamString ); - } - */ -// Let's keep knowledge of doors even without models ! - /* if ((!nWorldModel || (!nWorldModel->GetFunctionType() && !(nWorldModel->GetUseFlags() & nonDiscardUseFlags))) && mDiscardPassiveObjects) - { - if (gDevDebug) Console->Print("Discarded"); - if (gDevDebug) - { - Console->Print("Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID); - Console->Print("Type=%s Param=%s", ActorString, ParamString); - } - return true; - }*/ - - PDoorTemplate* nDoor = new PDoorTemplate; - nDoor->mDoorID = Data.mDoorID; - - //nDoor->mUnknown1 = Data.mUnknown1; //18 00 - //nDoor->mUnknown1bis = Data.mUnknown1bis; //00 00 ? varies - nDoor->mPosY = Data.mPosY; - nDoor->mPosZ = Data.mPosZ; - nDoor->mPosX = Data.mPosX; - //nDoor->mUnknown5 = Data.mUnknown5; //00 00 ? second byte varies - nDoor->mWorldmodelID = Data.mWorldmodelID; //door type from worldmodel.def - nDoor->mDefWorldModel = nWorldModel; - - nDoor->SetDoorTypeName( ActorString ); - nDoor->SetDoorParameters( ParamString ); - - mWorld->AddDoor( nDoor ); - - return true; -} - -bool PWorldDatParser::ProcessSec2NPCEntry( uint32_t nSize ) -{ - PSec2NPC_EntryPart1 tNPCPartA; - PSec2NPC_EntryPart2 tNPCPartB; - std::string tActorName; - std::string tAngle; - char tStrBuffer[64]; - - uint32_t tSizeOfA = sizeof(tNPCPartA); - uint32_t tSizeOfB = sizeof(tNPCPartB); - - // Are we able to read enough bytes from the file? means: CAN we safely read our entire struct from the file? - if ( nSize < tSizeOfA ) - { - Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_EntryPart1 (%d read vs %d needed", nSize, tSizeOfA ); - return false; - } - // yes we can! So read it now. If we reach EOF, break - if (( uint32_t )( f->Read( &tNPCPartA, tSizeOfA ) ) < tSizeOfA ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry" ); - return false; - } - // Now we have the header. lets check if we have some waypoints for this NPC - // Size of entire NPC entry in file - uint32_t tCompleteNPCSize = tSizeOfA + tNPCPartA.mActorStringSize + tNPCPartA.mAngleStringSize; - if ( tNPCPartA.mHasAdditionalCoords > 0 ) - { - // It has additional coords, add 'em - tCompleteNPCSize += tSizeOfB*tNPCPartA.mHasAdditionalCoords; - } - - // Do a last check if we're on the correct size - if ( nSize != tCompleteNPCSize ) - { - Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_Entry (%d available vs %d expected", nSize, tCompleteNPCSize ); - Console->Print( RED, BLACK, "NPC ID was: %d", tNPCPartA.mNpcID); - return false; - } - // We are. Continue reading! - // Assign the 2 strings and watch out for EOF! - memset(tStrBuffer, 0, 64); - if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mActorStringSize ) ) < tNPCPartA.mActorStringSize ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mActorStringSize" ); - return false; - } - tActorName = tStrBuffer; - - memset(tStrBuffer, 0, 64); - if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mAngleStringSize ) ) < tNPCPartA.mAngleStringSize ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mAngleStringSize" ); - return false; - } - tAngle = tStrBuffer; - - // We're done. Now create new NPC entry - PNPCTemplate* tNPC = new PNPCTemplate; - - // and assing all that stuff - tNPC->SetUnknown1(tNPCPartA.mUnknown1); - tNPC->SetPosX(tNPCPartA.mPosX); - tNPC->SetPosY(tNPCPartA.mPosY); - tNPC->SetPosZ(tNPCPartA.mPosZ); - tNPC->SetNPCTypeID(tNPCPartA.mNPCTypeID); - tNPC->SetActorStrSize(tNPCPartA.mActorStringSize); - tNPC->SetAngleStrSize(tNPCPartA.mAngleStringSize); - tNPC->SetNpcID(tNPCPartA.mNpcID); - tNPC->SetUnknown2a(tNPCPartA.mUnknown2a); - tNPC->SetUnknown2b(tNPCPartA.mUnknown2b); - tNPC->SetUnknown2c(tNPCPartA.mUnknown2c); - tNPC->SetTradeID/*SetUnknown3*/(tNPCPartA.mTradeID/*mUnknown3*/); - tNPC->SetUnknown4(tNPCPartA.mUnknown4); - - tNPC->SetActorName(tActorName); - tNPC->SetAngle(tAngle); - - // Read additional Waypoints if available - uint8_t tCurrWayP = 0; - if ( tNPCPartA.mHasAdditionalCoords > 0 ) - { - while ( tCurrWayP < tNPCPartA.mHasAdditionalCoords ) - { - memset(&tNPCPartB, 0, tSizeOfB); - if (( uint32_t )( f->Read( &tNPCPartB, tSizeOfB ) ) < tSizeOfB ) - { - Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry while reading WayPoints" ); - return false; - } - tNPC->AddWayPoint(tNPCPartB.mPosX, tNPCPartB.mPosY, tNPCPartB.mPosZ, tCurrWayP); - tCurrWayP++; - } - } - - if (gDevDebug) Console->Print("Added NPC ID %d", tNPCPartA.mNpcID); - - mWorld->AddNPC(tNPC); - return true; -} +#include +#include +#include "GameServer/Definitions/Includes.hxx" +#include "GameServer/Includes.hxx" + +const uint16_t nonDiscardUseFlags = ufTouchable | ufUsable | ufChair | ufToolTarget ; // furniture always to keep even if function type = 0 + +PWorldDatParser::PWorldDatParser() +{ + f = NULL; +} + +PWorldDatParser::~PWorldDatParser() +{ + +} + +int PWorldDatParser::LoadDatFile( const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects, const bool nTestAccesOnly ) +{ + PWorldFileHeader FileHeader; + PSectionHeader SectionHeader; + PSec2ElemHeader Sec2ElemHeader; + + uint32_t FileLen; + uint32_t NextSectionOffset = 0; + uint32_t NextElementOffset; + bool ProcessOK; + + mWorld = nWorld; + mDiscardPassiveObjects = nDiscardPassiveObjects; + + if ( mNCDataPath == "" ) + { + mNCDataPath = Config->GetOption( "nc_data_path" ); + } + + if ( gDevDebug ) + Console->Print( "Reading file %s/%s", mNCDataPath.c_str(), nFilename.c_str() ); + f = Filesystem->Open( "", nFilename.c_str(), mNCDataPath ); + + if ( nTestAccesOnly ) + { + ProcessOK = ( bool )f; + Filesystem->Close( f ); + return ( ProcessOK ? 0 : -1 ); + } + + if ( f ) + { + FileLen = f->GetSize(); + + // Section 1 + if (gDevDebug) + Console->Print( "Reading file header (section 1) ... " ); + f->Read( &FileHeader, sizeof( PWorldFileHeader ) ); + if (( FileHeader.mHeaderSize != 0x00000008 ) + || ( FileHeader.mHeaderSig != 0x000fcfcf ) + || ( FileHeader.mSection != 0x00000001 ) ) + { + if (gDevDebug) + Console->Print( "Read header: %08x / %08x / %08x", FileHeader.mHeaderSize, FileHeader.mHeaderSig, FileHeader.mSection); + Filesystem->Close( f ); + return -2; + } + NextSectionOffset += FileHeader.mHeaderSize + 4; + + // Other Sections + // Header + while ( ! f->Eof() ) + { + f->Seek( NextSectionOffset ); // Make sure we are at the computed offset + if (gDevDebug) + Console->Print( "Reading next section header ... " ); + if (( uint32_t )( f->Read( &SectionHeader, sizeof( PSectionHeader ) ) ) < sizeof( PSectionHeader ) ) + { + Filesystem->Close( f ); + return -3; + } + + if (( SectionHeader.mHeaderSize != 0x0000000c ) || ( SectionHeader.mHeaderSig != 0x0000ffcf ) ) + { + Filesystem->Close( f ); + return -2; + } + + if ( SectionHeader.mSection == 0 ) + { + if (gDevDebug) + Console->Print( "Ending section reached" ); + break; + } + + NextElementOffset = NextSectionOffset + SectionHeader.mHeaderSize + 4; + NextSectionOffset = NextElementOffset + SectionHeader.mDataSize; + if (gDevDebug) + Console->Print( "Processing section %d (size %d)", SectionHeader.mSection, SectionHeader.mDataSize ); + + if ( SectionHeader.mSection == 2 ) + { + //int cnt=0; + if ( gDevDebug ) + Console->Print( "Element Type 3 size: %d or %d", sizeof( PSec2ElemType3a ), sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ) ); + while ( NextElementOffset < NextSectionOffset ) + { + f->Seek( NextElementOffset ); // Make sure we are at the computed offset + + //if ( gDevDebug ) + // Console->Print( "Reading next element header ... " ); + if (( uint32_t )( f->Read( &Sec2ElemHeader, sizeof( PSec2ElemHeader ) ) ) < sizeof( PSec2ElemHeader ) ) + { + Filesystem->Close( f ); + return -3; + } + if (( Sec2ElemHeader.mHeaderSize != 0x0000000c ) || ( Sec2ElemHeader.mHeaderSig != 0x0ffefef1 ) ) + { + Filesystem->Close( f ); + return -2; + } + NextElementOffset += ( Sec2ElemHeader.mHeaderSize + 4 + Sec2ElemHeader.mDataSize ); + //if (gDevDebug) Console->Print("Found element %d of type %d, size %d", ++cnt, Sec2ElemHeader.mElementType, Sec2ElemHeader.mDataSize); + switch ( Sec2ElemHeader.mElementType ) + { + case 1000003: + { + ProcessOK = ProcessSec2ElemType3( Sec2ElemHeader.mDataSize ); + break; + } + case 1000005: + { + ProcessOK = ProcessSec2ElemType5( Sec2ElemHeader.mDataSize ); + break; + } + case 1000006: + { + ProcessOK = ProcessSec2NPCEntry( Sec2ElemHeader.mDataSize ); + break; + } + default: + { + if (gDevDebug) Console->Print( "Ignoring SectionID %d, not supportet yet", Sec2ElemHeader.mElementType ); + ProcessOK = true; + break; + } + } + + if ( !ProcessOK ) + return -4; + } + } + else + { + if ( gDevDebug ) + Console->Print( "Section %d ignored", SectionHeader.mSection ); + continue; + } + + } + + Filesystem->Close( f ); + } + else + { + return -1; + } + + return 0; +} + +bool PWorldDatParser::ProcessSec2ElemType3( uint32_t nSize ) // furniture +{ + PSec2ElemType3a DataA; + PSec2ElemType3b DataB; + const PDefWorldModel* nWorldModel; + std::string nName; + const uint32_t sza = sizeof( PSec2ElemType3a ); + const uint32_t szb = sizeof( PSec2ElemType3a ) + sizeof( PSec2ElemType3b ); + + if (( nSize != szb ) && ( nSize != sza ) ) + { + Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType3 (%d read vs %d or %d needed", nSize, sza, szb ); + return false; + } + if (( uint32_t )( f->Read( &DataA, sza ) ) < sza ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3a" ); + return false; + } + if ( nSize == szb ) + { + if (( uint32_t )( f->Read( &DataB, sizeof( PSec2ElemType3b ) ) ) < sizeof( PSec2ElemType3b ) ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType3b" ); + return false; + } + } + else + { + DataB.mBoxLowerY = DataB.mBoxLowerZ = DataB.mBoxLowerX = 0; + DataB.mBoxUpperY = DataB.mBoxUpperZ = DataB.mBoxUpperX = 0; + } + + if ( DataA.mWorldmodelID ) + { + nWorldModel = GameDefs->WorldModels()->GetDef( DataA.mWorldmodelID ); + if ( nWorldModel ) + nName = nWorldModel->GetName(); + else + nName = "UNKNOWN"; + } + else + { + nName = "PASSIVE"; + nWorldModel = NULL; + } + + /* if (gDevDebug) { + Console->Print("-------------------------------------------------------"); + Console->Print("%s (%d) : ID %d", nName.c_str(), DataA.mWorldmodelID, DataA.mObjectID); + if (!nWorldModel) Console->Print("y:%f z:%f x:%f model %d", DataA.mPosY , DataA.mPosZ, DataA.mPosX, DataA.mModelID); + Console->Print("Scale:%f Uk2:0x%08x Uk3:0x%08x", DataA.mScale, DataA.mUnknown2, DataA.mUnknown3); + Console->Print("Uk4:0x%08x Uk5:0x%04x", DataA.mUnknown4, DataA.mUnknown5); + //Console->Print("Ly:%f Lz:%f Lx:%f", DataB.mBoxLowerY, DataB.mBoxLowerZ, DataB.mBoxLowerX); + //Console->Print("Uy:%f Uz:%f Ux:%f", DataB.mBoxUpperY, DataB.mBoxUpperZ, DataB.mBoxUpperX); + }*/ + + if (( !nWorldModel || ( !nWorldModel->GetFunctionType() && !( nWorldModel->GetUseFlags() & nonDiscardUseFlags ) ) ) && mDiscardPassiveObjects ) + { + //if ( gDevDebug ) + // Console->Print( "Discarded" ); + return true; + } + + PFurnitureItemTemplate* nItem = new PFurnitureItemTemplate; + nItem->mObjectID = DataA.mObjectID; + + // The commented out values are not loaded from dat file atm because they are not used yet. + nItem->mPosY = DataA.mPosY; // float pos values are kept 0-centered + nItem->mPosZ = DataA.mPosZ; + nItem->mPosX = DataA.mPosX; +// nItem->mRotY = DataA.mRotY; + nItem->mRotZ = DataA.mRotZ; +// nItem->mRotX = DataA.mRotX; +// nItem->mScale = DataA.mScale; +// nItem->mUnknown2 = DataA.mUnknown2; + nItem->mModelID = DataA.mModelID; +// nItem->mUnknown3 = DataA.mUnknown3; +// nItem->mUnknown4 = DataA.mUnknown4; + nItem->mWorldmodelID = DataA.mWorldmodelID; +// nItem->mUnknown5 = DataA.mUnknown5; + +// nItem->mBoxLowerY = DataB.mBoxLowerY; +// nItem->mBoxLowerZ = DataB.mBoxLowerZ; +// nItem->mBoxLowerX = DataB.mBoxLowerX; +// nItem->mBoxUpperY = DataB.mBoxUpperY; +// nItem->mBoxUpperZ = DataB.mBoxUpperZ; +// nItem->mBoxUpperX = DataB.mBoxUpperX; + + nItem->mDefWorldModel = nWorldModel; + /*uint16_t func=nWorldModel->GetFunctionType(); + if((func==18) || (func==20) || (func==29)) + Console->Print("gate model: %d", DataA.mWorldmodelID);*/ + + float Angle = ( 180 + DataA.mRotZ ) * 3.14159 / 180; + float Radius = abs(( int )(( DataB.mBoxUpperX - DataB.mBoxLowerX ) / 2 ) ); + if ( Radius == 0 ) + { + Radius = 10; + } + Radius *= DataA.mScale; + Radius += 5; + + // int pos values are change to match char pos scale (32000 centered) + nItem->mFrontPosY = ( uint16_t )( 32000 + DataA.mPosY + Radius * sinf( Angle ) ); + nItem->mFrontPosZ = ( uint16_t )( 32000 + DataA.mPosZ ); + nItem->mFrontPosX = ( uint16_t )( 32000 + DataA.mPosX + Radius * cosf( Angle ) ); + nItem->mFrontLR = ( uint8_t )( 0.5 * ( DataA.mRotZ + ( DataA.mRotZ < 0 ? 360 : 0 ) ) ); + + mWorld->AddFurnitureItem( nItem ); + + return true; +} + +bool PWorldDatParser::ProcessSec2ElemType5( uint32_t nSize ) // doors +{ + PSec2ElemType5Start Data; + char StringData[64]; + + const PDefWorldModel* nWorldModel; + std::string nName; + char* ActorString; + char* ParamString; + + const uint32_t sza = sizeof( PSec2ElemType5Start ); + + if (( nSize < sza ) ) + { + Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza ); + return false; + } + if (( uint32_t )( f->Read( &Data, sza ) ) < sza ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5start" ); + return false; + } + uint32_t szb = Data.mActorStringSize + Data.mParamStringSize; + + if ( nSize != ( sza + szb ) ) + { + Console->Print( RED, BLACK, "[ERROR] Wrong size for Sec2ElemType5 (%d read vs %d needed", nSize, sza + szb ); + return false; + } + else + { + if ( szb > 64 ) + { + Console->Print( RED, BLACK, "[Warning] String data too long in Sec2ElemType5 End String. End will be ignored" ); + szb = 64; + } + if (( uint32_t )( f->Read( StringData, szb ) ) < szb ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in Sec2ElemType5 End Strings" ); + return false; + } + } + + if ( Data.mWorldmodelID ) + { + nWorldModel = GameDefs->WorldModels()->GetDef( Data.mWorldmodelID ); + if ( nWorldModel ) + nName = nWorldModel->GetName(); + else + nName = "UNKNOWN"; + } + else + { + nName = "PASSIVE"; + nWorldModel = NULL; + } + + StringData[Data.mActorStringSize - 1] = 0; + ActorString = StringData; + StringData[szb - 1] = 0; + ParamString = StringData + Data.mActorStringSize; + /* + if ( gDevDebug ) + { + Console->Print( "-------------------------------------------------------" ); + Console->Print( "Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID ); + Console->Print( "y:%f z:%f x:%f", Data.mPosY , Data.mPosZ, Data.mPosX ); + Console->Print( "Uk1:0x%04x Uk1bis:0x%04x Uk5:0x%04x", Data.mUnknown1, Data.mUnknown1bis, Data.mUnknown5 ); + Console->Print( "Type=%s Param=%s", ActorString, ParamString ); + } + */ +// Let's keep knowledge of doors even without models ! + /* if ((!nWorldModel || (!nWorldModel->GetFunctionType() && !(nWorldModel->GetUseFlags() & nonDiscardUseFlags))) && mDiscardPassiveObjects) + { + if (gDevDebug) Console->Print("Discarded"); + if (gDevDebug) + { + Console->Print("Door %s (%d) : ID %d", nName.c_str(), Data.mWorldmodelID, Data.mDoorID); + Console->Print("Type=%s Param=%s", ActorString, ParamString); + } + return true; + }*/ + + PDoorTemplate* nDoor = new PDoorTemplate; + nDoor->mDoorID = Data.mDoorID; + + //nDoor->mUnknown1 = Data.mUnknown1; //18 00 + //nDoor->mUnknown1bis = Data.mUnknown1bis; //00 00 ? varies + nDoor->mPosY = Data.mPosY; + nDoor->mPosZ = Data.mPosZ; + nDoor->mPosX = Data.mPosX; + //nDoor->mUnknown5 = Data.mUnknown5; //00 00 ? second byte varies + nDoor->mWorldmodelID = Data.mWorldmodelID; //door type from worldmodel.def + nDoor->mDefWorldModel = nWorldModel; + + nDoor->SetDoorTypeName( ActorString ); + nDoor->SetDoorParameters( ParamString ); + + mWorld->AddDoor( nDoor ); + + return true; +} + +bool PWorldDatParser::ProcessSec2NPCEntry( uint32_t nSize ) +{ + PSec2NPC_EntryPart1 tNPCPartA; + PSec2NPC_EntryPart2 tNPCPartB; + std::string tActorName; + std::string tAngle; + char tStrBuffer[64]; + + uint32_t tSizeOfA = sizeof(tNPCPartA); + uint32_t tSizeOfB = sizeof(tNPCPartB); + + // Are we able to read enough bytes from the file? means: CAN we safely read our entire struct from the file? + if ( nSize < tSizeOfA ) + { + Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_EntryPart1 (%d read vs %d needed", nSize, tSizeOfA ); + return false; + } + // yes we can! So read it now. If we reach EOF, break + if (( uint32_t )( f->Read( &tNPCPartA, tSizeOfA ) ) < tSizeOfA ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry" ); + return false; + } + // Now we have the header. lets check if we have some waypoints for this NPC + // Size of entire NPC entry in file + uint32_t tCompleteNPCSize = tSizeOfA + tNPCPartA.mActorStringSize + tNPCPartA.mAngleStringSize; + if ( tNPCPartA.mHasAdditionalCoords > 0 ) + { + // It has additional coords, add 'em + tCompleteNPCSize += tSizeOfB*tNPCPartA.mHasAdditionalCoords; + } + + // Do a last check if we're on the correct size + if ( nSize != tCompleteNPCSize ) + { + Console->Print( RED, BLACK, "[ERROR] Wrong size for PSec2NPC_Entry (%d available vs %d expected", nSize, tCompleteNPCSize ); + Console->Print( RED, BLACK, "NPC ID was: %d", tNPCPartA.mNpcID); + return false; + } + // We are. Continue reading! + // Assign the 2 strings and watch out for EOF! + memset(tStrBuffer, 0, 64); + if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mActorStringSize ) ) < tNPCPartA.mActorStringSize ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mActorStringSize" ); + return false; + } + tActorName = tStrBuffer; + + memset(tStrBuffer, 0, 64); + if (( uint32_t )( f->Read( tStrBuffer, tNPCPartA.mAngleStringSize ) ) < tNPCPartA.mAngleStringSize ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry mAngleStringSize" ); + return false; + } + tAngle = tStrBuffer; + + // We're done. Now create new NPC entry + PNPCTemplate* tNPC = new PNPCTemplate; + + // and assing all that stuff + tNPC->SetUnknown1(tNPCPartA.mUnknown1); + tNPC->SetPosX(tNPCPartA.mPosX); + tNPC->SetPosY(tNPCPartA.mPosY); + tNPC->SetPosZ(tNPCPartA.mPosZ); + tNPC->SetNPCTypeID(tNPCPartA.mNPCTypeID); + tNPC->SetActorStrSize(tNPCPartA.mActorStringSize); + tNPC->SetAngleStrSize(tNPCPartA.mAngleStringSize); + tNPC->SetNpcID(tNPCPartA.mNpcID); + tNPC->SetUnknown2a(tNPCPartA.mUnknown2a); + tNPC->SetUnknown2b(tNPCPartA.mUnknown2b); + tNPC->SetUnknown2c(tNPCPartA.mUnknown2c); + tNPC->SetTradeID/*SetUnknown3*/(tNPCPartA.mTradeID/*mUnknown3*/); + tNPC->SetUnknown4(tNPCPartA.mUnknown4); + + tNPC->SetActorName(tActorName); + tNPC->SetAngle(tAngle); + + // Read additional Waypoints if available + uint8_t tCurrWayP = 0; + if ( tNPCPartA.mHasAdditionalCoords > 0 ) + { + while ( tCurrWayP < tNPCPartA.mHasAdditionalCoords ) + { + memset(&tNPCPartB, 0, tSizeOfB); + if (( uint32_t )( f->Read( &tNPCPartB, tSizeOfB ) ) < tSizeOfB ) + { + Console->Print( RED, BLACK, "[ERROR] Unexpected end of file in ProcessSec2NPCEntry while reading WayPoints" ); + return false; + } + tNPC->AddWayPoint(tNPCPartB.mPosX, tNPCPartB.mPosY, tNPCPartB.mPosZ, tCurrWayP); + tCurrWayP++; + } + } + + if (gDevDebug) Console->Print("Added NPC ID %d", tNPCPartA.mNpcID); + + mWorld->AddNPC(tNPC); + return true; +} diff --git a/TinNS/Source/GameServer/Definitions/WorldDatParser.hxx b/TinNS/Source/GameServer/Definitions/WorldDatParser.hxx index dfe60bd..136b408 100644 --- a/TinNS/Source/GameServer/Definitions/WorldDatParser.hxx +++ b/TinNS/Source/GameServer/Definitions/WorldDatParser.hxx @@ -1,26 +1,26 @@ -#pragma once - -#include -#include - -class PFile; -class PWorldDataTemplate; - -class PWorldDatParser { -private: - PFile* f; - std::string mNCDataPath; - - PWorldDataTemplate* mWorld; - bool mDiscardPassiveObjects; - - bool ProcessSec2ElemType3(uint32_t nSize); - bool ProcessSec2ElemType5(uint32_t nSize); - bool ProcessSec2NPCEntry(uint32_t nSize); - -public: - PWorldDatParser(); - ~PWorldDatParser(); - - int32_t LoadDatFile(const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects = true, const bool nTestAccesOnly = false); -}; +#pragma once + +#include +#include + +class PFile; +class PWorldDataTemplate; + +class PWorldDatParser { +private: + PFile* f; + std::string mNCDataPath; + + PWorldDataTemplate* mWorld; + bool mDiscardPassiveObjects; + + bool ProcessSec2ElemType3(uint32_t nSize); + bool ProcessSec2ElemType5(uint32_t nSize); + bool ProcessSec2NPCEntry(uint32_t nSize); + +public: + PWorldDatParser(); + ~PWorldDatParser(); + + int32_t LoadDatFile(const std::string& nFilename, PWorldDataTemplate* nWorld, const bool nDiscardPassiveObjects = true, const bool nTestAccesOnly = false); +}; diff --git a/TinNS/Source/GameServer/Definitions/WorldDatStruct.hxx b/TinNS/Source/GameServer/Definitions/WorldDatStruct.hxx index 0d1d4a1..57f92c7 100644 --- a/TinNS/Source/GameServer/Definitions/WorldDatStruct.hxx +++ b/TinNS/Source/GameServer/Definitions/WorldDatStruct.hxx @@ -1,128 +1,128 @@ -#pragma once - -#include - -struct PWorldFileHeader { - uint32_t mHeaderSize; // must be 08 00 00 00, = header size after this field - uint32_t mHeaderSig; // must be CF CF 0F 00 - uint32_t mSection; // must be 01 00 00 00 -}; - -struct PSectionHeader { - uint32_t mHeaderSize; // must be 0C 00 00 00 - uint32_t mHeaderSig; // must be CF FF 00 00 - uint32_t mSection; // 00 00 00 00 means end - uint32_t mDataSize; -}; - -struct PSec2ElemHeader { - uint32_t mHeaderSize; // must be 0C 00 00 00 - uint32_t mHeaderSig; // must be F1 FE FE 0F - uint32_t mElementType; // 1000003, 1000005 or 1000014 - uint32_t mDataSize; -}; - -struct PSec2ElemType3a { //static object ? - float mPosY; //= uint32_t16_t PosY - 32000 - float mPosZ; - float mPosX; - float mRotY; - float mRotZ; - float mRotX; - float mScale; //00 00 80 3F ? = float(1.000000) !!! => scale factor ????? - uint32_t mUnknown2; //01 00 00 00 ? - uint16_t mModelID; // point32_ts to models.ini - uint32_t mUnknown3; //00 00 00 00 ? - uint32_t mUnknown4; //00 00 00 00 ? - uint16_t mWorldmodelID; // point32_ts to worldmodel.def - uint16_t mUnknown5; //12 00 ? - uint32_t mObjectID; -}; - -struct PSec2ElemType3b { //this part is optional - float mBoxLowerY; //Bounding box, for useflag "64 - selfconstructing colisionbox" - float mBoxLowerZ; // int32_t32_t or uint32_t32_t ? - float mBoxLowerX; - float mBoxUpperY; - float mBoxUpperZ; - float mBoxUpperX; -}; - -struct PSec2ElemType5Start { //door - uint16_t mUnknown1; //18 00 - uint16_t mUnknown1bis; //00 00 ? varies - float mPosY; - float mPosZ; - float mPosX; - uint8_t mActorStringSize; //string size with ending 0 - uint8_t mParamStringSize; //string size with ending 0 - uint16_t mUnknown5; //00 00 ? second byte varies - uint16_t mDoorID; // but what is the link with ObjectID sent in Use message (can't find the base offset .. or 0x80 for doors ???) - uint16_t mWorldmodelID; //door type from worldmodel.def -}; -//Actor As String //null terminated string -//Params As String //null terminated string - for DDOOR, 2nd param is the ID of the other (half)door (*) -//param1 = 2 => simple lateral move ?, 3 => door frontal+lateral move (as at Typherra memorial) ? -//last param = 0/1 for lateral move direction ? no ... -//(*) here is the bug(?) that makes open only one half of a double door - -/* -struct PSec2ElemType6Start //npc -{ - uint16_t mUnknown1; //20 00 ? - uint16_t mUnknown2; //12 00 ? - float mPosY; - float mPosZ; - float mPosX; - uint32_t mNPCTypeID; //npc type in npc.def - uint8_t mActorStringSize; //string size with ending 0 - uint8_t mParamStringSize; //string size with ending 0 - uint16_t mNpcID; // kind of ? - uint32_t mUnknown3; //01 00 00 00 ? - uint16_t mUnknown4; //00 00 ? - uint16_t mUnknown5; //04 00 ? -}; - //Actor As String //null terminated string - //Params As String //null terminated string - Seem to be the facing angle in degres -struct PSec2ElemType6End -{ - float mPosY2; //second position for movement ? - float mPosZ2; // - float mPosX2; // -}; -*/ -struct PSec2NPC_EntryPart1 { - uint32_t mUnknown1; // Is always 0x20001200, in every log. maybe header for NPCs? - float mPosY; - float mPosZ; - float mPosX; - uint32_t mNPCTypeID; //npc type in npc.def - uint8_t mActorStringSize; //string size with ending 0 - uint8_t mAngleStringSize; //string size with ending 0 - uint16_t mNpcID; - uint8_t mHasAdditionalCoords; - uint8_t mUnknown2a; - uint8_t mUnknown2b; - uint8_t mUnknown2c; - uint16_t mTradeID; //mUnknown3; //00 00 ? - uint16_t mUnknown4; //04 00 ? -}; - -// uint32_t8_t mActorName[mActorStringSize]; -// uint32_t8_t mAngle[mAngleStringSize]; - -struct PSec2NPC_EntryPart2 { // Waypoint32_ts! or something like that... - float mPosY; - float mPosZ; - float mPosX; -}; - -// uint32_t16_t mStrSize; //non-zero terminated string size -// Name As String //non-zero terminated string -struct PSec2ElemType15End { //area definition/sound ? - float mUnknown1; - float mUnknown2; - float mUnknown3; - float mUnknown4; - float mUnknown5; -}; +#pragma once + +#include + +struct PWorldFileHeader { + uint32_t mHeaderSize; // must be 08 00 00 00, = header size after this field + uint32_t mHeaderSig; // must be CF CF 0F 00 + uint32_t mSection; // must be 01 00 00 00 +}; + +struct PSectionHeader { + uint32_t mHeaderSize; // must be 0C 00 00 00 + uint32_t mHeaderSig; // must be CF FF 00 00 + uint32_t mSection; // 00 00 00 00 means end + uint32_t mDataSize; +}; + +struct PSec2ElemHeader { + uint32_t mHeaderSize; // must be 0C 00 00 00 + uint32_t mHeaderSig; // must be F1 FE FE 0F + uint32_t mElementType; // 1000003, 1000005 or 1000014 + uint32_t mDataSize; +}; + +struct PSec2ElemType3a { //static object ? + float mPosY; //= uint32_t16_t PosY - 32000 + float mPosZ; + float mPosX; + float mRotY; + float mRotZ; + float mRotX; + float mScale; //00 00 80 3F ? = float(1.000000) !!! => scale factor ????? + uint32_t mUnknown2; //01 00 00 00 ? + uint16_t mModelID; // point32_ts to models.ini + uint32_t mUnknown3; //00 00 00 00 ? + uint32_t mUnknown4; //00 00 00 00 ? + uint16_t mWorldmodelID; // point32_ts to worldmodel.def + uint16_t mUnknown5; //12 00 ? + uint32_t mObjectID; +}; + +struct PSec2ElemType3b { //this part is optional + float mBoxLowerY; //Bounding box, for useflag "64 - selfconstructing colisionbox" + float mBoxLowerZ; // int32_t32_t or uint32_t32_t ? + float mBoxLowerX; + float mBoxUpperY; + float mBoxUpperZ; + float mBoxUpperX; +}; + +struct PSec2ElemType5Start { //door + uint16_t mUnknown1; //18 00 + uint16_t mUnknown1bis; //00 00 ? varies + float mPosY; + float mPosZ; + float mPosX; + uint8_t mActorStringSize; //string size with ending 0 + uint8_t mParamStringSize; //string size with ending 0 + uint16_t mUnknown5; //00 00 ? second byte varies + uint16_t mDoorID; // but what is the link with ObjectID sent in Use message (can't find the base offset .. or 0x80 for doors ???) + uint16_t mWorldmodelID; //door type from worldmodel.def +}; +//Actor As String //null terminated string +//Params As String //null terminated string - for DDOOR, 2nd param is the ID of the other (half)door (*) +//param1 = 2 => simple lateral move ?, 3 => door frontal+lateral move (as at Typherra memorial) ? +//last param = 0/1 for lateral move direction ? no ... +//(*) here is the bug(?) that makes open only one half of a double door + +/* +struct PSec2ElemType6Start //npc +{ + uint16_t mUnknown1; //20 00 ? + uint16_t mUnknown2; //12 00 ? + float mPosY; + float mPosZ; + float mPosX; + uint32_t mNPCTypeID; //npc type in npc.def + uint8_t mActorStringSize; //string size with ending 0 + uint8_t mParamStringSize; //string size with ending 0 + uint16_t mNpcID; // kind of ? + uint32_t mUnknown3; //01 00 00 00 ? + uint16_t mUnknown4; //00 00 ? + uint16_t mUnknown5; //04 00 ? +}; + //Actor As String //null terminated string + //Params As String //null terminated string - Seem to be the facing angle in degres +struct PSec2ElemType6End +{ + float mPosY2; //second position for movement ? + float mPosZ2; // + float mPosX2; // +}; +*/ +struct PSec2NPC_EntryPart1 { + uint32_t mUnknown1; // Is always 0x20001200, in every log. maybe header for NPCs? + float mPosY; + float mPosZ; + float mPosX; + uint32_t mNPCTypeID; //npc type in npc.def + uint8_t mActorStringSize; //string size with ending 0 + uint8_t mAngleStringSize; //string size with ending 0 + uint16_t mNpcID; + uint8_t mHasAdditionalCoords; + uint8_t mUnknown2a; + uint8_t mUnknown2b; + uint8_t mUnknown2c; + uint16_t mTradeID; //mUnknown3; //00 00 ? + uint16_t mUnknown4; //04 00 ? +}; + +// uint32_t8_t mActorName[mActorStringSize]; +// uint32_t8_t mAngle[mAngleStringSize]; + +struct PSec2NPC_EntryPart2 { // Waypoint32_ts! or something like that... + float mPosY; + float mPosZ; + float mPosX; +}; + +// uint32_t16_t mStrSize; //non-zero terminated string size +// Name As String //non-zero terminated string +struct PSec2ElemType15End { //area definition/sound ? + float mUnknown1; + float mUnknown2; + float mUnknown3; + float mUnknown4; + float mUnknown5; +}; diff --git a/TinNS/Source/GameServer/Definitions/WorldFile.cxx b/TinNS/Source/GameServer/Definitions/WorldFile.cxx index 66e1762..18bb141 100644 --- a/TinNS/Source/GameServer/Definitions/WorldFile.cxx +++ b/TinNS/Source/GameServer/Definitions/WorldFile.cxx @@ -1,132 +1,132 @@ -#include "GameServer/Definitions/Includes.hxx" -#include "GameServer/Includes.hxx" - -/* - NOTA: Some entries in worlds.ini share the same Id ... - e.g: 505: techtown_enter 1/1a/1b/2 - As we don't know what it means & how it is supposed to be handled, - we keep the first one for the moment. (this is managed in gamedef.cpp) - TODO: Add a config entry to select the Nth entry for each such case, - as well as a config entry to select the default entry to be kept (first/last) -*/ - -PDefWorldFile::PDefWorldFile() -{ - mFileInWorldsDir = false; -} - -bool PDefWorldFile::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - int StartPos = 0; - int TailLen = 0; - int Len; - - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0: // setentry - continue; - - case 1: // index - mIndex = atoi(i->c_str()); break; - - case 2: // name - { - Len = (*i).length(); - - while((StartPos = (*i).find("\\",StartPos))>-1) - (*i)[StartPos]='/'; - StartPos = 0; - - if ((*i)[0] == '\"') - StartPos = 1; - - if ( (*i).substr(StartPos,9) == "./worlds/" ) - { - mFileInWorldsDir = true; - StartPos += 9; - } - else if ( (*i).substr(StartPos,2) == "./" ) - StartPos += 2; - - if ((*i)[Len-1] == '\"') - TailLen = 1; - if ( (Len > (StartPos+TailLen+4)) && ((*i)[Len-TailLen-4] == '.') ) - TailLen += 4; - - mName = (*i).substr(StartPos,Len-StartPos-TailLen); // remove prefix, extension and doublequotes - - break; - } - } - } - - return (Idx == 3); -} - -// class PDefWorldFileMap defined in gamedefs.h -bool PDefWorldFilesMap::Load(const char* nName, const char* nFilename) -{ - mName = nName; - if(mName.empty()) - { - Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) ); - return (false); - } - - if(! *nFilename) - { - Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() ); - return (false); - } - - PDefParser parser; - int nDefs = 0, nErrors = 0, nDup = 0; - - if ( parser.Parse( nFilename ) ) - { - const PDefTokenList &t = parser.GetTokens(); - - for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ ) - { - PDefWorldFile *it = new PDefWorldFile(); - bool loadfail = !it->LoadFromDef( *i ), insertfail = false; - - if ( !loadfail ) - insertfail = !mDefs.insert( std::make_pair( it->GetIndex(), it ) ).second; - if ( loadfail || insertfail ) - { - if ( insertfail ) - { - ++nDup; - if ( gDevDebug ) Console->Print( "%s ini error (new duplicate id %i discarded)", mName.c_str(), it->GetIndex(), it->GetName().c_str() ); - } - else - { - Console->Print( "%s ini load error @ %i", mName.c_str(), nDefs + nErrors ); - ++nErrors; - } - delete it; - } - else - ++nDefs; - } - } - else - { - Console->Print( "%s Error loading %s ini defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() ); - return ( false ); - } - - if ( nErrors > 0 ) - Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( RED, BLACK, "[ERROR]" ), nDefs, mName.c_str(), nErrors ); - else - Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs, mName.c_str(), nErrors ); - - if ( nDup ) - Console->Print( "%s %d duplicate entries ignored in %s ini defs.", Console->ColorText( YELLOW, BLACK, "[Notice]" ), nDup, mName.c_str() ); - - return ( true ); -} +#include "GameServer/Definitions/Includes.hxx" +#include "GameServer/Includes.hxx" + +/* + NOTA: Some entries in worlds.ini share the same Id ... + e.g: 505: techtown_enter 1/1a/1b/2 + As we don't know what it means & how it is supposed to be handled, + we keep the first one for the moment. (this is managed in gamedef.cpp) + TODO: Add a config entry to select the Nth entry for each such case, + as well as a config entry to select the default entry to be kept (first/last) +*/ + +PDefWorldFile::PDefWorldFile() +{ + mFileInWorldsDir = false; +} + +bool PDefWorldFile::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + int StartPos = 0; + int TailLen = 0; + int Len; + + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0: // setentry + continue; + + case 1: // index + mIndex = atoi(i->c_str()); break; + + case 2: // name + { + Len = (*i).length(); + + while((StartPos = (*i).find("\\",StartPos))>-1) + (*i)[StartPos]='/'; + StartPos = 0; + + if ((*i)[0] == '\"') + StartPos = 1; + + if ( (*i).substr(StartPos,9) == "./worlds/" ) + { + mFileInWorldsDir = true; + StartPos += 9; + } + else if ( (*i).substr(StartPos,2) == "./" ) + StartPos += 2; + + if ((*i)[Len-1] == '\"') + TailLen = 1; + if ( (Len > (StartPos+TailLen+4)) && ((*i)[Len-TailLen-4] == '.') ) + TailLen += 4; + + mName = (*i).substr(StartPos,Len-StartPos-TailLen); // remove prefix, extension and doublequotes + + break; + } + } + } + + return (Idx == 3); +} + +// class PDefWorldFileMap defined in gamedefs.h +bool PDefWorldFilesMap::Load(const char* nName, const char* nFilename) +{ + mName = nName; + if(mName.empty()) + { + Console->Print( "%s Defs name not defined", Console->ColorText( RED, BLACK, "[ERROR]" ) ); + return (false); + } + + if(! *nFilename) + { + Console->Print( "%s Filename not defined for %s defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() ); + return (false); + } + + PDefParser parser; + int nDefs = 0, nErrors = 0, nDup = 0; + + if ( parser.Parse( nFilename ) ) + { + const PDefTokenList &t = parser.GetTokens(); + + for ( PDefTokenList::const_iterator i = t.begin(); i != t.end(); i++ ) + { + PDefWorldFile *it = new PDefWorldFile(); + bool loadfail = !it->LoadFromDef( *i ), insertfail = false; + + if ( !loadfail ) + insertfail = !mDefs.insert( std::make_pair( it->GetIndex(), it ) ).second; + if ( loadfail || insertfail ) + { + if ( insertfail ) + { + ++nDup; + if ( gDevDebug ) Console->Print( "%s ini error (new duplicate id %i discarded)", mName.c_str(), it->GetIndex(), it->GetName().c_str() ); + } + else + { + Console->Print( "%s ini load error @ %i", mName.c_str(), nDefs + nErrors ); + ++nErrors; + } + delete it; + } + else + ++nDefs; + } + } + else + { + Console->Print( "%s Error loading %s ini defs", Console->ColorText( RED, BLACK, "[ERROR]" ), mName.c_str() ); + return ( false ); + } + + if ( nErrors > 0 ) + Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( RED, BLACK, "[ERROR]" ), nDefs, mName.c_str(), nErrors ); + else + Console->Print( "%s Loaded %i %s ini defs, %i error(s).", Console->ColorText( GREEN, BLACK, "[Success]" ), nDefs, mName.c_str(), nErrors ); + + if ( nDup ) + Console->Print( "%s %d duplicate entries ignored in %s ini defs.", Console->ColorText( YELLOW, BLACK, "[Notice]" ), nDup, mName.c_str() ); + + return ( true ); +} diff --git a/TinNS/Source/GameServer/Definitions/WorldFile.hxx b/TinNS/Source/GameServer/Definitions/WorldFile.hxx index ea2c788..4c05954 100644 --- a/TinNS/Source/GameServer/Definitions/WorldFile.hxx +++ b/TinNS/Source/GameServer/Definitions/WorldFile.hxx @@ -1,30 +1,30 @@ -#pragma once - -#include -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefWorldFile : public PDef { -private: - //int32_t mIndex; - std::string mName; // dat filename with ending extension and starting ./ or ./worlds/ REMOVED - bool mFileInWorldsDir; // TRUE if worlds/ must be appendend before mName to get real file name (dat file at least) - -public: - PDefWorldFile(); - //~PDefWorldFile(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline const std::string GetBasicFileName() const { return (mFileInWorldsDir ? (std::string("worlds/") + mName) : mName); }; -}; - - -class PDefWorldFilesMap : public PDefMap { -public: - bool Load(const char* nName, const char* nFilename); - inline std::map::const_iterator ConstIteratorBegin() const { return mDefs.begin(); } - inline std::map::const_iterator ConstIteratorEnd() const { return mDefs.end(); } -}; +#pragma once + +#include +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefWorldFile : public PDef { +private: + //int32_t mIndex; + std::string mName; // dat filename with ending extension and starting ./ or ./worlds/ REMOVED + bool mFileInWorldsDir; // TRUE if worlds/ must be appendend before mName to get real file name (dat file at least) + +public: + PDefWorldFile(); + //~PDefWorldFile(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline const std::string GetBasicFileName() const { return (mFileInWorldsDir ? (std::string("worlds/") + mName) : mName); }; +}; + + +class PDefWorldFilesMap : public PDefMap { +public: + bool Load(const char* nName, const char* nFilename); + inline std::map::const_iterator ConstIteratorBegin() const { return mDefs.begin(); } + inline std::map::const_iterator ConstIteratorEnd() const { return mDefs.end(); } +}; diff --git a/TinNS/Source/GameServer/Definitions/WorldModels.cxx b/TinNS/Source/GameServer/Definitions/WorldModels.cxx index 68a3c7f..15aeb72 100644 --- a/TinNS/Source/GameServer/Definitions/WorldModels.cxx +++ b/TinNS/Source/GameServer/Definitions/WorldModels.cxx @@ -1,41 +1,41 @@ -#include "GameServer/Definitions/Includes.hxx" - -PDefWorldModel::PDefWorldModel() -{ -} - -bool PDefWorldModel::LoadFromDef(PTokenList *Tokens) -{ - int Idx=0; - for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) - { - switch(Idx) - { - case 0: // setentry - continue; - - case 1: // index - mIndex = atoi(i->c_str()); break; - - case 2: // name - mName = *i; break; - - case 3: // use flag - mUseFlags = atoi(i->c_str()); break; - - case 4: // function type - mFunctionType = atoi(i->c_str()); break; - - case 5: // function value - mFunctionValue = atoi(i->c_str()); break; - - case 6: // hack difficulty - mHackDifficulty = atoi(i->c_str()); break; - - case 7: // hack penalty - mHackPenalty = atoi(i->c_str()); break; - } - } - - return true; -} +#include "GameServer/Definitions/Includes.hxx" + +PDefWorldModel::PDefWorldModel() +{ +} + +bool PDefWorldModel::LoadFromDef(PTokenList *Tokens) +{ + int Idx=0; + for(PTokenList::iterator i=Tokens->begin(); i!=Tokens->end(); i++, Idx++) + { + switch(Idx) + { + case 0: // setentry + continue; + + case 1: // index + mIndex = atoi(i->c_str()); break; + + case 2: // name + mName = *i; break; + + case 3: // use flag + mUseFlags = atoi(i->c_str()); break; + + case 4: // function type + mFunctionType = atoi(i->c_str()); break; + + case 5: // function value + mFunctionValue = atoi(i->c_str()); break; + + case 6: // hack difficulty + mHackDifficulty = atoi(i->c_str()); break; + + case 7: // hack penalty + mHackPenalty = atoi(i->c_str()); break; + } + } + + return true; +} diff --git a/TinNS/Source/GameServer/Definitions/WorldModels.hxx b/TinNS/Source/GameServer/Definitions/WorldModels.hxx index 11cb111..2b500e8 100644 --- a/TinNS/Source/GameServer/Definitions/WorldModels.hxx +++ b/TinNS/Source/GameServer/Definitions/WorldModels.hxx @@ -1,30 +1,30 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefWorldModel : public PDef { -private: - //int32_t mIndex; - std::string mName; - int32_t mUseFlags; - int32_t mFunctionType; - int32_t mFunctionValue; - int32_t mHackDifficulty; - int32_t mHackPenalty; - -public: - PDefWorldModel(); - //~PDefWorldModel(); - - bool LoadFromDef(PTokenList *Tokens); - - inline int32_t GetID() const { return mIndex; } - inline const std::string &GetName() const { return mName; } - inline int32_t GetUseFlags() const { return mUseFlags; } - inline int32_t GetFunctionType() const { return mFunctionType; } - inline int32_t GetFunctionValue() const { return mFunctionValue; } - inline int32_t GetHackDifficulty() const { return mHackDifficulty; } - inline int32_t GetHackPenalty() const { return mHackPenalty; } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefWorldModel : public PDef { +private: + //int32_t mIndex; + std::string mName; + int32_t mUseFlags; + int32_t mFunctionType; + int32_t mFunctionValue; + int32_t mHackDifficulty; + int32_t mHackPenalty; + +public: + PDefWorldModel(); + //~PDefWorldModel(); + + bool LoadFromDef(PTokenList *Tokens); + + inline int32_t GetID() const { return mIndex; } + inline const std::string &GetName() const { return mName; } + inline int32_t GetUseFlags() const { return mUseFlags; } + inline int32_t GetFunctionType() const { return mFunctionType; } + inline int32_t GetFunctionValue() const { return mFunctionValue; } + inline int32_t GetHackDifficulty() const { return mHackDifficulty; } + inline int32_t GetHackPenalty() const { return mHackPenalty; } +}; diff --git a/TinNS/Source/GameServer/Definitions/Worlds.cxx b/TinNS/Source/GameServer/Definitions/Worlds.cxx index fdb13eb..84c3342 100644 --- a/TinNS/Source/GameServer/Definitions/Worlds.cxx +++ b/TinNS/Source/GameServer/Definitions/Worlds.cxx @@ -1,88 +1,88 @@ -#include "GameServer/Definitions/Includes.hxx" - -PDefWorld::PDefWorld() -{ -} - -bool PDefWorld::LoadFromDef( PTokenList *Tokens ) -{ - int Idx = 0; - int StartPos = 0; - int TailLen = 0; - int Len; - - for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ ) - { - switch ( Idx ) - { - case 0: // setentry - continue; - case 3: // music - continue; - - case 1: // index - mIndex = atoi( i->c_str() ); break; - - case 2: // name - { - Len = ( *i ).length(); - - if (( *i )[0] == '\"' ) - StartPos = 1; - - while (( *i )[StartPos] == ' ' ) - ++StartPos; - - if (( *i )[Len-1] == '\"' ) - TailLen = 1; - - while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) ) - ++TailLen; - - if ( StartPos >= Len - TailLen ) - mName = ""; - else - mName = ( *i ).substr( StartPos, Len - StartPos - TailLen ); - - break; - } - - case 4: // datfile - { - Len = ( *i ).length(); - - while (( StartPos = ( *i ).find( "\\", StartPos ) ) > -1 ) - ( *i )[StartPos] = '/'; - StartPos = 0; - - if (( *i )[0] == '\"' ) - StartPos = 1; - - while (( *i )[StartPos] == ' ' ) - ++StartPos; - - if (( StartPos <= Len - 2 ) && (( *i ).substr( StartPos, 2 ) == "./" ) ) - StartPos += 2; - - if (( *i )[Len-1] == '\"' ) - TailLen = 1; - - while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) ) - ++TailLen; - - if ( StartPos >= Len - TailLen ) - mDatFile = ""; - else - mDatFile = ( *i ).substr( StartPos, Len - StartPos - TailLen ); - - break; - } - - case 5: - mFlags = atoi( i->c_str() ); break; - } - } - - return true; -} - +#include "GameServer/Definitions/Includes.hxx" + +PDefWorld::PDefWorld() +{ +} + +bool PDefWorld::LoadFromDef( PTokenList *Tokens ) +{ + int Idx = 0; + int StartPos = 0; + int TailLen = 0; + int Len; + + for ( PTokenList::iterator i = Tokens->begin(); i != Tokens->end(); i++, Idx++ ) + { + switch ( Idx ) + { + case 0: // setentry + continue; + case 3: // music + continue; + + case 1: // index + mIndex = atoi( i->c_str() ); break; + + case 2: // name + { + Len = ( *i ).length(); + + if (( *i )[0] == '\"' ) + StartPos = 1; + + while (( *i )[StartPos] == ' ' ) + ++StartPos; + + if (( *i )[Len-1] == '\"' ) + TailLen = 1; + + while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) ) + ++TailLen; + + if ( StartPos >= Len - TailLen ) + mName = ""; + else + mName = ( *i ).substr( StartPos, Len - StartPos - TailLen ); + + break; + } + + case 4: // datfile + { + Len = ( *i ).length(); + + while (( StartPos = ( *i ).find( "\\", StartPos ) ) > -1 ) + ( *i )[StartPos] = '/'; + StartPos = 0; + + if (( *i )[0] == '\"' ) + StartPos = 1; + + while (( *i )[StartPos] == ' ' ) + ++StartPos; + + if (( StartPos <= Len - 2 ) && (( *i ).substr( StartPos, 2 ) == "./" ) ) + StartPos += 2; + + if (( *i )[Len-1] == '\"' ) + TailLen = 1; + + while (( Len - TailLen > 0 ) && (( *i )[Len-TailLen-1] == ' ' ) ) + ++TailLen; + + if ( StartPos >= Len - TailLen ) + mDatFile = ""; + else + mDatFile = ( *i ).substr( StartPos, Len - StartPos - TailLen ); + + break; + } + + case 5: + mFlags = atoi( i->c_str() ); break; + } + } + + return true; +} + diff --git a/TinNS/Source/GameServer/Definitions/Worlds.hxx b/TinNS/Source/GameServer/Definitions/Worlds.hxx index 9129479..3d4eff3 100644 --- a/TinNS/Source/GameServer/Definitions/Worlds.hxx +++ b/TinNS/Source/GameServer/Definitions/Worlds.hxx @@ -1,23 +1,23 @@ -#pragma once - -#include -#include -#include "GameServer/Definitions/Definition.hxx" - -class PDefWorld : public PDef { -private: - //int32_t mIndex; - std::string mName; - std::string mDatFile; - int32_t mFlags; - -public: - PDefWorld(); - //~PDefWorld(); - - bool LoadFromDef(PTokenList *Tokens); - - inline const std::string &GetName() const { return mName; } - inline const std::string &GetDatFile() const { return mDatFile; } - inline int32_t GetFlags() const { return mFlags; } -}; +#pragma once + +#include +#include +#include "GameServer/Definitions/Definition.hxx" + +class PDefWorld : public PDef { +private: + //int32_t mIndex; + std::string mName; + std::string mDatFile; + int32_t mFlags; + +public: + PDefWorld(); + //~PDefWorld(); + + bool LoadFromDef(PTokenList *Tokens); + + inline const std::string &GetName() const { return mName; } + inline const std::string &GetDatFile() const { return mDatFile; } + inline int32_t GetFlags() const { return mFlags; } +}; diff --git a/TinNS/Source/GameServer/DoorTemplate.cxx b/TinNS/Source/GameServer/DoorTemplate.cxx index 94aa485..43685e7 100644 --- a/TinNS/Source/GameServer/DoorTemplate.cxx +++ b/TinNS/Source/GameServer/DoorTemplate.cxx @@ -1,116 +1,116 @@ -#include -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" - -// TODO: - mem corruption occurs if mDoorParameters[] is given a size of 6, and that 6 max param can be accepted -// This bug occurs in world 105. Reason not found yet :-x - -const std::string EmptyString; - -PDoorTemplate::PDoorTemplate() -{ - mDoorID = 0; - mWorldmodelID = 0; - mDefWorldModel = NULL; - mIsDoubleDoor = false; - mIsTriggeredDoor = false; -} - -PDoorTemplate::~PDoorTemplate() -{ -} - -uint16_t PDoorTemplate::GetID() -{ - return mDoorID; -} - -uint16_t PDoorTemplate::GetUseFlags() -{ - return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0); -} - -uint16_t PDoorTemplate::GetFunctionType() -{ - return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0); -} - -int PDoorTemplate::GetFunctionValue() -{ - return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0); -} - -const std::string& PDoorTemplate::GetName() const -{ - return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString ); -} - -const PDefWorldModel *PDoorTemplate::GetDefWorldModel() const -{ - return mDefWorldModel; -} - -void PDoorTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const -{ - *nPosY = mPosY; - *nPosZ = mPosZ; - *nPosX = mPosX; -} - -uint16_t PDoorTemplate::GetOtherDoorID() -{ - return (mIsDoubleDoor ? mDoorParameters[1] : 0); -} - -bool PDoorTemplate::IsDoubleDoor() const -{ - return mIsDoubleDoor; -} - -bool PDoorTemplate::IsTriggeredDoor() const -{ - return mIsTriggeredDoor; -} - -void PDoorTemplate::SetDoorParameters(char* nDoorParametersString) -{ - char* SepPos; - int ParamNum = 0; -//Console->Print("door parameter: %s", nDoorParametersString); - while ( *nDoorParametersString && (SepPos = strchr(nDoorParametersString, ',')) && (ParamNum < 4)) - { - *SepPos = 0; - mDoorParameters[ParamNum++] = atoi(nDoorParametersString); - nDoorParametersString = SepPos + 1; - } - if (*nDoorParametersString) - { - if (ParamNum < 4) - mDoorParameters[ParamNum] = atoi(nDoorParametersString); - //else - // Console->Print(RED, BLACK, "[ERROR] More than 4 parameters in Sec2ElemType5 ParamString"); - } -} - -void PDoorTemplate::SetDoorTypeName(char* nDoorTypeName) -{ - mDoorTypeName = nDoorTypeName; - - if (mDoorTypeName == "DDOOR") - { - mIsDoubleDoor = true; - } - else if (mDoorTypeName == "TRIGDD") - { - mIsDoubleDoor = true; - mIsTriggeredDoor = true; - } - else if (mDoorTypeName == "TRIGDOOR") - { - mIsTriggeredDoor = true; - } - else if (mDoorTypeName == "NBUTTON") - { - mIsTriggeredDoor = false; - } -} +#include +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" + +// TODO: - mem corruption occurs if mDoorParameters[] is given a size of 6, and that 6 max param can be accepted +// This bug occurs in world 105. Reason not found yet :-x + +const std::string EmptyString; + +PDoorTemplate::PDoorTemplate() +{ + mDoorID = 0; + mWorldmodelID = 0; + mDefWorldModel = NULL; + mIsDoubleDoor = false; + mIsTriggeredDoor = false; +} + +PDoorTemplate::~PDoorTemplate() +{ +} + +uint16_t PDoorTemplate::GetID() +{ + return mDoorID; +} + +uint16_t PDoorTemplate::GetUseFlags() +{ + return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0); +} + +uint16_t PDoorTemplate::GetFunctionType() +{ + return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0); +} + +int PDoorTemplate::GetFunctionValue() +{ + return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0); +} + +const std::string& PDoorTemplate::GetName() const +{ + return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString ); +} + +const PDefWorldModel *PDoorTemplate::GetDefWorldModel() const +{ + return mDefWorldModel; +} + +void PDoorTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const +{ + *nPosY = mPosY; + *nPosZ = mPosZ; + *nPosX = mPosX; +} + +uint16_t PDoorTemplate::GetOtherDoorID() +{ + return (mIsDoubleDoor ? mDoorParameters[1] : 0); +} + +bool PDoorTemplate::IsDoubleDoor() const +{ + return mIsDoubleDoor; +} + +bool PDoorTemplate::IsTriggeredDoor() const +{ + return mIsTriggeredDoor; +} + +void PDoorTemplate::SetDoorParameters(char* nDoorParametersString) +{ + char* SepPos; + int ParamNum = 0; +//Console->Print("door parameter: %s", nDoorParametersString); + while ( *nDoorParametersString && (SepPos = strchr(nDoorParametersString, ',')) && (ParamNum < 4)) + { + *SepPos = 0; + mDoorParameters[ParamNum++] = atoi(nDoorParametersString); + nDoorParametersString = SepPos + 1; + } + if (*nDoorParametersString) + { + if (ParamNum < 4) + mDoorParameters[ParamNum] = atoi(nDoorParametersString); + //else + // Console->Print(RED, BLACK, "[ERROR] More than 4 parameters in Sec2ElemType5 ParamString"); + } +} + +void PDoorTemplate::SetDoorTypeName(char* nDoorTypeName) +{ + mDoorTypeName = nDoorTypeName; + + if (mDoorTypeName == "DDOOR") + { + mIsDoubleDoor = true; + } + else if (mDoorTypeName == "TRIGDD") + { + mIsDoubleDoor = true; + mIsTriggeredDoor = true; + } + else if (mDoorTypeName == "TRIGDOOR") + { + mIsTriggeredDoor = true; + } + else if (mDoorTypeName == "NBUTTON") + { + mIsTriggeredDoor = false; + } +} diff --git a/TinNS/Source/GameServer/DoorTemplate.hxx b/TinNS/Source/GameServer/DoorTemplate.hxx index e3bbd84..c406471 100644 --- a/TinNS/Source/GameServer/DoorTemplate.hxx +++ b/TinNS/Source/GameServer/DoorTemplate.hxx @@ -1,47 +1,47 @@ -#pragma once - -#include - -class PDefWorldModel; - -class PDoorTemplate { - friend class PWorldDatParser; - -private: - uint16_t mDoorID; - - // The commented out values are not loaded from dat file atm because they are not used yet. - //uint16_t mUnknown1; //18 00 - //uint16_t mUnknown1bis; //00 00 ? varies - float mPosY; - float mPosZ; - float mPosX; - //uint16_t mUnknown5; //00 00 ? second byte varies - uint16_t mWorldmodelID; //door type from worldmodel.def - - std::string mDoorTypeName; - int mDoorParameters[4]; - bool mIsDoubleDoor; - bool mIsTriggeredDoor; - - const PDefWorldModel* mDefWorldModel; - -public: - PDoorTemplate(); - ~PDoorTemplate(); - - uint16_t GetID(); - uint16_t GetUseFlags(); - uint16_t GetFunctionType(); - int GetFunctionValue(); - const std::string& GetName() const; /// !!!! - const PDefWorldModel *GetDefWorldModel() const; - - void GetPos(float *nPosX, float *nPosY, float *nPosZ) const; - uint16_t GetOtherDoorID(); - bool IsDoubleDoor() const; - bool IsTriggeredDoor() const; - - void SetDoorTypeName(char* nDoorTypeName); - void SetDoorParameters(char* nDoorParametersString); -}; +#pragma once + +#include + +class PDefWorldModel; + +class PDoorTemplate { + friend class PWorldDatParser; + +private: + uint16_t mDoorID; + + // The commented out values are not loaded from dat file atm because they are not used yet. + //uint16_t mUnknown1; //18 00 + //uint16_t mUnknown1bis; //00 00 ? varies + float mPosY; + float mPosZ; + float mPosX; + //uint16_t mUnknown5; //00 00 ? second byte varies + uint16_t mWorldmodelID; //door type from worldmodel.def + + std::string mDoorTypeName; + int mDoorParameters[4]; + bool mIsDoubleDoor; + bool mIsTriggeredDoor; + + const PDefWorldModel* mDefWorldModel; + +public: + PDoorTemplate(); + ~PDoorTemplate(); + + uint16_t GetID(); + uint16_t GetUseFlags(); + uint16_t GetFunctionType(); + int GetFunctionValue(); + const std::string& GetName() const; /// !!!! + const PDefWorldModel *GetDefWorldModel() const; + + void GetPos(float *nPosX, float *nPosY, float *nPosZ) const; + uint16_t GetOtherDoorID(); + bool IsDoubleDoor() const; + bool IsTriggeredDoor() const; + + void SetDoorTypeName(char* nDoorTypeName); + void SetDoorParameters(char* nDoorParametersString); +}; diff --git a/TinNS/Source/GameServer/FurnitureTemplate.cxx b/TinNS/Source/GameServer/FurnitureTemplate.cxx index bc29b37..3d1e974 100644 --- a/TinNS/Source/GameServer/FurnitureTemplate.cxx +++ b/TinNS/Source/GameServer/FurnitureTemplate.cxx @@ -1,76 +1,76 @@ -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" - -const std::string EmptyString; - -PFurnitureItemTemplate::PFurnitureItemTemplate() -{ - mObjectID = 0; - mModelID = 0; - mWorldmodelID = 0; - mDefWorldModel = NULL; - mLinkedObjectID = 0; -} - -PFurnitureItemTemplate::~PFurnitureItemTemplate() -{ -} - -uint32_t PFurnitureItemTemplate::GetID() const -{ - return mObjectID; -} - -uint16_t PFurnitureItemTemplate::GetUseFlags() const -{ - return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0); -} - -uint16_t PFurnitureItemTemplate::GetFunctionType() const -{ - return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0); -} - -int PFurnitureItemTemplate::GetFunctionValue() const -{ - return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0); -} - -const std::string &PFurnitureItemTemplate::GetName() const -{ - return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString); -} - -const PDefWorldModel *PFurnitureItemTemplate::GetDefWorldModel() const -{ - return mDefWorldModel; -} - -uint8_t PFurnitureItemTemplate::GetFrontLR() const -{ - return mFrontLR; -} - -void PFurnitureItemTemplate::GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const -{ - *nFrontPosY = mFrontPosY; - *nFrontPosZ = mFrontPosZ; - *nFrontPosX = mFrontPosX; -} - -void PFurnitureItemTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const -{ - *nPosY = mPosY; - *nPosZ = mPosZ; - *nPosX = mPosX; -} - -void PFurnitureItemTemplate::SetLinkedObjectID(uint32_t nID) -{ - mLinkedObjectID = nID; -} - -uint32_t PFurnitureItemTemplate::GetLinkedObjectID() const -{ - return mLinkedObjectID; -} +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" + +const std::string EmptyString; + +PFurnitureItemTemplate::PFurnitureItemTemplate() +{ + mObjectID = 0; + mModelID = 0; + mWorldmodelID = 0; + mDefWorldModel = NULL; + mLinkedObjectID = 0; +} + +PFurnitureItemTemplate::~PFurnitureItemTemplate() +{ +} + +uint32_t PFurnitureItemTemplate::GetID() const +{ + return mObjectID; +} + +uint16_t PFurnitureItemTemplate::GetUseFlags() const +{ + return (mDefWorldModel ? mDefWorldModel->GetUseFlags() : 0); +} + +uint16_t PFurnitureItemTemplate::GetFunctionType() const +{ + return (mDefWorldModel ? mDefWorldModel->GetFunctionType() : 0); +} + +int PFurnitureItemTemplate::GetFunctionValue() const +{ + return (mDefWorldModel ? mDefWorldModel->GetFunctionValue() : 0); +} + +const std::string &PFurnitureItemTemplate::GetName() const +{ + return (mDefWorldModel ? mDefWorldModel->GetName() : EmptyString); +} + +const PDefWorldModel *PFurnitureItemTemplate::GetDefWorldModel() const +{ + return mDefWorldModel; +} + +uint8_t PFurnitureItemTemplate::GetFrontLR() const +{ + return mFrontLR; +} + +void PFurnitureItemTemplate::GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const +{ + *nFrontPosY = mFrontPosY; + *nFrontPosZ = mFrontPosZ; + *nFrontPosX = mFrontPosX; +} + +void PFurnitureItemTemplate::GetPos(float *nPosX, float *nPosY, float *nPosZ) const +{ + *nPosY = mPosY; + *nPosZ = mPosZ; + *nPosX = mPosX; +} + +void PFurnitureItemTemplate::SetLinkedObjectID(uint32_t nID) +{ + mLinkedObjectID = nID; +} + +uint32_t PFurnitureItemTemplate::GetLinkedObjectID() const +{ + return mLinkedObjectID; +} diff --git a/TinNS/Source/GameServer/FurnitureTemplate.hxx b/TinNS/Source/GameServer/FurnitureTemplate.hxx index 1e1abbb..35b3429 100644 --- a/TinNS/Source/GameServer/FurnitureTemplate.hxx +++ b/TinNS/Source/GameServer/FurnitureTemplate.hxx @@ -1,111 +1,111 @@ -#pragma once - -#include -#include - -class PDefWorldModel; - -enum { // Furniture Use flags (cumlative) - ufTouchable = 1, - ufUsable = 2, - ufNoCollision = 4, - ufChair = 8, - ufToolTarget = 16, - ufSelfCollisionBox = 64, - ufGraphicalEffect = 128, - ufNoSelectionBox = 256 -}; - -class PFurnitureItemTemplate { - friend class PWorldDatParser; - -private: - uint32_t mObjectID; - - // The commented out values are not loaded from dat file atm because they are not used yet. - float mPosY; //= mPosY from dat file + 32000, to be coherent with char Pos scale - float mPosZ; - float mPosX; - //float mRotY; - float mRotZ; - //float mRotX; - //uint32_t mScale; //00 00 80 3F ? = float(1.0000) scale factor ? // mostly used by holoscreens (passiv object) - //uint32_t mUnknown2; //01 00 00 00 ? - uint16_t mModelID; // points to models.ini - //uint32_t mUnknown3; //00 00 00 00 ? - //uint32_t mUnknown4; //00 00 00 00 ? - uint16_t mWorldmodelID; // points to worldmodel.def - //uint16_t mUnknown5; //12 00 ? // changes sometime (ex: c288 ...) - - //float mBoxLowerY; //Bounding box, for use when ufSelfCollisionBox is set in mUseFlags. - //float mBoxLowerZ; - //float mBoxLowerX; - //float mBoxUpperY; - //float mBoxUpperZ; - //float mBoxUpperX; - - uint16_t mFrontPosY; - uint16_t mFrontPosZ; - uint16_t mFrontPosX; - uint8_t mFrontLR; - - const PDefWorldModel* mDefWorldModel; - - uint32_t mLinkedObjectID; // for buttons, stores the corresponding triggered door - // fo GR, stores order of the GR entity (spawn point) to later choose from respawn.def data - - public: - PFurnitureItemTemplate(); - ~PFurnitureItemTemplate(); - - uint32_t GetID() const; - uint16_t GetUseFlags() const; - uint16_t GetFunctionType() const; - int GetFunctionValue() const; - const std::string &GetName() const; /// !!!! - const PDefWorldModel *GetDefWorldModel() const; - uint8_t GetFrontLR() const; - void GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const; - void GetPos(float *nPosX, float *nPosY, float *nPosZ) const; - - void SetLinkedObjectID(uint32_t nID); - uint32_t GetLinkedObjectID() const; -}; - -// *** from worldmodel.def *** - -//function Type -// 0 - none -// 1 - Itemcontainer -// 2 - Terminal -// 3 - Outfitter -// 4 - Trader -// 5 - Mineral -// 6 - Respawn Station -// 7 - GoGuardian -// 8 - Hackterminal -// 9 - Appartement Eingang -// 10 - Appartement Ein/Ausgang -// 11 - Appartement Klingel/�ffner -// 12 - Standard Button -// 13 - Hack Button -// 14 - HOLOMATCH ENTRANCE -// 15 - HOLOMATCH EXIT -// 16 - HOLOMATCH REFRESH -// 17 - HOLOMATCH HEAL -// 18 - WORLDCHANGEACTOR -// 19 - CLANTERMINAL -// 20 - DATFILE WORLDCHANGE ACTOR -// 21 - LOCATION FOR 20 -// 22 - -// 23 - EINTRITTSGELD BUTTON -// 24- TUTORIALEXIT -// 25 - EXPLOSIVE -// 26 - Outpost Switch -// 27 - Old goguardian -// 28 - Fahrzeug Depot Interface -// 29 - Underground Exit -// 30 - Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle) -// 31 - Venture Warp Station -// 32 - functionvalue+100 gibt eine Meldung aus der Text.ini [MISC] an. -// +#pragma once + +#include +#include + +class PDefWorldModel; + +enum { // Furniture Use flags (cumlative) + ufTouchable = 1, + ufUsable = 2, + ufNoCollision = 4, + ufChair = 8, + ufToolTarget = 16, + ufSelfCollisionBox = 64, + ufGraphicalEffect = 128, + ufNoSelectionBox = 256 +}; + +class PFurnitureItemTemplate { + friend class PWorldDatParser; + +private: + uint32_t mObjectID; + + // The commented out values are not loaded from dat file atm because they are not used yet. + float mPosY; //= mPosY from dat file + 32000, to be coherent with char Pos scale + float mPosZ; + float mPosX; + //float mRotY; + float mRotZ; + //float mRotX; + //uint32_t mScale; //00 00 80 3F ? = float(1.0000) scale factor ? // mostly used by holoscreens (passiv object) + //uint32_t mUnknown2; //01 00 00 00 ? + uint16_t mModelID; // points to models.ini + //uint32_t mUnknown3; //00 00 00 00 ? + //uint32_t mUnknown4; //00 00 00 00 ? + uint16_t mWorldmodelID; // points to worldmodel.def + //uint16_t mUnknown5; //12 00 ? // changes sometime (ex: c288 ...) + + //float mBoxLowerY; //Bounding box, for use when ufSelfCollisionBox is set in mUseFlags. + //float mBoxLowerZ; + //float mBoxLowerX; + //float mBoxUpperY; + //float mBoxUpperZ; + //float mBoxUpperX; + + uint16_t mFrontPosY; + uint16_t mFrontPosZ; + uint16_t mFrontPosX; + uint8_t mFrontLR; + + const PDefWorldModel* mDefWorldModel; + + uint32_t mLinkedObjectID; // for buttons, stores the corresponding triggered door + // fo GR, stores order of the GR entity (spawn point) to later choose from respawn.def data + + public: + PFurnitureItemTemplate(); + ~PFurnitureItemTemplate(); + + uint32_t GetID() const; + uint16_t GetUseFlags() const; + uint16_t GetFunctionType() const; + int GetFunctionValue() const; + const std::string &GetName() const; /// !!!! + const PDefWorldModel *GetDefWorldModel() const; + uint8_t GetFrontLR() const; + void GetFrontPos(uint16_t *nFrontPosX, uint16_t *nFrontPosY, uint16_t *nFrontPosZ) const; + void GetPos(float *nPosX, float *nPosY, float *nPosZ) const; + + void SetLinkedObjectID(uint32_t nID); + uint32_t GetLinkedObjectID() const; +}; + +// *** from worldmodel.def *** + +//function Type +// 0 - none +// 1 - Itemcontainer +// 2 - Terminal +// 3 - Outfitter +// 4 - Trader +// 5 - Mineral +// 6 - Respawn Station +// 7 - GoGuardian +// 8 - Hackterminal +// 9 - Appartement Eingang +// 10 - Appartement Ein/Ausgang +// 11 - Appartement Klingel/�ffner +// 12 - Standard Button +// 13 - Hack Button +// 14 - HOLOMATCH ENTRANCE +// 15 - HOLOMATCH EXIT +// 16 - HOLOMATCH REFRESH +// 17 - HOLOMATCH HEAL +// 18 - WORLDCHANGEACTOR +// 19 - CLANTERMINAL +// 20 - DATFILE WORLDCHANGE ACTOR +// 21 - LOCATION FOR 20 +// 22 - +// 23 - EINTRITTSGELD BUTTON +// 24- TUTORIALEXIT +// 25 - EXPLOSIVE +// 26 - Outpost Switch +// 27 - Old goguardian +// 28 - Fahrzeug Depot Interface +// 29 - Underground Exit +// 30 - Static FX (Value=Type. 1=Fire 2=Smoke 3=Steam 4=Sparkle) +// 31 - Venture Warp Station +// 32 - functionvalue+100 gibt eine Meldung aus der Text.ini [MISC] an. +// diff --git a/TinNS/Source/GameServer/GameCommands/Ban.cxx b/TinNS/Source/GameServer/GameCommands/Ban.cxx index 235aa0e..05296d6 100644 --- a/TinNS/Source/GameServer/GameCommands/Ban.cxx +++ b/TinNS/Source/GameServer/GameCommands/Ban.cxx @@ -1,94 +1,94 @@ -#include -#include "GameServer/Includes.hxx" - -void PCommands::doCmdban() -{ - bool SyntaxError = false; - if(ArgC < 2) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@ban ///"); - return; - } - - if(IsArgNumeric(1) == true) - { - target = GetClientByID(GetArgInt(1)); - } - else - { - char tmp_destNick[50]; - GetArgText(1, tmp_destNick, 50); - target = GetClientByNick(tmp_destNick); - } - - if(target == nullptr) // If victim isnt found, return error - { - Chat->send(source, CHAT_DIRECT, "System", "No such player"); - return; - } - if(source->GetAccountLevel() <= target->GetAccountLevel()) - { - char tmpMsg[200]; - snprintf(tmpMsg, 199, "Cant ban %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); - tmpMsg[199] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - return; - } - char tmpTimeVal[10]; - GetArgText(2, tmpTimeVal, 10); - - int32_t loop_i = 0; - char tmp_atoi[10]; - - while(isdigit(tmpTimeVal[loop_i]) != 0 && loop_i < 10) - { - tmp_atoi[loop_i] = tmpTimeVal[loop_i]; - loop_i++; - } - char timefactor[1]; - timefactor[0] = tmpTimeVal[loop_i]; - int32_t timevalue = atoi(tmp_atoi); - int32_t time_to_ban = 0; - - if(strcasecmp(timefactor, "s") == 0 ) - { - time_to_ban = timevalue; - } - else if(strcasecmp(timefactor, "m") == 0 ) - { - time_to_ban = timevalue * 60; - } - else if(strcasecmp(timefactor, "h") == 0 ) - { - time_to_ban = timevalue * 60 * 60; - } - else if(strcasecmp(timefactor, "d") == 0 ) - { - time_to_ban = timevalue * 60 * 60 * 24; - } - else - { - Chat->send(source, CHAT_DIRECT, "Usage", "@ban ///"); - return; - } - - int32_t final_bantime = std::time(nullptr) + time_to_ban; - PAccount Acc(target->GetAccountID()); - Acc.SetBannedUntilTime(final_bantime); - Acc.Save(); - - target->InitCharVanish(); - - GameServer->ClientDisconnected(target); // Now kick the player (Hes banned :) ) - - char tmpMsg_success[81]; - snprintf(tmpMsg_success, 80, "Successfully banned %s", target->GetChar()->GetName().c_str()); - tmpMsg_success[80] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success); - return; -} +#include +#include "GameServer/Includes.hxx" + +void PCommands::doCmdban() +{ + bool SyntaxError = false; + if(ArgC < 2) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@ban ///"); + return; + } + + if(IsArgNumeric(1) == true) + { + target = GetClientByID(GetArgInt(1)); + } + else + { + char tmp_destNick[50]; + GetArgText(1, tmp_destNick, 50); + target = GetClientByNick(tmp_destNick); + } + + if(target == nullptr) // If victim isnt found, return error + { + Chat->send(source, CHAT_DIRECT, "System", "No such player"); + return; + } + if(source->GetAccountLevel() <= target->GetAccountLevel()) + { + char tmpMsg[200]; + snprintf(tmpMsg, 199, "Cant ban %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); + tmpMsg[199] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + return; + } + char tmpTimeVal[10]; + GetArgText(2, tmpTimeVal, 10); + + int32_t loop_i = 0; + char tmp_atoi[10]; + + while(isdigit(tmpTimeVal[loop_i]) != 0 && loop_i < 10) + { + tmp_atoi[loop_i] = tmpTimeVal[loop_i]; + loop_i++; + } + char timefactor[1]; + timefactor[0] = tmpTimeVal[loop_i]; + int32_t timevalue = atoi(tmp_atoi); + int32_t time_to_ban = 0; + + if(strcasecmp(timefactor, "s") == 0 ) + { + time_to_ban = timevalue; + } + else if(strcasecmp(timefactor, "m") == 0 ) + { + time_to_ban = timevalue * 60; + } + else if(strcasecmp(timefactor, "h") == 0 ) + { + time_to_ban = timevalue * 60 * 60; + } + else if(strcasecmp(timefactor, "d") == 0 ) + { + time_to_ban = timevalue * 60 * 60 * 24; + } + else + { + Chat->send(source, CHAT_DIRECT, "Usage", "@ban ///"); + return; + } + + int32_t final_bantime = std::time(nullptr) + time_to_ban; + PAccount Acc(target->GetAccountID()); + Acc.SetBannedUntilTime(final_bantime); + Acc.Save(); + + target->InitCharVanish(); + + GameServer->ClientDisconnected(target); // Now kick the player (Hes banned :) ) + + char tmpMsg_success[81]; + snprintf(tmpMsg_success, 80, "Successfully banned %s", target->GetChar()->GetName().c_str()); + tmpMsg_success[80] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success); + return; +} diff --git a/TinNS/Source/GameServer/GameCommands/Brightness.cxx b/TinNS/Source/GameServer/GameCommands/Brightness.cxx index e285b30..0d3084f 100644 --- a/TinNS/Source/GameServer/GameCommands/Brightness.cxx +++ b/TinNS/Source/GameServer/GameCommands/Brightness.cxx @@ -1,43 +1,43 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdbrightness() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@brightness -| [-|] [-|]"); - return; - } - - char tmp_v1[30]; - char tmp_v2[30]; - char tmp_v3[30]; - - GetArgText(1, tmp_v1, 30); - GetArgText(2, tmp_v2, 30); - GetArgText(3, tmp_v3, 30); - - uint8_t val1, val2, val3, val4, val5, val6; - char effStr[128]; - PMessage* tmpMsg; - - source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6); - if(tmp_v1[0] != '-') - val4 = (uint8_t)(atoi(tmp_v1) & 0xff); - if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0')) - val5 = (uint8_t)(atoi(tmp_v2) & 0xff); - if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0')) - val6 = (uint8_t)(atoi(tmp_v3) & 0xff); - source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6); - - tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - ClientManager->UDPBroadcast(tmpMsg, source); - snprintf(effStr, 127, "Body brightness set to values %d %d %d", val4, val5, val6); - effStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", effStr); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdbrightness() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@brightness -| [-|] [-|]"); + return; + } + + char tmp_v1[30]; + char tmp_v2[30]; + char tmp_v3[30]; + + GetArgText(1, tmp_v1, 30); + GetArgText(2, tmp_v2, 30); + GetArgText(3, tmp_v3, 30); + + uint8_t val1, val2, val3, val4, val5, val6; + char effStr[128]; + PMessage* tmpMsg; + + source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6); + if(tmp_v1[0] != '-') + val4 = (uint8_t)(atoi(tmp_v1) & 0xff); + if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0')) + val5 = (uint8_t)(atoi(tmp_v2) & 0xff); + if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0')) + val6 = (uint8_t)(atoi(tmp_v3) & 0xff); + source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6); + + tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + ClientManager->UDPBroadcast(tmpMsg, source); + snprintf(effStr, 127, "Body brightness set to values %d %d %d", val4, val5, val6); + effStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", effStr); +} diff --git a/TinNS/Source/GameServer/GameCommands/Broadcast.cxx b/TinNS/Source/GameServer/GameCommands/Broadcast.cxx index 2fcf278..556ee62 100644 --- a/TinNS/Source/GameServer/GameCommands/Broadcast.cxx +++ b/TinNS/Source/GameServer/GameCommands/Broadcast.cxx @@ -1,13 +1,13 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmdbroadcast() -{ - if(DumbMade == false) - { - Console->Print("%s Missing packetdumb in PCommands::doCmdbroadcast for declared broadcast function!", Console->ColorText(RED, BLACK, "[PANIC]")); - return; - } - - Chat->sendBroadcast(OrgPacketDumb+11); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmdbroadcast() +{ + if(DumbMade == false) + { + Console->Print("%s Missing packetdumb in PCommands::doCmdbroadcast for declared broadcast function!", Console->ColorText(RED, BLACK, "[PANIC]")); + return; + } + + Chat->sendBroadcast(OrgPacketDumb+11); +} diff --git a/TinNS/Source/GameServer/GameCommands/Color.cxx b/TinNS/Source/GameServer/GameCommands/Color.cxx index f8bad49..d684782 100644 --- a/TinNS/Source/GameServer/GameCommands/Color.cxx +++ b/TinNS/Source/GameServer/GameCommands/Color.cxx @@ -1,43 +1,43 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdcolor() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@color -| [-|] [-|]"); - return; - } - - char tmp_v1[30]; - char tmp_v2[30]; - char tmp_v3[30]; - - GetArgText(1, tmp_v1, 30); - GetArgText(2, tmp_v2, 30); - GetArgText(3, tmp_v3, 30); - - uint8_t val1, val2, val3, val4, val5, val6; - char effStr[128]; - PMessage* tmpMsg; - - source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6); - if(tmp_v1[0] != '-') - val1 = (uint8_t)(atoi(tmp_v1) & 0xff); - if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0')) - val2 = (uint8_t)(atoi(tmp_v2) & 0xff); - if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0')) - val3 = (uint8_t)(atoi(tmp_v3) & 0xff); - source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6); - - tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - ClientManager->UDPBroadcast(tmpMsg, source); - snprintf(effStr, 127, "Body color set to values %d %d %d", val1, val2, val3); - effStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", effStr); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdcolor() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@color -| [-|] [-|]"); + return; + } + + char tmp_v1[30]; + char tmp_v2[30]; + char tmp_v3[30]; + + GetArgText(1, tmp_v1, 30); + GetArgText(2, tmp_v2, 30); + GetArgText(3, tmp_v3, 30); + + uint8_t val1, val2, val3, val4, val5, val6; + char effStr[128]; + PMessage* tmpMsg; + + source->GetChar()->GetCurrentBodyColor(val1, val2, val3, val4, val5, val6); + if(tmp_v1[0] != '-') + val1 = (uint8_t)(atoi(tmp_v1) & 0xff); + if((tmp_v2[0] != '-') && (tmp_v2[0] != '\0')) + val2 = (uint8_t)(atoi(tmp_v2) & 0xff); + if((tmp_v3[0] != '-') && (tmp_v3[0] != '\0')) + val3 = (uint8_t)(atoi(tmp_v3) & 0xff); + source->GetChar()->SetCurrentBodyColor(val1, val2, val3, val4, val5, val6); + + tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + ClientManager->UDPBroadcast(tmpMsg, source); + snprintf(effStr, 127, "Body color set to values %d %d %d", val1, val2, val3); + effStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", effStr); +} diff --git a/TinNS/Source/GameServer/GameCommands/Debug.cxx b/TinNS/Source/GameServer/GameCommands/Debug.cxx index 6b45f67..97dcb2a 100644 --- a/TinNS/Source/GameServer/GameCommands/Debug.cxx +++ b/TinNS/Source/GameServer/GameCommands/Debug.cxx @@ -1,75 +1,75 @@ -#include -#include "GameServer/Includes.hxx" - -void PCommands::doCmddebug() -{ - PDebugMode nWhat = DBG_ALL; - int nHow = -1; - const char* DbgTarget = "all"; - char DbgMessage[80]; - const char* Usage = "@debug [loc[ation] | it[emid] | sub[way]] [0|1]"; - - if(ArgC > 0) - { - if(IsArgNumeric(1) == true) - { - if(GetArgInt(1) == 0) - { - nHow = 0; - } - else - { - nHow = 1; - } - } - else - { - char tmp[10]; - if(GetArgText(1, tmp, 10)) - { - if(strncmp(tmp, "loc", 3) == 0) - { - nWhat = DBG_LOCATION; - DbgTarget = "location"; - } - else if(strncmp(tmp, "it", 2) == 0) - { - nWhat = DBG_ITEMID; - DbgTarget = "itemid"; - } - else if(strncmp(tmp, "sub", 3) == 0) - { - nWhat = DBG_SUBWAY; - DbgTarget = "subway"; - } - } - } - - if (nWhat != DBG_ALL) - { - if(ArgC == 1) - { - nHow = (source->GetDebugMode(nWhat) ? 0 : 1); // toggle if no arg - } - else if(ArgC > 1 && GetArgInt(2) == 0) - { - nHow = 0; - } - else if(ArgC > 1 && GetArgInt(2) == 1) - { - nHow = 1; - } - } - } - - if (nHow != -1) - { - source->SetDebugMode(nWhat, nHow); - snprintf(DbgMessage, 80, "Debug %s is now %s", DbgTarget, (nHow ? "ENABLED" : "DISABLED")); - Chat->send(source, CHAT_DIRECT, "System", DbgMessage); - } - else - { - Chat->send(source, CHAT_DIRECT, "Usage", Usage); - } -} +#include +#include "GameServer/Includes.hxx" + +void PCommands::doCmddebug() +{ + PDebugMode nWhat = DBG_ALL; + int nHow = -1; + const char* DbgTarget = "all"; + char DbgMessage[80]; + const char* Usage = "@debug [loc[ation] | it[emid] | sub[way]] [0|1]"; + + if(ArgC > 0) + { + if(IsArgNumeric(1) == true) + { + if(GetArgInt(1) == 0) + { + nHow = 0; + } + else + { + nHow = 1; + } + } + else + { + char tmp[10]; + if(GetArgText(1, tmp, 10)) + { + if(strncmp(tmp, "loc", 3) == 0) + { + nWhat = DBG_LOCATION; + DbgTarget = "location"; + } + else if(strncmp(tmp, "it", 2) == 0) + { + nWhat = DBG_ITEMID; + DbgTarget = "itemid"; + } + else if(strncmp(tmp, "sub", 3) == 0) + { + nWhat = DBG_SUBWAY; + DbgTarget = "subway"; + } + } + } + + if (nWhat != DBG_ALL) + { + if(ArgC == 1) + { + nHow = (source->GetDebugMode(nWhat) ? 0 : 1); // toggle if no arg + } + else if(ArgC > 1 && GetArgInt(2) == 0) + { + nHow = 0; + } + else if(ArgC > 1 && GetArgInt(2) == 1) + { + nHow = 1; + } + } + } + + if (nHow != -1) + { + source->SetDebugMode(nWhat, nHow); + snprintf(DbgMessage, 80, "Debug %s is now %s", DbgTarget, (nHow ? "ENABLED" : "DISABLED")); + Chat->send(source, CHAT_DIRECT, "System", DbgMessage); + } + else + { + Chat->send(source, CHAT_DIRECT, "Usage", Usage); + } +} diff --git a/TinNS/Source/GameServer/GameCommands/Effect.cxx b/TinNS/Source/GameServer/GameCommands/Effect.cxx index 926b92d..ab8ff39 100644 --- a/TinNS/Source/GameServer/GameCommands/Effect.cxx +++ b/TinNS/Source/GameServer/GameCommands/Effect.cxx @@ -1,36 +1,36 @@ -#include -#include -#include "GameServer/Includes.hxx" - -void PCommands::doCmdeffect() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(IsArgNumeric(1) == false) - SyntaxError = true; - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@effect []"); - return; - } - - uint8_t val1, val2; - char effStr[128]; - PMessage* tmpMsg; - - val1 = (uint8_t)(GetArgInt(1) & 0xff); - val2 = (uint8_t)(GetArgInt(2) & 0xff); - - source->GetChar()->SetBodyEffect(val1, val2); - - tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - ClientManager->UDPBroadcast(tmpMsg, source); - snprintf(effStr, 127, "Body effect set to value %d with density %d (but you can see it yourself)", val1, val2); - effStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", effStr); -} +#include +#include +#include "GameServer/Includes.hxx" + +void PCommands::doCmdeffect() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(IsArgNumeric(1) == false) + SyntaxError = true; + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@effect []"); + return; + } + + uint8_t val1, val2; + char effStr[128]; + PMessage* tmpMsg; + + val1 = (uint8_t)(GetArgInt(1) & 0xff); + val2 = (uint8_t)(GetArgInt(2) & 0xff); + + source->GetChar()->SetBodyEffect(val1, val2); + + tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + ClientManager->UDPBroadcast(tmpMsg, source); + snprintf(effStr, 127, "Body effect set to value %d with density %d (but you can see it yourself)", val1, val2); + effStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", effStr); +} diff --git a/TinNS/Source/GameServer/GameCommands/H.cxx b/TinNS/Source/GameServer/GameCommands/H.cxx index c39272e..53cbfa5 100644 --- a/TinNS/Source/GameServer/GameCommands/H.cxx +++ b/TinNS/Source/GameServer/GameCommands/H.cxx @@ -1,55 +1,55 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmd_dev_h() -{ - if(IsAdmin() == false) - return; - - if(source->GetAccountLevel() < PAL_ADMIN) - return; - - - - PMessage* tmpMsg = MsgBuilder->BuildEntityPositionMsg(source, GetArgInt(1) & 0xffff, GetArgInt(2) & 0xffff, GetArgInt(3) & 0xffff); - source->SendUDPMessage(tmpMsg); -/* - u8 val1, val2, val3, val4; - char tmpStr[128]; - - if(ArgC > 0) - { - val1 = (u8)(GetArgInt(1) & 0xff); - val2 = (u8)(GetArgInt(2) & 0xff); - val3 = (u8)(GetArgInt(3) & 0xff); - val4 = (ArgC > 3) ? (u8)(GetArgInt(4) & 0xff) : 0x01; - } - else - { - val1 = 0xff; - val2 = 0xff; - val3 = 0xff; - val4 = 0x01; - } - - PMessage* tmpMsg = new PMessage(14); - - *tmpMsg << (u8)0x13; - *tmpMsg << (u16)0x0000; //source->GetUDP_ID(); // just placeholder, must be set outside - *tmpMsg << (u16)0x0000; // source->GetSessionID(); // just placeholder, must be set outside - *tmpMsg << (u8)0x00; // Message length placeholder; - *tmpMsg << (u8)0x1f; - *tmpMsg << (u16)source->GetLocalID(); - *tmpMsg << (u8)0x30; - *tmpMsg << (u8)val1; //Head Heath (% ?) (45%) - *tmpMsg << (u8)val2; //Body Heath (35%) - *tmpMsg << (u8)val3; //Feet Heath (20%) - *tmpMsg << (u8)val4; - - (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6); - ClientManager->UDPBroadcast(tmpMsg, source); - - snprintf(tmpStr, 127, "Data set to values 0x%02x 0x%02x", val1, val2); - tmpStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpStr); - */ -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmd_dev_h() +{ + if(IsAdmin() == false) + return; + + if(source->GetAccountLevel() < PAL_ADMIN) + return; + + + + PMessage* tmpMsg = MsgBuilder->BuildEntityPositionMsg(source, GetArgInt(1) & 0xffff, GetArgInt(2) & 0xffff, GetArgInt(3) & 0xffff); + source->SendUDPMessage(tmpMsg); +/* + u8 val1, val2, val3, val4; + char tmpStr[128]; + + if(ArgC > 0) + { + val1 = (u8)(GetArgInt(1) & 0xff); + val2 = (u8)(GetArgInt(2) & 0xff); + val3 = (u8)(GetArgInt(3) & 0xff); + val4 = (ArgC > 3) ? (u8)(GetArgInt(4) & 0xff) : 0x01; + } + else + { + val1 = 0xff; + val2 = 0xff; + val3 = 0xff; + val4 = 0x01; + } + + PMessage* tmpMsg = new PMessage(14); + + *tmpMsg << (u8)0x13; + *tmpMsg << (u16)0x0000; //source->GetUDP_ID(); // just placeholder, must be set outside + *tmpMsg << (u16)0x0000; // source->GetSessionID(); // just placeholder, must be set outside + *tmpMsg << (u8)0x00; // Message length placeholder; + *tmpMsg << (u8)0x1f; + *tmpMsg << (u16)source->GetLocalID(); + *tmpMsg << (u8)0x30; + *tmpMsg << (u8)val1; //Head Heath (% ?) (45%) + *tmpMsg << (u8)val2; //Body Heath (35%) + *tmpMsg << (u8)val3; //Feet Heath (20%) + *tmpMsg << (u8)val4; + + (*tmpMsg)[5] = (u8)(tmpMsg->GetSize() - 6); + ClientManager->UDPBroadcast(tmpMsg, source); + + snprintf(tmpStr, 127, "Data set to values 0x%02x 0x%02x", val1, val2); + tmpStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpStr); + */ +} diff --git a/TinNS/Source/GameServer/GameCommands/Info.cxx b/TinNS/Source/GameServer/GameCommands/Info.cxx index c481ad7..92d023c 100644 --- a/TinNS/Source/GameServer/GameCommands/Info.cxx +++ b/TinNS/Source/GameServer/GameCommands/Info.cxx @@ -1,97 +1,97 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdinfo() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@info "); - return; - } - - if(IsArgNumeric(1) == true) - { - target = GetClientByID(GetArgInt(1)); - } - else - { - char tmp_destNick[50]; - GetArgText(1, tmp_destNick, 50); - target = GetClientByNick(tmp_destNick); - } - - if(target == NULL) // If victim isnt found, return error - { - Chat->send(source, CHAT_DIRECT, "System", "No such player"); - return; - } - // *************** Checks done, proceed with command - /* - DIRECT> System: PlayerInformation - DIRECT> Info: CharID : %d // victim->GetCharID(); - DIRECT> Info: AccountID : %d // victim->GetAccount()->GetID(); - DIRECT> Info: LoginName : %s // victim->GetAccount()->GetName(); - DIRECT> Info: AccessLevel: %d // victim->GetAccountLevel(); - DIRECT> Info: Current Loc: %d // Chars->GetChar(source->GetCharID())->GetLocation(); - DIRECT> Info: IP address : %s // victim->GetAddress(): - - Maybe for future addons... - DIRECT> System: CharInformation - DIRECT> Info: Faction : %d // Chars->GetChar(source->GetCharID())->GetFaction(); - DIRECT> Info: Cash : %d // Chars->GetChar(source->GetCharID())->GetCash(); - DIRECT> Info: Soullight : %d // Chars->GetChar(source->GetCharID())->GetSoullight(); - */ - - PAccount Acc(target->GetAccountID()); - - // If source != target - if(source->GetAccountID() != target->GetAccountID()) - { - // Check if accesslevel is lower - if(source->GetAccountLevel() <= target->GetAccountLevel()) - { - char tmpMsg[200]; - snprintf(tmpMsg, 199, "Cant display info about %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); - tmpMsg[199] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - return; - } - } - - char tmpInfo_head[151]; - char tmpInfo_cID[151]; - char tmpInfo_aID[151]; - char tmpInfo_Login[151]; - char tmpInfo_AxxLv[151]; - char tmpInfo_Loc[151]; - char tmpInfo_IP[151]; - - snprintf(tmpInfo_head, 150, "PlayerInformation"); - snprintf(tmpInfo_cID, 150, "CharID : %d", target->GetCharID()); - snprintf(tmpInfo_aID, 150, "AccountID : %d", Acc.GetID()); - snprintf(tmpInfo_Login, 150, "LoginName : %s", Acc.GetName().c_str()); - snprintf(tmpInfo_AxxLv, 150, "AccessLevel: %d", Acc.GetLevel()); - snprintf(tmpInfo_Loc, 150, "Current Loc: %d", Chars->GetChar(target->GetCharID())->GetLocation()); - snprintf(tmpInfo_IP, 150, "IP address : %s", target->GetAddress()); - - tmpInfo_head[150] = '\0'; - tmpInfo_cID[150] = '\0'; - tmpInfo_aID[150] = '\0'; - tmpInfo_Login[150] = '\0'; - tmpInfo_AxxLv[150] = '\0'; - tmpInfo_Loc[150] = '\0'; - tmpInfo_IP[150] = '\0'; - - Chat->send(source, CHAT_DIRECT, "System", tmpInfo_head); - Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_cID); - Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_aID); - Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Login); - Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_AxxLv); - Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Loc); - Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_IP); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdinfo() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@info "); + return; + } + + if(IsArgNumeric(1) == true) + { + target = GetClientByID(GetArgInt(1)); + } + else + { + char tmp_destNick[50]; + GetArgText(1, tmp_destNick, 50); + target = GetClientByNick(tmp_destNick); + } + + if(target == NULL) // If victim isnt found, return error + { + Chat->send(source, CHAT_DIRECT, "System", "No such player"); + return; + } + // *************** Checks done, proceed with command + /* + DIRECT> System: PlayerInformation + DIRECT> Info: CharID : %d // victim->GetCharID(); + DIRECT> Info: AccountID : %d // victim->GetAccount()->GetID(); + DIRECT> Info: LoginName : %s // victim->GetAccount()->GetName(); + DIRECT> Info: AccessLevel: %d // victim->GetAccountLevel(); + DIRECT> Info: Current Loc: %d // Chars->GetChar(source->GetCharID())->GetLocation(); + DIRECT> Info: IP address : %s // victim->GetAddress(): + + Maybe for future addons... + DIRECT> System: CharInformation + DIRECT> Info: Faction : %d // Chars->GetChar(source->GetCharID())->GetFaction(); + DIRECT> Info: Cash : %d // Chars->GetChar(source->GetCharID())->GetCash(); + DIRECT> Info: Soullight : %d // Chars->GetChar(source->GetCharID())->GetSoullight(); + */ + + PAccount Acc(target->GetAccountID()); + + // If source != target + if(source->GetAccountID() != target->GetAccountID()) + { + // Check if accesslevel is lower + if(source->GetAccountLevel() <= target->GetAccountLevel()) + { + char tmpMsg[200]; + snprintf(tmpMsg, 199, "Cant display info about %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); + tmpMsg[199] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + return; + } + } + + char tmpInfo_head[151]; + char tmpInfo_cID[151]; + char tmpInfo_aID[151]; + char tmpInfo_Login[151]; + char tmpInfo_AxxLv[151]; + char tmpInfo_Loc[151]; + char tmpInfo_IP[151]; + + snprintf(tmpInfo_head, 150, "PlayerInformation"); + snprintf(tmpInfo_cID, 150, "CharID : %d", target->GetCharID()); + snprintf(tmpInfo_aID, 150, "AccountID : %d", Acc.GetID()); + snprintf(tmpInfo_Login, 150, "LoginName : %s", Acc.GetName().c_str()); + snprintf(tmpInfo_AxxLv, 150, "AccessLevel: %d", Acc.GetLevel()); + snprintf(tmpInfo_Loc, 150, "Current Loc: %d", Chars->GetChar(target->GetCharID())->GetLocation()); + snprintf(tmpInfo_IP, 150, "IP address : %s", target->GetAddress()); + + tmpInfo_head[150] = '\0'; + tmpInfo_cID[150] = '\0'; + tmpInfo_aID[150] = '\0'; + tmpInfo_Login[150] = '\0'; + tmpInfo_AxxLv[150] = '\0'; + tmpInfo_Loc[150] = '\0'; + tmpInfo_IP[150] = '\0'; + + Chat->send(source, CHAT_DIRECT, "System", tmpInfo_head); + Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_cID); + Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_aID); + Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Login); + Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_AxxLv); + Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_Loc); + Chat->send(source, CHAT_DIRECT, "Info", tmpInfo_IP); +} diff --git a/TinNS/Source/GameServer/GameCommands/Kick.cxx b/TinNS/Source/GameServer/GameCommands/Kick.cxx index ffa22d2..c4a6b00 100644 --- a/TinNS/Source/GameServer/GameCommands/Kick.cxx +++ b/TinNS/Source/GameServer/GameCommands/Kick.cxx @@ -1,59 +1,59 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmdkick() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@kick "); - return; - } - - if(IsArgNumeric(1) == true) - { - target = GetClientByID(GetArgInt(1)); - } - else - { - char tmp_destNick[50]; - GetArgText(1, tmp_destNick, 50); - target = GetClientByNick(tmp_destNick); - } - - if(target == NULL) // If victim isnt found, return error - { - Chat->send(source, CHAT_DIRECT, "System", "No such player"); - return; - } - - // Make sure only people with a higher level than victim can kick victim - if(source->GetAccountLevel() <= target->GetAccountLevel()) - { - char tmpMsg[200]; - snprintf(tmpMsg, 199, "Cant kick %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); - tmpMsg[199] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - return; - } - -// *************** Checks done, proceed with command - int final_bantime = std::time(NULL) + 60; // Ban 60 seconds (Anti-Rejoin) - PAccount Acc(target->GetAccountID()); - Acc.SetBannedUntilTime(final_bantime); - Acc.Save(); - - target->InitCharVanish(); - GameServer->ClientDisconnected(target); // Kick - - Console->Print("%s %s (Lv %d) kicked %s (Lv %d)", Console->ColorText(YELLOW, BLACK, "[GameCommand]"), Chars->GetChar(source->GetCharID())->GetName().c_str(), source->GetAccountLevel(), Chars->GetChar(target->GetCharID())->GetName().c_str(), target->GetAccountLevel()); - char successmsg[100]; - snprintf(successmsg, 99, "Kicked %s", Chars->GetChar(target->GetCharID())->GetName().c_str()); - successmsg[99] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", successmsg); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmdkick() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@kick "); + return; + } + + if(IsArgNumeric(1) == true) + { + target = GetClientByID(GetArgInt(1)); + } + else + { + char tmp_destNick[50]; + GetArgText(1, tmp_destNick, 50); + target = GetClientByNick(tmp_destNick); + } + + if(target == NULL) // If victim isnt found, return error + { + Chat->send(source, CHAT_DIRECT, "System", "No such player"); + return; + } + + // Make sure only people with a higher level than victim can kick victim + if(source->GetAccountLevel() <= target->GetAccountLevel()) + { + char tmpMsg[200]; + snprintf(tmpMsg, 199, "Cant kick %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); + tmpMsg[199] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + return; + } + +// *************** Checks done, proceed with command + int final_bantime = std::time(NULL) + 60; // Ban 60 seconds (Anti-Rejoin) + PAccount Acc(target->GetAccountID()); + Acc.SetBannedUntilTime(final_bantime); + Acc.Save(); + + target->InitCharVanish(); + GameServer->ClientDisconnected(target); // Kick + + Console->Print("%s %s (Lv %d) kicked %s (Lv %d)", Console->ColorText(YELLOW, BLACK, "[GameCommand]"), Chars->GetChar(source->GetCharID())->GetName().c_str(), source->GetAccountLevel(), Chars->GetChar(target->GetCharID())->GetName().c_str(), target->GetAccountLevel()); + char successmsg[100]; + snprintf(successmsg, 99, "Kicked %s", Chars->GetChar(target->GetCharID())->GetName().c_str()); + successmsg[99] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", successmsg); +} diff --git a/TinNS/Source/GameServer/GameCommands/ListBans.cxx b/TinNS/Source/GameServer/GameCommands/ListBans.cxx index 88c5fa5..8c9997b 100644 --- a/TinNS/Source/GameServer/GameCommands/ListBans.cxx +++ b/TinNS/Source/GameServer/GameCommands/ListBans.cxx @@ -1,8 +1,8 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdlistbans() -{ - Chat->send(source, CHAT_DIRECT, "System", "Sorry, namikon was too lazy to code that ^^"); - Chat->send(source, CHAT_DIRECT, "System", "Please wait until the ban is removed automaticly or edit your sqlDB"); - return; -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdlistbans() +{ + Chat->send(source, CHAT_DIRECT, "System", "Sorry, namikon was too lazy to code that ^^"); + Chat->send(source, CHAT_DIRECT, "System", "Please wait until the ban is removed automaticly or edit your sqlDB"); + return; +} diff --git a/TinNS/Source/GameServer/GameCommands/Online.cxx b/TinNS/Source/GameServer/GameCommands/Online.cxx index 096d394..0b12031 100644 --- a/TinNS/Source/GameServer/GameCommands/Online.cxx +++ b/TinNS/Source/GameServer/GameCommands/Online.cxx @@ -1,8 +1,8 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmdconlist() -{ - if (gDevDebug) Console->Print("IngameCommand: Sending connected-player-list to charID %d", source->GetCharID()); - Chat->sendConnectedList(source, false); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmdconlist() +{ + if (gDevDebug) Console->Print("IngameCommand: Sending connected-player-list to charID %d", source->GetCharID()); + Chat->sendConnectedList(source, false); +} diff --git a/TinNS/Source/GameServer/GameCommands/RawF.cxx b/TinNS/Source/GameServer/GameCommands/RawF.cxx index 0dab13a..d4d176f 100644 --- a/TinNS/Source/GameServer/GameCommands/RawF.cxx +++ b/TinNS/Source/GameServer/GameCommands/RawF.cxx @@ -1,85 +1,85 @@ -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmdrawf() -{ - bool SyntaxError = false; - bool DebugMode = false; - int Prot = 0; // 0: Error 1: UDP 2: TCP - - if(ArgC < 2) - { - SyntaxError = true; - } - - char file_to_send[50], protocol_to_use[10]; - GetArgText(1, file_to_send, 50); - GetArgText(2, protocol_to_use, 10); - - if(strcmp(protocol_to_use, "udp") == 0) - { - Prot = 1; - } - else if(strcmp(protocol_to_use, "tcp") == 0) - { - Prot = 2; - } - else if(strcmp(protocol_to_use, "debug") == 0) - { - DebugMode = true; - } - else - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@rawf "); - return; - } - - std::ifstream::pos_type size; - char *buffer; - - std::ifstream hexdump (file_to_send, std::ios::in | std::ios::binary | std::ios::ate); - if (hexdump.is_open()) - { - if (gDevDebug) Console->Print("IngameCommand: Sending packet file %s", file_to_send); - - size = hexdump.tellg(); - buffer = new char [size]; - hexdump.seekg (0, std::ios::beg); - - hexdump.read (buffer, size); - hexdump.close(); - if(DebugMode == true) - { - int k; - Console->Print("Byte dump of %s:", file_to_send); - for(k=0;kPrint("Byte %d: %#x", k, buffer[k]); - } - } - else - { - if(Prot == 1) - source->getUDPConn()->write(buffer, size); - else if(Prot == 2) - source->getTCPConn()->write(buffer, size); - else // Should never happen... - Console->Print("%s unable to determine protocol in PCommands::doCmdrawf", Console->ColorText(RED, BLACK, "[Error]")); - } - - delete[] buffer; - } - else - { - char output[100]; - Console->Print("IngameCommand: Unable to send file %s", file_to_send); - snprintf(output, 100, "File not found: %s", file_to_send); - Chat->send(source, CHAT_DIRECT, "System", output); - } -} +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmdrawf() +{ + bool SyntaxError = false; + bool DebugMode = false; + int Prot = 0; // 0: Error 1: UDP 2: TCP + + if(ArgC < 2) + { + SyntaxError = true; + } + + char file_to_send[50], protocol_to_use[10]; + GetArgText(1, file_to_send, 50); + GetArgText(2, protocol_to_use, 10); + + if(strcmp(protocol_to_use, "udp") == 0) + { + Prot = 1; + } + else if(strcmp(protocol_to_use, "tcp") == 0) + { + Prot = 2; + } + else if(strcmp(protocol_to_use, "debug") == 0) + { + DebugMode = true; + } + else + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@rawf "); + return; + } + + std::ifstream::pos_type size; + char *buffer; + + std::ifstream hexdump (file_to_send, std::ios::in | std::ios::binary | std::ios::ate); + if (hexdump.is_open()) + { + if (gDevDebug) Console->Print("IngameCommand: Sending packet file %s", file_to_send); + + size = hexdump.tellg(); + buffer = new char [size]; + hexdump.seekg (0, std::ios::beg); + + hexdump.read (buffer, size); + hexdump.close(); + if(DebugMode == true) + { + int k; + Console->Print("Byte dump of %s:", file_to_send); + for(k=0;kPrint("Byte %d: %#x", k, buffer[k]); + } + } + else + { + if(Prot == 1) + source->getUDPConn()->write(buffer, size); + else if(Prot == 2) + source->getTCPConn()->write(buffer, size); + else // Should never happen... + Console->Print("%s unable to determine protocol in PCommands::doCmdrawf", Console->ColorText(RED, BLACK, "[Error]")); + } + + delete[] buffer; + } + else + { + char output[100]; + Console->Print("IngameCommand: Unable to send file %s", file_to_send); + snprintf(output, 100, "File not found: %s", file_to_send); + Chat->send(source, CHAT_DIRECT, "System", output); + } +} diff --git a/TinNS/Source/GameServer/GameCommands/Remove.cxx b/TinNS/Source/GameServer/GameCommands/Remove.cxx index d52948a..4f96f9f 100644 --- a/TinNS/Source/GameServer/GameCommands/Remove.cxx +++ b/TinNS/Source/GameServer/GameCommands/Remove.cxx @@ -1,63 +1,63 @@ -#include -#include "GameServer/Includes.hxx" - -void PCommands::doCmdremove() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@remove actor/"); - return; - } - - char tmp_v1[30]; - GetArgText(1, tmp_v1, 30); - - if(strcmp(tmp_v1, "actor") == 0) - { - if(source->IsInRemoveActorMode() == false) - { - source->SetRemoveActorMode(true); - Chat->send(source, CHAT_DIRECT, "System", "You are now in REMOVE ACTOR mode. Rightclick an actor to remove it, type command again to disable mode"); - } - else - { - source->SetRemoveActorMode(false); - Chat->send(source, CHAT_DIRECT, "System", "REMOVE ACTOR mode disabled"); - } - return; - } - - if(IsArgNumeric(1) == true) - { - uint32_t tTest = GetArgInt(1); - if(WorldActors->IsDynamicActor(tTest) == true) - { - Chat->send(source, CHAT_DIRECT, "System", "You cannot remove dynamic actors over their ID!"); - return; - } - uint32_t TargetID; - char delStr[128]; - PMessage* tmpMsg; - - TargetID = (uint32_t)(atoi(tmp_v1) & 0xffffffff); - tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 5); - - ClientManager->UDPBroadcast(tmpMsg, source); - tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 9); - - ClientManager->UDPBroadcast(tmpMsg, source); - snprintf(delStr, 127, "Item %d removed.", TargetID); - delStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", delStr); - } - else - { - Chat->send(source, CHAT_DIRECT, "System", "Invalid argument given"); - return; - } -} +#include +#include "GameServer/Includes.hxx" + +void PCommands::doCmdremove() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@remove actor/"); + return; + } + + char tmp_v1[30]; + GetArgText(1, tmp_v1, 30); + + if(strcmp(tmp_v1, "actor") == 0) + { + if(source->IsInRemoveActorMode() == false) + { + source->SetRemoveActorMode(true); + Chat->send(source, CHAT_DIRECT, "System", "You are now in REMOVE ACTOR mode. Rightclick an actor to remove it, type command again to disable mode"); + } + else + { + source->SetRemoveActorMode(false); + Chat->send(source, CHAT_DIRECT, "System", "REMOVE ACTOR mode disabled"); + } + return; + } + + if(IsArgNumeric(1) == true) + { + uint32_t tTest = GetArgInt(1); + if(WorldActors->IsDynamicActor(tTest) == true) + { + Chat->send(source, CHAT_DIRECT, "System", "You cannot remove dynamic actors over their ID!"); + return; + } + uint32_t TargetID; + char delStr[128]; + PMessage* tmpMsg; + + TargetID = (uint32_t)(atoi(tmp_v1) & 0xffffffff); + tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 5); + + ClientManager->UDPBroadcast(tmpMsg, source); + tmpMsg = MsgBuilder->BuildFurnitureActivateMsg(source, TargetID, 9); + + ClientManager->UDPBroadcast(tmpMsg, source); + snprintf(delStr, 127, "Item %d removed.", TargetID); + delStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", delStr); + } + else + { + Chat->send(source, CHAT_DIRECT, "System", "Invalid argument given"); + return; + } +} diff --git a/TinNS/Source/GameServer/GameCommands/SetLevel.cxx b/TinNS/Source/GameServer/GameCommands/SetLevel.cxx index ea23ff9..e0a2a74 100644 --- a/TinNS/Source/GameServer/GameCommands/SetLevel.cxx +++ b/TinNS/Source/GameServer/GameCommands/SetLevel.cxx @@ -1,66 +1,66 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdsetlevel() -{ - int destLevel = 0; - bool SyntaxError = false; - if (ArgC < 2) - { - SyntaxError = true; - } - - if (IsArgNumeric(2) == false) - { - SyntaxError = true; - } - else - { - destLevel = GetArgInt(2); - } - - if (SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@setlevel "); - return; - } - - if (IsArgNumeric(1) == true) - { - target = GetClientByID(GetArgInt(1)); - } - else - { - char tmp_destNick[50]; - GetArgText(1, tmp_destNick, 50); - target = GetClientByNick(tmp_destNick); - } - - if (target == NULL) // If victim isnt found, return error - { - Chat->send(source, CHAT_DIRECT, "System", "No such player"); - return; - } - if (source->GetAccountLevel() <= target->GetAccountLevel()) - { - char tmpMsg[200]; - snprintf(tmpMsg, 199, "Cant set new level for %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); - tmpMsg[199] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - return; - } - - PAccount Acc(target->GetAccountID()); - Acc.SetLevel(destLevel); - Acc.Save(); - source->RefreshAccountInfo(&Acc); - - char tmpMsg[60], tmpMsg2[60]; - snprintf(tmpMsg, 59, "Set level for player %s to %d", Chars->GetChar(target->GetCharID())->GetName().c_str(), destLevel); - snprintf(tmpMsg2, 59, "**POOF** Your new accesslevel is now %d", destLevel); - - tmpMsg[59] = '\0'; - tmpMsg2[59] = '\0'; - - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - Chat->send(target, CHAT_DIRECT, "System", tmpMsg2); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdsetlevel() +{ + int destLevel = 0; + bool SyntaxError = false; + if (ArgC < 2) + { + SyntaxError = true; + } + + if (IsArgNumeric(2) == false) + { + SyntaxError = true; + } + else + { + destLevel = GetArgInt(2); + } + + if (SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@setlevel "); + return; + } + + if (IsArgNumeric(1) == true) + { + target = GetClientByID(GetArgInt(1)); + } + else + { + char tmp_destNick[50]; + GetArgText(1, tmp_destNick, 50); + target = GetClientByNick(tmp_destNick); + } + + if (target == NULL) // If victim isnt found, return error + { + Chat->send(source, CHAT_DIRECT, "System", "No such player"); + return; + } + if (source->GetAccountLevel() <= target->GetAccountLevel()) + { + char tmpMsg[200]; + snprintf(tmpMsg, 199, "Cant set new level for %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); + tmpMsg[199] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + return; + } + + PAccount Acc(target->GetAccountID()); + Acc.SetLevel(destLevel); + Acc.Save(); + source->RefreshAccountInfo(&Acc); + + char tmpMsg[60], tmpMsg2[60]; + snprintf(tmpMsg, 59, "Set level for player %s to %d", Chars->GetChar(target->GetCharID())->GetName().c_str(), destLevel); + snprintf(tmpMsg2, 59, "**POOF** Your new accesslevel is now %d", destLevel); + + tmpMsg[59] = '\0'; + tmpMsg2[59] = '\0'; + + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + Chat->send(target, CHAT_DIRECT, "System", tmpMsg2); +} diff --git a/TinNS/Source/GameServer/GameCommands/SetTime.cxx b/TinNS/Source/GameServer/GameCommands/SetTime.cxx index 0b38078..fdbd528 100644 --- a/TinNS/Source/GameServer/GameCommands/SetTime.cxx +++ b/TinNS/Source/GameServer/GameCommands/SetTime.cxx @@ -1,17 +1,17 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmdsettime() -{ - if(ArgC < 1 && GetArgInt(1) == 0) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@settime "); - return; - } - - int newtime = 0; - newtime = GetArgInt(1); - - GameServer->SetGameTime(newtime); - Console->Print("IngameCommand: CharID %d set ingametime to %d", source->GetCharID(), newtime); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmdsettime() +{ + if(ArgC < 1 && GetArgInt(1) == 0) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@settime "); + return; + } + + int newtime = 0; + newtime = GetArgInt(1); + + GameServer->SetGameTime(newtime); + Console->Print("IngameCommand: CharID %d set ingametime to %d", source->GetCharID(), newtime); +} diff --git a/TinNS/Source/GameServer/GameCommands/Shun.cxx b/TinNS/Source/GameServer/GameCommands/Shun.cxx index c899549..d1447d4 100644 --- a/TinNS/Source/GameServer/GameCommands/Shun.cxx +++ b/TinNS/Source/GameServer/GameCommands/Shun.cxx @@ -1,56 +1,56 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdshun() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@shun "); - return; - } - - if(IsArgNumeric(1) == true) - { - target = GetClientByID(GetArgInt(1)); - } - else - { - char tmp_destNick[50]; - GetArgText(1, tmp_destNick, 50); - target = GetClientByNick(tmp_destNick); - } - - if(target == NULL) // If victim isnt found, return error - { - Chat->send(source, CHAT_DIRECT, "System", "No such player"); - return; - } - if(source->GetAccountLevel() <= target->GetAccountLevel()) - { - char tmpMsg[200]; - snprintf(tmpMsg, 199, "Cant shun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); - tmpMsg[199] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - return; - } - if(target->GetChar()->IsShunned() == false) - { - target->GetChar()->SetShun(true); - - char tmpMsg_success[81]; - snprintf(tmpMsg_success, 80, "Successfully shunned %s", target->GetChar()->GetName().c_str()); - tmpMsg_success[80] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success); - return; - } - else - { - Chat->send(source, CHAT_DIRECT, "System", "Player is already shunned"); - return; - } -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdshun() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@shun "); + return; + } + + if(IsArgNumeric(1) == true) + { + target = GetClientByID(GetArgInt(1)); + } + else + { + char tmp_destNick[50]; + GetArgText(1, tmp_destNick, 50); + target = GetClientByNick(tmp_destNick); + } + + if(target == NULL) // If victim isnt found, return error + { + Chat->send(source, CHAT_DIRECT, "System", "No such player"); + return; + } + if(source->GetAccountLevel() <= target->GetAccountLevel()) + { + char tmpMsg[200]; + snprintf(tmpMsg, 199, "Cant shun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); + tmpMsg[199] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + return; + } + if(target->GetChar()->IsShunned() == false) + { + target->GetChar()->SetShun(true); + + char tmpMsg_success[81]; + snprintf(tmpMsg_success, 80, "Successfully shunned %s", target->GetChar()->GetName().c_str()); + tmpMsg_success[80] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success); + return; + } + else + { + Chat->send(source, CHAT_DIRECT, "System", "Player is already shunned"); + return; + } +} diff --git a/TinNS/Source/GameServer/GameCommands/Skin.cxx b/TinNS/Source/GameServer/GameCommands/Skin.cxx index 249fa29..03494f2 100644 --- a/TinNS/Source/GameServer/GameCommands/Skin.cxx +++ b/TinNS/Source/GameServer/GameCommands/Skin.cxx @@ -1,102 +1,102 @@ -#include -#include "GameServer/Includes.hxx" - -void PCommands::doCmdskin() -{ -// ------------------------------------------------------- -/* -Usage: @skin # - for use with the index id from characters.def - or @skin |-|# [[ [ ]]] - is the model id found after the model name in characters.def - # resets to real char skin (optionnaly modified by following args) - - means current skin - incrementaly optional , and are values 0-9 -*/ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - uint32_t Skinval1, Skinval2, Skinval3, Skinval4; - PChar *SkinChar = Chars->GetChar(source->GetCharID()); - std::stringstream SkinChat; - char SkinStr[128]; - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@skin ( # ) | ( | # [[ [ ]]] )"); - return; - } - - char tmpval[30]; - GetArgText(1, tmpval, 30); - if((tmpval[0] == '#') && (tmpval[1] != '\0')) - { - Skinval1 = atoi(tmpval+1); - SkinChar->SetCurrentLookFromCharType(atoi(tmpval+1)); - SkinChat << "Skin set to the skin of char type "; - SkinChat << (int)Skinval1; - } - else - { - if ((tmpval[0] == '#') && (tmpval[1] == '\0')) - { - SkinChar->GetRealLook(Skinval1, Skinval2, Skinval3, Skinval4); - } - else if ((tmpval[0] == '-') && (tmpval[1] == '\0')) - { - SkinChar->GetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4); - } - else - { - Skinval1 = GetArgInt(1); - } - - char tmp_arg2[30]; - char tmp_arg3[30]; - char tmp_arg4[30]; - - GetArgText(2, tmp_arg2, 30); - GetArgText(3, tmp_arg3, 30); - GetArgText(4, tmp_arg4, 30); - - if(tmp_arg2[0] != '\0') - { - if(tmp_arg2[0] != '-') - { - tmp_arg2[1] = '\0'; - Skinval2 = GetArgInt(2); - } - if(tmp_arg3[0] != '\0') - { - if(tmp_arg3[0] != '-') - { - tmp_arg3[1] = '\0'; - Skinval3 = GetArgInt(3); - } - if(tmp_arg4[0] != '\0') - { - if(tmp_arg4[0] != '-') - { - tmp_arg4[1] = '\0'; - Skinval4 = GetArgInt(4); - } - } - } - } - - SkinChar->SetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4); - - SkinChat << "Skin set to model "; - SkinChat << (int)Skinval1 << " with head " << (int)Skinval2 << ", torso " << (int)Skinval3 << ", legs " << (int)Skinval4; - } - - snprintf(SkinStr, 127, "%s", SkinChat.str().c_str()); - SkinStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", SkinStr); - - PMessage* tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - ClientManager->UDPBroadcast(tmpMsg, source); -} +#include +#include "GameServer/Includes.hxx" + +void PCommands::doCmdskin() +{ +// ------------------------------------------------------- +/* +Usage: @skin # + for use with the index id from characters.def + or @skin |-|# [[ [ ]]] + is the model id found after the model name in characters.def + # resets to real char skin (optionnaly modified by following args) + - means current skin + incrementaly optional , and are values 0-9 +*/ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + uint32_t Skinval1, Skinval2, Skinval3, Skinval4; + PChar *SkinChar = Chars->GetChar(source->GetCharID()); + std::stringstream SkinChat; + char SkinStr[128]; + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@skin ( # ) | ( | # [[ [ ]]] )"); + return; + } + + char tmpval[30]; + GetArgText(1, tmpval, 30); + if((tmpval[0] == '#') && (tmpval[1] != '\0')) + { + Skinval1 = atoi(tmpval+1); + SkinChar->SetCurrentLookFromCharType(atoi(tmpval+1)); + SkinChat << "Skin set to the skin of char type "; + SkinChat << (int)Skinval1; + } + else + { + if ((tmpval[0] == '#') && (tmpval[1] == '\0')) + { + SkinChar->GetRealLook(Skinval1, Skinval2, Skinval3, Skinval4); + } + else if ((tmpval[0] == '-') && (tmpval[1] == '\0')) + { + SkinChar->GetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4); + } + else + { + Skinval1 = GetArgInt(1); + } + + char tmp_arg2[30]; + char tmp_arg3[30]; + char tmp_arg4[30]; + + GetArgText(2, tmp_arg2, 30); + GetArgText(3, tmp_arg3, 30); + GetArgText(4, tmp_arg4, 30); + + if(tmp_arg2[0] != '\0') + { + if(tmp_arg2[0] != '-') + { + tmp_arg2[1] = '\0'; + Skinval2 = GetArgInt(2); + } + if(tmp_arg3[0] != '\0') + { + if(tmp_arg3[0] != '-') + { + tmp_arg3[1] = '\0'; + Skinval3 = GetArgInt(3); + } + if(tmp_arg4[0] != '\0') + { + if(tmp_arg4[0] != '-') + { + tmp_arg4[1] = '\0'; + Skinval4 = GetArgInt(4); + } + } + } + } + + SkinChar->SetCurrentLook(Skinval1, Skinval2, Skinval3, Skinval4); + + SkinChat << "Skin set to model "; + SkinChat << (int)Skinval1 << " with head " << (int)Skinval2 << ", torso " << (int)Skinval3 << ", legs " << (int)Skinval4; + } + + snprintf(SkinStr, 127, "%s", SkinChat.str().c_str()); + SkinStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", SkinStr); + + PMessage* tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + ClientManager->UDPBroadcast(tmpMsg, source); +} diff --git a/TinNS/Source/GameServer/GameCommands/SpawnActor.cxx b/TinNS/Source/GameServer/GameCommands/SpawnActor.cxx index 678a550..9d8407a 100644 --- a/TinNS/Source/GameServer/GameCommands/SpawnActor.cxx +++ b/TinNS/Source/GameServer/GameCommands/SpawnActor.cxx @@ -1,92 +1,92 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdspawnactor() -{ - bool SyntaxError = false; - if(ArgC < 2) - { - SyntaxError = true; - } - - if(IsArgNumeric(1) == false || IsArgNumeric(2) == false) - { - SyntaxError = true; - } - - uint16_t tmpActorID = (uint16_t)GetArgInt(1); - uint16_t tmpFunctionID = (uint16_t)GetArgInt(2); - uint16_t tmpOption1 = 0; - uint16_t tmpOption2 = 0; - uint16_t tmpOption3 = 0; - - if(ArgC > 2) - { - if(IsArgNumeric(3) == false) - { - SyntaxError = true; - } - else - { - tmpOption1 = (uint16_t)GetArgInt(3); - if(ArgC > 3) - { - if(IsArgNumeric(4) == false) - { - SyntaxError = true; - } - else - { - tmpOption1 = (uint16_t)GetArgInt(4); - if(ArgC > 4) - { - if(IsArgNumeric(4) == false) - { - SyntaxError = true; - } - else - { - tmpOption1 = (uint16_t)GetArgInt(5); - } - } - } - } - } - } - - if(tmpActorID == 0) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@spawnactor [ ]"); - return; - } - - if(WorldActors->IsValidWAFunction(tmpFunctionID) == true) - { - if(WorldActors->RequiresLinkedObject(tmpFunctionID == true)) - { - if(WorldActors->IsValidLinkedObject(source, tmpOption1, tmpFunctionID) == false) - { - if(tmpOption1 == 0) - Chat->send(source, CHAT_DIRECT, "System", "Error: This functionID requires an linked object"); - else if(tmpOption1 == 18) - Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid destination world"); - else - Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid worldobjectID to link to"); - return; - } - } - WorldActors->AddWorldActor(source, tmpActorID, tmpFunctionID, tmpOption1, tmpOption2, tmpOption3); - } - else - { - Chat->send(source, CHAT_DIRECT, "System", "Error: This is an invalid function ID"); - return; - } - //PMessage* tmpMsg = MsgBuilder->BuiltSpawnObjectMsg(source, tmpActorID, tmpFunctionID, mWOID++); - //ClientManager->UDPBroadcast(tmpMsg, source); - //tmpMsg = NULL; -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdspawnactor() +{ + bool SyntaxError = false; + if(ArgC < 2) + { + SyntaxError = true; + } + + if(IsArgNumeric(1) == false || IsArgNumeric(2) == false) + { + SyntaxError = true; + } + + uint16_t tmpActorID = (uint16_t)GetArgInt(1); + uint16_t tmpFunctionID = (uint16_t)GetArgInt(2); + uint16_t tmpOption1 = 0; + uint16_t tmpOption2 = 0; + uint16_t tmpOption3 = 0; + + if(ArgC > 2) + { + if(IsArgNumeric(3) == false) + { + SyntaxError = true; + } + else + { + tmpOption1 = (uint16_t)GetArgInt(3); + if(ArgC > 3) + { + if(IsArgNumeric(4) == false) + { + SyntaxError = true; + } + else + { + tmpOption1 = (uint16_t)GetArgInt(4); + if(ArgC > 4) + { + if(IsArgNumeric(4) == false) + { + SyntaxError = true; + } + else + { + tmpOption1 = (uint16_t)GetArgInt(5); + } + } + } + } + } + } + + if(tmpActorID == 0) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@spawnactor [ ]"); + return; + } + + if(WorldActors->IsValidWAFunction(tmpFunctionID) == true) + { + if(WorldActors->RequiresLinkedObject(tmpFunctionID == true)) + { + if(WorldActors->IsValidLinkedObject(source, tmpOption1, tmpFunctionID) == false) + { + if(tmpOption1 == 0) + Chat->send(source, CHAT_DIRECT, "System", "Error: This functionID requires an linked object"); + else if(tmpOption1 == 18) + Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid destination world"); + else + Chat->send(source, CHAT_DIRECT, "System", "Error: Invalid worldobjectID to link to"); + return; + } + } + WorldActors->AddWorldActor(source, tmpActorID, tmpFunctionID, tmpOption1, tmpOption2, tmpOption3); + } + else + { + Chat->send(source, CHAT_DIRECT, "System", "Error: This is an invalid function ID"); + return; + } + //PMessage* tmpMsg = MsgBuilder->BuiltSpawnObjectMsg(source, tmpActorID, tmpFunctionID, mWOID++); + //ClientManager->UDPBroadcast(tmpMsg, source); + //tmpMsg = NULL; +} diff --git a/TinNS/Source/GameServer/GameCommands/Speed.cxx b/TinNS/Source/GameServer/GameCommands/Speed.cxx index 8b86daa..6dee3f2 100644 --- a/TinNS/Source/GameServer/GameCommands/Speed.cxx +++ b/TinNS/Source/GameServer/GameCommands/Speed.cxx @@ -1,35 +1,35 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdspeed() -{ -// Speed override setting. -// Usage: @speed | # -// with = 0 (no move).. 254 , 255 or # meaning "no speed override" - - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@speed | 255 | #"); - return; - } - char tmpval[30]; - GetArgText(1, tmpval, 30); - - uint8_t val1; - char effStr[128]; - PMessage* tmpMsg; - - val1 = ((tmpval[0] == '#') ? 255 : (uint8_t)(atoi(tmpval) & 0xff)); - source->GetChar()->SetSpeedOverride(val1); - - tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - ClientManager->UDPBroadcast(tmpMsg, source); - snprintf(effStr, 127, "Speed override set to value %d ", val1); - effStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", effStr); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdspeed() +{ +// Speed override setting. +// Usage: @speed | # +// with = 0 (no move).. 254 , 255 or # meaning "no speed override" + + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@speed | 255 | #"); + return; + } + char tmpval[30]; + GetArgText(1, tmpval, 30); + + uint8_t val1; + char effStr[128]; + PMessage* tmpMsg; + + val1 = ((tmpval[0] == '#') ? 255 : (uint8_t)(atoi(tmpval) & 0xff)); + source->GetChar()->SetSpeedOverride(val1); + + tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + ClientManager->UDPBroadcast(tmpMsg, source); + snprintf(effStr, 127, "Speed override set to value %d ", val1); + effStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", effStr); +} diff --git a/TinNS/Source/GameServer/GameCommands/T.cxx b/TinNS/Source/GameServer/GameCommands/T.cxx index 8c463a5..051b2fb 100644 --- a/TinNS/Source/GameServer/GameCommands/T.cxx +++ b/TinNS/Source/GameServer/GameCommands/T.cxx @@ -1,475 +1,475 @@ -#include -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmd_dev_t() -{ - const char* usage = "Usage: @t r (to remove object) | @t d [ []] (to send death packet to object with args v1 v2)"; - char tmpStr[128]; - const char* textMsg = usage; - PMessage* tmpMsg = NULL; - char Arg1[30]; - - if ( IsAdmin() == false ) - return; - - Arg1[0] = tmpStr[0] = '\0'; - - if ( ArgC >= 2 ) - { - GetArgText( 1, Arg1, 30 ); - uint32_t targetObjectId = GetArgInt( 2 ) & 0xffffffff; - if ( Arg1[0] == 't' ) - { - uint8_t val1; - if ( ArgC >= 3 ) - { - int val2 = GetArgInt( 3 ); - tmpMsg = new PMessage( 32 ); - source->IncreaseUDP_ID(); - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint16_t )source->GetSessionID(); - *tmpMsg << ( uint8_t )0x00; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x2d; - *tmpMsg << ( uint32_t )targetObjectId; - *tmpMsg << ( uint8_t )0x01; - *tmpMsg << ( uint32_t )val2; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - source->SendUDPMessage( tmpMsg ); - snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with values 6/%d", targetObjectId, val2 ); - textMsg = tmpStr; - } - else for(val1 = 2; val1 < 255; ++val1) - { - if(val1 == 6) continue; - tmpMsg = new PMessage( 15 ); - source->IncreaseUDP_ID(); - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint16_t )source->GetSessionID(); - *tmpMsg << ( uint8_t )0x00; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x2d; - *tmpMsg << ( uint32_t )targetObjectId; - *tmpMsg << ( uint8_t )val1; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - source->SendUDPMessage( tmpMsg ); - snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with value %d", targetObjectId, val1 ); - textMsg = tmpStr; - tmpStr[127] = '\0'; - Chat->send( source, CHAT_DIRECT, "System", textMsg ); - source->getUDPConn()->update(); - source->getTCPConn()->update(); - //sleep(1); - std::this_thread::sleep_for(std::chrono::seconds(1)); - } - tmpMsg = NULL; - } - else if ( Arg1[0] == 'd' ) - { - uint8_t val1 = 0x4a; // default values - uint8_t val2 = 0x1e; - - if ( ArgC >= 3 ) - val1 = GetArgInt( 3 ) & 0xff; - if ( ArgC >= 4 ) - val2 = GetArgInt( 4 ) & 0xff; - tmpMsg = MsgBuilder->BuildNpcDeathMsg( source, targetObjectId, val1, val2 ); - snprintf( tmpStr, 127, "Sending Death update to object id 0x%08x with values 0x%02x 0x%02x", targetObjectId, val1, val2 ); - textMsg = tmpStr; - } - else if ( Arg1[0] == 'm' ) - { - uint8_t nTxtGroupID = targetObjectId & 0xff; - uint16_t nTxtID = 10; - //uint32_t nVal = 0; - if ( ArgC >= 3 ) - nTxtID = GetArgInt( 3 ) & 0xffff; - //if(ArgC >= 4) - // val2 = GetArgInt(4) & 0xff; - - tmpMsg = new PMessage( 20 ); - - source->IncreaseUDP_ID(); - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint16_t )source->GetSessionID(); - *tmpMsg << ( uint8_t )0x0e; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )source->GetLocalID(); - *tmpMsg << ( uint8_t )0x25; // ?? - *tmpMsg << ( uint8_t )0x15; // ?? - *tmpMsg << nTxtGroupID; - *tmpMsg << nTxtID; - *tmpMsg << ( uint16_t )0x00; // ?? - *tmpMsg << ( uint8_t )0x01; - *tmpMsg << ( uint8_t )0x04; - *tmpMsg << ( uint32_t )0x00; - //*tmpMsg << (uint8_t)0x00; // ?? - //*tmpMsg << (uint8_t)0x00; // ?? - //*tmpMsg << (uint32_t)nVal; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - snprintf( tmpStr, 127, "Using msg n %d from group %d", nTxtID, nTxtGroupID ); - textMsg = tmpStr; - - source->SendUDPMessage( tmpMsg ); - tmpMsg = NULL; - } - else if ( Arg1[0] == 'e' ) - { - targetObjectId = 1004; //target=int - uint16_t nval = 5; - uint8_t nType = 1; // 1=+ 2=- - uint16_t nDur = 20; - uint8_t nparam = 1; - - nparam = GetArgInt( 2 ) & 0xff; - - tmpMsg = new PMessage( 32 ); - - source->IncreaseUDP_ID(); - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint16_t )source->GetSessionID(); - *tmpMsg << ( uint8_t )0x0e; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )source->GetLocalID(); - *tmpMsg << ( uint8_t )0x25; // ?? - *tmpMsg << ( uint8_t )0x06; // ?? - *tmpMsg << ( uint8_t )0x01; // 1 effect - *tmpMsg << ( uint8_t )0x01; // effect on intox level ???? - *tmpMsg << ( uint16_t )nDur; - *tmpMsg << ( uint16_t )(700+(targetObjectId % 100)); //item id Thyronol - *tmpMsg << ( uint8_t )nType; - *tmpMsg << ( uint16_t )(nval*100); //uint32_t in nc2.2 - *tmpMsg << ( uint16_t )targetObjectId; - - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - snprintf( tmpStr, 127, "Sendind drug mod to stat %d, %s %d", targetObjectId, (nType == 1 ? "inc" : "dec"), nval ); - textMsg = tmpStr; - - source->SendUDPMessage( tmpMsg ); - tmpMsg = NULL; - } - else if ( Arg1[0] == 'w' ) - { - /*targetObjectId &= 0xffff; - uint16_t val1 = 0; - if ( ArgC >= 3 ) - val1 = GetArgInt( 3 ) & 0xffff; -*/ - tmpMsg = new PMessage( 15 ); - - source->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint16_t )source->GetSessionID(); - *tmpMsg << ( uint8_t )0x0a; // Message length place; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )source->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x23; - *tmpMsg << ( uint16_t )0x0012; // cmd = ? - *tmpMsg << ( uint16_t )0x0007; - *tmpMsg << ( uint32_t )0x00000000; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - snprintf( tmpStr, 127, "Sending w msg " ); - textMsg = tmpStr; - - source->SendUDPMessage( tmpMsg ); - tmpMsg = NULL; - } - else if ( Arg1[0] == 'x' ) - { - uint8_t val1 = targetObjectId &= 0xff; - - tmpMsg = MsgBuilder->BuildUndefineduseMsg( source, val1 ); - - snprintf( tmpStr, 127, "Sending x msg with param %d (0x%2x)", val1, val1 ); - textMsg = tmpStr; - - source->SendUDPMessage( tmpMsg ); - tmpMsg = NULL; - } - } - - tmpStr[127] = '\0'; - Chat->send( source, CHAT_DIRECT, "System", textMsg ); - - if ( tmpMsg ) - ClientManager->UDPBroadcast( tmpMsg, source ); -} - -/*** Packet fields testing. Please do not delete (Hammag) -void PCommands::doCmd_dev_t() -{ - if(IsAdmin() == false) - return; - - char Arg1[30], Arg2[30]; - - Arg1[0] = '\0'; - Arg2[0] = '\0'; - - if(ArgC > 0) - { - GetArgText(1, Arg1, 30); - if(ArgC > 1) - { - GetArgText(2, Arg2, 30); - } - } - - uint32_t val1; - uint8_t val2; - char tmpStr[128]; - static PMessage* tmpMsg = NULL; - bool SetUDP_IDNeeded = true; - PChar* nChar = source->GetChar(); - (nChar->Coords).mY += 20; - (nChar->Coords).mZ += 20; - (nChar->Coords).mX += 20; - - if (!tmpMsg) - { - tmpMsg = MsgBuilder->BuildPacket0Msg(source); - //tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - SetUDP_IDNeeded = false; - } - - if(Arg1[0] != '\0' && Arg2[0] != '\0') - { - val1 = atoi(Arg1); - val2 = (uint8_t)(atoi(Arg2) & 0xff); - //tmpMsg->U8Data(16 + val1) = val2; - tmpMsg->U8Data(10 + val1) = val2; - snprintf(tmpStr, 127, "Data #%d set to value 0x%02x", val1, val2); - } - else - { - if (tmpMsg) - delete tmpMsg; - //tmpMsg = MsgBuilder->BuildCharHelloMsg(source); - tmpMsg = MsgBuilder->BuildPacket0Msg(source); - SetUDP_IDNeeded = false; - snprintf(tmpStr, 127, "Data reset to normal values"); - } - - tmpStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpStr); - - PMessage* SendMsg = new PMessage(*tmpMsg); - if(SetUDP_IDNeeded) { - source->FillInUDP_ID(SendMsg); - } - SendMsg->Dump(); - //ClientManager->UDPBroadcast(SendMsg, source); - source->SendUDPMessage(SendMsg); -} -***/ - -/*** Subwy testing. Please do not delete (Hammag) -void PCommands::doCmd_dev_t() -{ - if(IsAdmin() == false) - return; - - char tmpStr[128]; - uint8_t SubWay[] = {0x13, 0x71, 0x00, 0x9b, 0xde, - //Subway 1 (fc 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfc, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xfc, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 2 (fb 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfb, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xf0, 0x41, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xfb, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 3 (fa 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfa, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x70, 0x42, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xfa, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 4 (f9 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf9, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb4, 0x42, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf9, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 5 (f8 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf8, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xf0, 0x42, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf8, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 6 (f7 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf7, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x16, 0x43, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf7, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00}; - - uint8_t SubWay2[] = {0x13, 0x71, 0x00, 0x9b, 0xde, - //Subway 7 (f6 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf6, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x34, 0x43, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf6, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 8 (f5 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf5, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x52, 0x43, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf5, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 9 (f4 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf4, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x70, 0x43, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf4, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 10 (f3 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf3, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x87, 0x43, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf3, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00, - //Subway 11 (f2 03) - 0x11, - 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf2, 0x03, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x96, 0x43, 0x00, 0x01, - 0x0d, - 0x03, 0x71, 0x00, 0x2d, 0xf2, 0x03, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x00}; - - if (source->GetChar()->GetLocation() != 1000) - return; - - //SubWay List - //Subway 1 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[7] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[25] = source->GetUDP_ID(); - - //Subway 2 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[39] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[57] = source->GetUDP_ID(); - - //Subway 3 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[71] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[89] = source->GetUDP_ID(); - - //Subway 4 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[103] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[121] = source->GetUDP_ID(); - - //Subway 5 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[135] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[153] = source->GetUDP_ID(); - - //Subway 6 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[167] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay[185] = source->GetUDP_ID(); - - //Subway 7 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[7] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[25] = source->GetUDP_ID(); - - //Subway 8 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[39] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[57] = source->GetUDP_ID(); - - //Subway 9 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[71] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[89] = source->GetUDP_ID(); - - //Subway 10 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[103] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[121] = source->GetUDP_ID(); - - //Subway 11 - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[135] = source->GetUDP_ID(); - source->IncreaseUDP_ID(); - *(uint16_t*)&SubWay2[153] = source->GetUDP_ID(); - - *(uint16_t*)&SubWay[1] = source->GetUDP_ID(); - *(uint16_t*)&SubWay[3] = source->GetSessionID(); - - PMessage* msg; - msg = new PMessage(197); - msg->Write(SubWay, sizeof(SubWay)); -Console->Print("---- Working 1 ----"); -msg->Dump(); - source->SendUDPMessage(msg); -msg = MsgBuilder->BuildSubwaySpawnMsg(source, false); -Console->Print("---- Not Working 1 ----"); -msg->Dump(); -source->SendUDPMessage(msg); - - *(uint16_t*)&SubWay2[1] = source->GetUDP_ID(); - *(uint16_t*)&SubWay2[3] = source->GetSessionID(); - - msg = new PMessage(197); - msg->Write(SubWay2, sizeof(SubWay2)); -Console->Print("---- Working 2 ----"); -msg->Dump(); - source->SendUDPMessage(msg); -msg = MsgBuilder->BuildSubwaySpawnMsg(source, true); -Console->Print("---- Not Working 2 ----"); -msg->Dump(); -source->SendUDPMessage(msg); - - snprintf(tmpStr, 127, "Initial subway data sent"); - tmpStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpStr); -} -***/ +#include +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmd_dev_t() +{ + const char* usage = "Usage: @t r (to remove object) | @t d [ []] (to send death packet to object with args v1 v2)"; + char tmpStr[128]; + const char* textMsg = usage; + PMessage* tmpMsg = NULL; + char Arg1[30]; + + if ( IsAdmin() == false ) + return; + + Arg1[0] = tmpStr[0] = '\0'; + + if ( ArgC >= 2 ) + { + GetArgText( 1, Arg1, 30 ); + uint32_t targetObjectId = GetArgInt( 2 ) & 0xffffffff; + if ( Arg1[0] == 't' ) + { + uint8_t val1; + if ( ArgC >= 3 ) + { + int val2 = GetArgInt( 3 ); + tmpMsg = new PMessage( 32 ); + source->IncreaseUDP_ID(); + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint16_t )source->GetSessionID(); + *tmpMsg << ( uint8_t )0x00; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x2d; + *tmpMsg << ( uint32_t )targetObjectId; + *tmpMsg << ( uint8_t )0x01; + *tmpMsg << ( uint32_t )val2; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + source->SendUDPMessage( tmpMsg ); + snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with values 6/%d", targetObjectId, val2 ); + textMsg = tmpStr; + } + else for(val1 = 2; val1 < 255; ++val1) + { + if(val1 == 6) continue; + tmpMsg = new PMessage( 15 ); + source->IncreaseUDP_ID(); + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint16_t )source->GetSessionID(); + *tmpMsg << ( uint8_t )0x00; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x2d; + *tmpMsg << ( uint32_t )targetObjectId; + *tmpMsg << ( uint8_t )val1; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + source->SendUDPMessage( tmpMsg ); + snprintf( tmpStr, 127, "Sent 13/03/2d msg to object id 0x%08x with value %d", targetObjectId, val1 ); + textMsg = tmpStr; + tmpStr[127] = '\0'; + Chat->send( source, CHAT_DIRECT, "System", textMsg ); + source->getUDPConn()->update(); + source->getTCPConn()->update(); + //sleep(1); + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + tmpMsg = NULL; + } + else if ( Arg1[0] == 'd' ) + { + uint8_t val1 = 0x4a; // default values + uint8_t val2 = 0x1e; + + if ( ArgC >= 3 ) + val1 = GetArgInt( 3 ) & 0xff; + if ( ArgC >= 4 ) + val2 = GetArgInt( 4 ) & 0xff; + tmpMsg = MsgBuilder->BuildNpcDeathMsg( source, targetObjectId, val1, val2 ); + snprintf( tmpStr, 127, "Sending Death update to object id 0x%08x with values 0x%02x 0x%02x", targetObjectId, val1, val2 ); + textMsg = tmpStr; + } + else if ( Arg1[0] == 'm' ) + { + uint8_t nTxtGroupID = targetObjectId & 0xff; + uint16_t nTxtID = 10; + //uint32_t nVal = 0; + if ( ArgC >= 3 ) + nTxtID = GetArgInt( 3 ) & 0xffff; + //if(ArgC >= 4) + // val2 = GetArgInt(4) & 0xff; + + tmpMsg = new PMessage( 20 ); + + source->IncreaseUDP_ID(); + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint16_t )source->GetSessionID(); + *tmpMsg << ( uint8_t )0x0e; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )source->GetLocalID(); + *tmpMsg << ( uint8_t )0x25; // ?? + *tmpMsg << ( uint8_t )0x15; // ?? + *tmpMsg << nTxtGroupID; + *tmpMsg << nTxtID; + *tmpMsg << ( uint16_t )0x00; // ?? + *tmpMsg << ( uint8_t )0x01; + *tmpMsg << ( uint8_t )0x04; + *tmpMsg << ( uint32_t )0x00; + //*tmpMsg << (uint8_t)0x00; // ?? + //*tmpMsg << (uint8_t)0x00; // ?? + //*tmpMsg << (uint32_t)nVal; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + snprintf( tmpStr, 127, "Using msg n %d from group %d", nTxtID, nTxtGroupID ); + textMsg = tmpStr; + + source->SendUDPMessage( tmpMsg ); + tmpMsg = NULL; + } + else if ( Arg1[0] == 'e' ) + { + targetObjectId = 1004; //target=int + uint16_t nval = 5; + uint8_t nType = 1; // 1=+ 2=- + uint16_t nDur = 20; + uint8_t nparam = 1; + + nparam = GetArgInt( 2 ) & 0xff; + + tmpMsg = new PMessage( 32 ); + + source->IncreaseUDP_ID(); + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint16_t )source->GetSessionID(); + *tmpMsg << ( uint8_t )0x0e; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )source->GetLocalID(); + *tmpMsg << ( uint8_t )0x25; // ?? + *tmpMsg << ( uint8_t )0x06; // ?? + *tmpMsg << ( uint8_t )0x01; // 1 effect + *tmpMsg << ( uint8_t )0x01; // effect on intox level ???? + *tmpMsg << ( uint16_t )nDur; + *tmpMsg << ( uint16_t )(700+(targetObjectId % 100)); //item id Thyronol + *tmpMsg << ( uint8_t )nType; + *tmpMsg << ( uint16_t )(nval*100); //uint32_t in nc2.2 + *tmpMsg << ( uint16_t )targetObjectId; + + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + snprintf( tmpStr, 127, "Sendind drug mod to stat %d, %s %d", targetObjectId, (nType == 1 ? "inc" : "dec"), nval ); + textMsg = tmpStr; + + source->SendUDPMessage( tmpMsg ); + tmpMsg = NULL; + } + else if ( Arg1[0] == 'w' ) + { + /*targetObjectId &= 0xffff; + uint16_t val1 = 0; + if ( ArgC >= 3 ) + val1 = GetArgInt( 3 ) & 0xffff; +*/ + tmpMsg = new PMessage( 15 ); + + source->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint16_t )source->GetSessionID(); + *tmpMsg << ( uint8_t )0x0a; // Message length place; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )source->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x23; + *tmpMsg << ( uint16_t )0x0012; // cmd = ? + *tmpMsg << ( uint16_t )0x0007; + *tmpMsg << ( uint32_t )0x00000000; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + snprintf( tmpStr, 127, "Sending w msg " ); + textMsg = tmpStr; + + source->SendUDPMessage( tmpMsg ); + tmpMsg = NULL; + } + else if ( Arg1[0] == 'x' ) + { + uint8_t val1 = targetObjectId &= 0xff; + + tmpMsg = MsgBuilder->BuildUndefineduseMsg( source, val1 ); + + snprintf( tmpStr, 127, "Sending x msg with param %d (0x%2x)", val1, val1 ); + textMsg = tmpStr; + + source->SendUDPMessage( tmpMsg ); + tmpMsg = NULL; + } + } + + tmpStr[127] = '\0'; + Chat->send( source, CHAT_DIRECT, "System", textMsg ); + + if ( tmpMsg ) + ClientManager->UDPBroadcast( tmpMsg, source ); +} + +/*** Packet fields testing. Please do not delete (Hammag) +void PCommands::doCmd_dev_t() +{ + if(IsAdmin() == false) + return; + + char Arg1[30], Arg2[30]; + + Arg1[0] = '\0'; + Arg2[0] = '\0'; + + if(ArgC > 0) + { + GetArgText(1, Arg1, 30); + if(ArgC > 1) + { + GetArgText(2, Arg2, 30); + } + } + + uint32_t val1; + uint8_t val2; + char tmpStr[128]; + static PMessage* tmpMsg = NULL; + bool SetUDP_IDNeeded = true; + PChar* nChar = source->GetChar(); + (nChar->Coords).mY += 20; + (nChar->Coords).mZ += 20; + (nChar->Coords).mX += 20; + + if (!tmpMsg) + { + tmpMsg = MsgBuilder->BuildPacket0Msg(source); + //tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + SetUDP_IDNeeded = false; + } + + if(Arg1[0] != '\0' && Arg2[0] != '\0') + { + val1 = atoi(Arg1); + val2 = (uint8_t)(atoi(Arg2) & 0xff); + //tmpMsg->U8Data(16 + val1) = val2; + tmpMsg->U8Data(10 + val1) = val2; + snprintf(tmpStr, 127, "Data #%d set to value 0x%02x", val1, val2); + } + else + { + if (tmpMsg) + delete tmpMsg; + //tmpMsg = MsgBuilder->BuildCharHelloMsg(source); + tmpMsg = MsgBuilder->BuildPacket0Msg(source); + SetUDP_IDNeeded = false; + snprintf(tmpStr, 127, "Data reset to normal values"); + } + + tmpStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpStr); + + PMessage* SendMsg = new PMessage(*tmpMsg); + if(SetUDP_IDNeeded) { + source->FillInUDP_ID(SendMsg); + } + SendMsg->Dump(); + //ClientManager->UDPBroadcast(SendMsg, source); + source->SendUDPMessage(SendMsg); +} +***/ + +/*** Subwy testing. Please do not delete (Hammag) +void PCommands::doCmd_dev_t() +{ + if(IsAdmin() == false) + return; + + char tmpStr[128]; + uint8_t SubWay[] = {0x13, 0x71, 0x00, 0x9b, 0xde, + //Subway 1 (fc 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfc, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xfc, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 2 (fb 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfb, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x41, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xfb, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 3 (fa 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xfa, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x42, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xfa, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 4 (f9 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf9, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb4, 0x42, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf9, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 5 (f8 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf8, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf0, 0x42, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf8, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 6 (f7 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf7, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x16, 0x43, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf7, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00}; + + uint8_t SubWay2[] = {0x13, 0x71, 0x00, 0x9b, 0xde, + //Subway 7 (f6 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf6, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x34, 0x43, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf6, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 8 (f5 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf5, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x52, 0x43, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf5, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 9 (f4 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf4, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x70, 0x43, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf4, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 10 (f3 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf3, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x87, 0x43, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf3, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00, + //Subway 11 (f2 03) + 0x11, + 0x03, 0x6d, 0x00, 0x28, 0x27, 0x00, 0xf2, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x96, 0x43, 0x00, 0x01, + 0x0d, + 0x03, 0x71, 0x00, 0x2d, 0xf2, 0x03, 0x00, 0x00, 0x0a, 0x00, + 0x00, 0x00, 0x00}; + + if (source->GetChar()->GetLocation() != 1000) + return; + + //SubWay List + //Subway 1 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[7] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[25] = source->GetUDP_ID(); + + //Subway 2 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[39] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[57] = source->GetUDP_ID(); + + //Subway 3 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[71] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[89] = source->GetUDP_ID(); + + //Subway 4 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[103] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[121] = source->GetUDP_ID(); + + //Subway 5 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[135] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[153] = source->GetUDP_ID(); + + //Subway 6 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[167] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay[185] = source->GetUDP_ID(); + + //Subway 7 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[7] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[25] = source->GetUDP_ID(); + + //Subway 8 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[39] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[57] = source->GetUDP_ID(); + + //Subway 9 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[71] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[89] = source->GetUDP_ID(); + + //Subway 10 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[103] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[121] = source->GetUDP_ID(); + + //Subway 11 + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[135] = source->GetUDP_ID(); + source->IncreaseUDP_ID(); + *(uint16_t*)&SubWay2[153] = source->GetUDP_ID(); + + *(uint16_t*)&SubWay[1] = source->GetUDP_ID(); + *(uint16_t*)&SubWay[3] = source->GetSessionID(); + + PMessage* msg; + msg = new PMessage(197); + msg->Write(SubWay, sizeof(SubWay)); +Console->Print("---- Working 1 ----"); +msg->Dump(); + source->SendUDPMessage(msg); +msg = MsgBuilder->BuildSubwaySpawnMsg(source, false); +Console->Print("---- Not Working 1 ----"); +msg->Dump(); +source->SendUDPMessage(msg); + + *(uint16_t*)&SubWay2[1] = source->GetUDP_ID(); + *(uint16_t*)&SubWay2[3] = source->GetSessionID(); + + msg = new PMessage(197); + msg->Write(SubWay2, sizeof(SubWay2)); +Console->Print("---- Working 2 ----"); +msg->Dump(); + source->SendUDPMessage(msg); +msg = MsgBuilder->BuildSubwaySpawnMsg(source, true); +Console->Print("---- Not Working 2 ----"); +msg->Dump(); +source->SendUDPMessage(msg); + + snprintf(tmpStr, 127, "Initial subway data sent"); + tmpStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpStr); +} +***/ diff --git a/TinNS/Source/GameServer/GameCommands/Test.cxx b/TinNS/Source/GameServer/GameCommands/Test.cxx index beaf4fe..8755110 100644 --- a/TinNS/Source/GameServer/GameCommands/Test.cxx +++ b/TinNS/Source/GameServer/GameCommands/Test.cxx @@ -3,59 +3,59 @@ void PCommands::doCmdtest() { - if (GetArgInt(1) == 1) - { - if(ArgC < 5) - return; - - PNPC* targetNPC = NULL; - PNPCWorld* currentNPCWorld = NULL; - currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() ); - if ( currentNPCWorld ) - { - targetNPC = currentNPCWorld->GetNPC( GetArgInt(2) ); - if(!targetNPC) - return; - // @test 15 - targetNPC->Attack(GetArgInt(3), (uint8_t)GetArgInt(5), (uint8_t)GetArgInt(4)); - } - } - else if (GetArgInt(1) == 2) - { - if(ArgC < 3) - return; - - int tF1 = GetArgInt(2); - int tF2 = GetArgInt(3); - const PDefFaction* tFactionA = NULL; - const PDefFaction* tFactionB = NULL; - - if(tF1 > tF2) - { - tFactionA = GameDefs->Factions()->GetDef(tF1); - tFactionB = GameDefs->Factions()->GetDef(tF2); - } - else - { - tFactionA = GameDefs->Factions()->GetDef(tF2); - tFactionB = GameDefs->Factions()->GetDef(tF1); - } - - if(tFactionA && tFactionB) - { - int tRel = -99; - if(tF1 > tF2) - tRel = tFactionA->GetRelation(tF2); - else - tRel = tFactionA->GetRelation(tF1); - - char buff[150]; - snprintf(buff, 150, "Relation between <%s> and <%s> is: %d", tFactionA->GetName().c_str(), tFactionB->GetName().c_str(), tRel); - Chat->send(source, CHAT_DIRECT, "Relations", buff); - } - else - Chat->send(source, CHAT_DIRECT, "Relations", "Invalid faction"); - } + if (GetArgInt(1) == 1) + { + if(ArgC < 5) + return; + + PNPC* targetNPC = NULL; + PNPCWorld* currentNPCWorld = NULL; + currentNPCWorld = NPCManager->GetWorld( source->GetChar()->GetLocation() ); + if ( currentNPCWorld ) + { + targetNPC = currentNPCWorld->GetNPC( GetArgInt(2) ); + if(!targetNPC) + return; + // @test 15 + targetNPC->Attack(GetArgInt(3), (uint8_t)GetArgInt(5), (uint8_t)GetArgInt(4)); + } + } + else if (GetArgInt(1) == 2) + { + if(ArgC < 3) + return; + + int tF1 = GetArgInt(2); + int tF2 = GetArgInt(3); + const PDefFaction* tFactionA = NULL; + const PDefFaction* tFactionB = NULL; + + if(tF1 > tF2) + { + tFactionA = GameDefs->Factions()->GetDef(tF1); + tFactionB = GameDefs->Factions()->GetDef(tF2); + } + else + { + tFactionA = GameDefs->Factions()->GetDef(tF2); + tFactionB = GameDefs->Factions()->GetDef(tF1); + } + + if(tFactionA && tFactionB) + { + int tRel = -99; + if(tF1 > tF2) + tRel = tFactionA->GetRelation(tF2); + else + tRel = tFactionA->GetRelation(tF1); + + char buff[150]; + snprintf(buff, 150, "Relation between <%s> and <%s> is: %d", tFactionA->GetName().c_str(), tFactionB->GetName().c_str(), tRel); + Chat->send(source, CHAT_DIRECT, "Relations", buff); + } + else + Chat->send(source, CHAT_DIRECT, "Relations", "Invalid faction"); + } diff --git a/TinNS/Source/GameServer/GameCommands/UnBan.cxx b/TinNS/Source/GameServer/GameCommands/UnBan.cxx index 4b83971..081c47c 100644 --- a/TinNS/Source/GameServer/GameCommands/UnBan.cxx +++ b/TinNS/Source/GameServer/GameCommands/UnBan.cxx @@ -1,6 +1,6 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdunban() -{ - Chat->send(source, CHAT_DIRECT, "System", "Unban is not yet possible, sorry."); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdunban() +{ + Chat->send(source, CHAT_DIRECT, "System", "Unban is not yet possible, sorry."); +} diff --git a/TinNS/Source/GameServer/GameCommands/UnShun.cxx b/TinNS/Source/GameServer/GameCommands/UnShun.cxx index 1754aeb..aa6ec77 100644 --- a/TinNS/Source/GameServer/GameCommands/UnShun.cxx +++ b/TinNS/Source/GameServer/GameCommands/UnShun.cxx @@ -1,56 +1,56 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmdunshun() -{ - bool SyntaxError = false; - if(ArgC < 1) - { - SyntaxError = true; - } - - if(SyntaxError == true) - { - Chat->send(source, CHAT_DIRECT, "Usage", "@shun "); - return; - } - - if(IsArgNumeric(1) == true) - { - target = GetClientByID(GetArgInt(1)); - } - else - { - char tmp_destNick[50]; - GetArgText(1, tmp_destNick, 50); - target = GetClientByNick(tmp_destNick); - } - - if(target == NULL) // If victim isnt found, return error - { - Chat->send(source, CHAT_DIRECT, "System", "No such player"); - return; - } - if(source->GetAccountLevel() <= target->GetAccountLevel()) - { - char tmpMsg[200]; - snprintf(tmpMsg, 199, "Cant unshun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); - tmpMsg[199] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg); - return; - } - if(target->GetChar()->IsShunned() == true) - { - target->GetChar()->SetShun(false); - - char tmpMsg_success[81]; - snprintf(tmpMsg_success, 80, "Successfully unshunned %s", target->GetChar()->GetName().c_str()); - tmpMsg_success[80] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success); - return; - } - else - { - Chat->send(source, CHAT_DIRECT, "System", "Player is not shunned"); - return; - } -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmdunshun() +{ + bool SyntaxError = false; + if(ArgC < 1) + { + SyntaxError = true; + } + + if(SyntaxError == true) + { + Chat->send(source, CHAT_DIRECT, "Usage", "@shun "); + return; + } + + if(IsArgNumeric(1) == true) + { + target = GetClientByID(GetArgInt(1)); + } + else + { + char tmp_destNick[50]; + GetArgText(1, tmp_destNick, 50); + target = GetClientByNick(tmp_destNick); + } + + if(target == NULL) // If victim isnt found, return error + { + Chat->send(source, CHAT_DIRECT, "System", "No such player"); + return; + } + if(source->GetAccountLevel() <= target->GetAccountLevel()) + { + char tmpMsg[200]; + snprintf(tmpMsg, 199, "Cant unshun %s, target level is higher or equal to yours!", Chars->GetChar(target->GetCharID())->GetName().c_str()); + tmpMsg[199] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg); + return; + } + if(target->GetChar()->IsShunned() == true) + { + target->GetChar()->SetShun(false); + + char tmpMsg_success[81]; + snprintf(tmpMsg_success, 80, "Successfully unshunned %s", target->GetChar()->GetName().c_str()); + tmpMsg_success[80] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpMsg_success); + return; + } + else + { + Chat->send(source, CHAT_DIRECT, "System", "Player is not shunned"); + return; + } +} diff --git a/TinNS/Source/GameServer/GameCommands/Uptime.cxx b/TinNS/Source/GameServer/GameCommands/Uptime.cxx index 281e369..479d036 100644 --- a/TinNS/Source/GameServer/GameCommands/Uptime.cxx +++ b/TinNS/Source/GameServer/GameCommands/Uptime.cxx @@ -1,134 +1,134 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmduptime() -{ - // get difference between var uptime and current time - time_t Uptime = GameServer->GetStartTime(); - uint32_t TimeDiff = std::time(NULL) - Uptime; - uint32_t UpYears = 0, UpMonths = 0, UpWeeks = 0, UpDays = 0, UpHours = 0, UpMinutes = 0, UpSeconds = 0; - char tmpY[21], tmpM[21], tmpW[21], tmpD[21], tmpH[21], tmpMi[21], tmpS[21]; - - // 1 min = 60 sec = 60 - // 1 hour = 60 * 60 sec = 3600 - // 1 day = 24 * 60 * 60 sec = 86400 - // 1 week = 7 * 24 * 60 * 60 sec = 604800 - // 1 month = 30 * 7 * 24 * 60 * 60 sec = 18144000 - // 1 year = 12 * 30 * 7 * 24 * 60 * 60 sec = 217728000 - - // Split Years - while(TimeDiff >= 217728000) - { - TimeDiff = TimeDiff - 217728000; - UpYears++; - } - - // Split Months - while(TimeDiff >= 18144000) - { - TimeDiff = TimeDiff - 18144000; - UpMonths++; - } - - // Split Weeks - while(TimeDiff >= 604800) - { - TimeDiff = TimeDiff - 604800; - UpWeeks++; - } - - // Split Days - while(TimeDiff >= 86400) - { - TimeDiff = TimeDiff - 86400; - UpDays++; - } - - // Split Hours - while(TimeDiff >= 3600) - { - TimeDiff = TimeDiff - 3600; - UpHours++; - } - - // Split Minutes - while(TimeDiff >= 60) - { - TimeDiff = TimeDiff - 60; - UpMinutes++; - } - - // What's left are seconds - UpSeconds = TimeDiff; - - // Now create output strings. Add 's' if > 1 - // Years - if(UpYears > 1) - snprintf(tmpY, 20, "%d years ", UpYears); - else if(UpYears > 0) - snprintf(tmpY, 20, "%d year ", UpYears); - else - tmpY[0] = '\0'; - - // Months - if(UpMonths > 1) - snprintf(tmpM, 20, "%d months ", UpMonths); - else if(UpMonths > 0) - snprintf(tmpM, 20, "%d month ", UpMonths); - else - tmpM[0] = '\0'; - - // Weeks - if(UpWeeks > 1) - snprintf(tmpW, 20, "%d weeks ", UpWeeks); - else if(UpWeeks > 0) - snprintf(tmpW, 20, "%d week ", UpWeeks); - else - tmpW[0] = '\0'; - - // Days - if(UpDays > 1) - snprintf(tmpD, 20, "%d days ", UpDays); - else if(UpDays > 0) - snprintf(tmpD, 20, "%d day ", UpDays); - else - tmpD[0] = '\0'; - - // Hours - if(UpHours > 1) - snprintf(tmpH, 20, "%d hours ", UpHours); - else if(UpHours > 0) - snprintf(tmpH, 20, "%d hour ", UpHours); - else - tmpH[0] = '\0'; - - // Minutes - if(UpMinutes > 1) - snprintf(tmpMi, 20, "%d minutes and ", UpMinutes); - else if(UpMinutes > 0) - snprintf(tmpMi, 20, "%d minute and ", UpMinutes); - else - tmpMi[0] = '\0'; - - // Seconds - if(UpSeconds > 1 || UpSeconds == 0) - snprintf(tmpS, 20, "%d seconds.", UpSeconds); - else - snprintf(tmpS, 20, "%d second.", UpSeconds); - - // Terminate all chars, just to be sure - tmpY[20] = '\0'; - tmpM[20] = '\0'; - tmpW[20] = '\0'; - tmpD[20] = '\0'; - tmpH[20] = '\0'; - tmpMi[20] = '\0'; - tmpS[20] = '\0'; - - //Copy the single msg's into one - char tmpChatMsg[300]; - snprintf(tmpChatMsg, 299, "The server has been running for %s%s%s%s%s%s%s", tmpY, tmpM, tmpW, tmpD, tmpH, tmpMi, tmpS); - tmpChatMsg[299] = '\0'; - - // Send it out - Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg); -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmduptime() +{ + // get difference between var uptime and current time + time_t Uptime = GameServer->GetStartTime(); + uint32_t TimeDiff = std::time(NULL) - Uptime; + uint32_t UpYears = 0, UpMonths = 0, UpWeeks = 0, UpDays = 0, UpHours = 0, UpMinutes = 0, UpSeconds = 0; + char tmpY[21], tmpM[21], tmpW[21], tmpD[21], tmpH[21], tmpMi[21], tmpS[21]; + + // 1 min = 60 sec = 60 + // 1 hour = 60 * 60 sec = 3600 + // 1 day = 24 * 60 * 60 sec = 86400 + // 1 week = 7 * 24 * 60 * 60 sec = 604800 + // 1 month = 30 * 7 * 24 * 60 * 60 sec = 18144000 + // 1 year = 12 * 30 * 7 * 24 * 60 * 60 sec = 217728000 + + // Split Years + while(TimeDiff >= 217728000) + { + TimeDiff = TimeDiff - 217728000; + UpYears++; + } + + // Split Months + while(TimeDiff >= 18144000) + { + TimeDiff = TimeDiff - 18144000; + UpMonths++; + } + + // Split Weeks + while(TimeDiff >= 604800) + { + TimeDiff = TimeDiff - 604800; + UpWeeks++; + } + + // Split Days + while(TimeDiff >= 86400) + { + TimeDiff = TimeDiff - 86400; + UpDays++; + } + + // Split Hours + while(TimeDiff >= 3600) + { + TimeDiff = TimeDiff - 3600; + UpHours++; + } + + // Split Minutes + while(TimeDiff >= 60) + { + TimeDiff = TimeDiff - 60; + UpMinutes++; + } + + // What's left are seconds + UpSeconds = TimeDiff; + + // Now create output strings. Add 's' if > 1 + // Years + if(UpYears > 1) + snprintf(tmpY, 20, "%d years ", UpYears); + else if(UpYears > 0) + snprintf(tmpY, 20, "%d year ", UpYears); + else + tmpY[0] = '\0'; + + // Months + if(UpMonths > 1) + snprintf(tmpM, 20, "%d months ", UpMonths); + else if(UpMonths > 0) + snprintf(tmpM, 20, "%d month ", UpMonths); + else + tmpM[0] = '\0'; + + // Weeks + if(UpWeeks > 1) + snprintf(tmpW, 20, "%d weeks ", UpWeeks); + else if(UpWeeks > 0) + snprintf(tmpW, 20, "%d week ", UpWeeks); + else + tmpW[0] = '\0'; + + // Days + if(UpDays > 1) + snprintf(tmpD, 20, "%d days ", UpDays); + else if(UpDays > 0) + snprintf(tmpD, 20, "%d day ", UpDays); + else + tmpD[0] = '\0'; + + // Hours + if(UpHours > 1) + snprintf(tmpH, 20, "%d hours ", UpHours); + else if(UpHours > 0) + snprintf(tmpH, 20, "%d hour ", UpHours); + else + tmpH[0] = '\0'; + + // Minutes + if(UpMinutes > 1) + snprintf(tmpMi, 20, "%d minutes and ", UpMinutes); + else if(UpMinutes > 0) + snprintf(tmpMi, 20, "%d minute and ", UpMinutes); + else + tmpMi[0] = '\0'; + + // Seconds + if(UpSeconds > 1 || UpSeconds == 0) + snprintf(tmpS, 20, "%d seconds.", UpSeconds); + else + snprintf(tmpS, 20, "%d second.", UpSeconds); + + // Terminate all chars, just to be sure + tmpY[20] = '\0'; + tmpM[20] = '\0'; + tmpW[20] = '\0'; + tmpD[20] = '\0'; + tmpH[20] = '\0'; + tmpMi[20] = '\0'; + tmpS[20] = '\0'; + + //Copy the single msg's into one + char tmpChatMsg[300]; + snprintf(tmpChatMsg, 299, "The server has been running for %s%s%s%s%s%s%s", tmpY, tmpM, tmpW, tmpD, tmpH, tmpMi, tmpS); + tmpChatMsg[299] = '\0'; + + // Send it out + Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg); +} diff --git a/TinNS/Source/GameServer/GameCommands/V.cxx b/TinNS/Source/GameServer/GameCommands/V.cxx index 4eea77b..4b375b6 100644 --- a/TinNS/Source/GameServer/GameCommands/V.cxx +++ b/TinNS/Source/GameServer/GameCommands/V.cxx @@ -1,46 +1,46 @@ -#include "GameServer/Includes.hxx" - -void PCommands::doCmd_dev_v() -{ - if(IsAdmin() == false) - return; - - char Arg1[30]; - - Arg1[0] = '\0'; - - if(ArgC > 0) - { - GetArgText(1, Arg1, 30); - } - - char tmpStr[128]; - int testmode = 1; // change here only for uint8_t/uint16_t/uint32_t testvalue use - - if(Arg1[0] != '\0') - { - switch(testmode) - { - case 0: source->testval8 = (uint8_t)(atoi(Arg1) & 0xff); break; - case 1: source->testval16 = (uint16_t)(atoi(Arg1) & 0xffff); break; - case 2: source->testval32 = (uint32_t)(atoi(Arg1) & 0xffffffff); break; - } - } - else - { - source->testval8 = 0; - source->testval16 = 0; - source->testval32 = 0; - } - - switch(testmode) - { - case 0: snprintf(tmpStr, 127, "Test value uint8_t set to 0x%02x (%d)", source->testval8, source->testval8); break; - case 1: snprintf(tmpStr, 127, "Test value uint16_t set to 0x%04x (%d)", source->testval16, source->testval16); break; - case 2: snprintf(tmpStr, 127, "Test value uint32_t set to 0x%08x (%d)", source->testval32, source->testval32); break; - default: tmpStr[0] = '\0'; - } - tmpStr[127] = '\0'; - Chat->send(source, CHAT_DIRECT, "System", tmpStr); - -} +#include "GameServer/Includes.hxx" + +void PCommands::doCmd_dev_v() +{ + if(IsAdmin() == false) + return; + + char Arg1[30]; + + Arg1[0] = '\0'; + + if(ArgC > 0) + { + GetArgText(1, Arg1, 30); + } + + char tmpStr[128]; + int testmode = 1; // change here only for uint8_t/uint16_t/uint32_t testvalue use + + if(Arg1[0] != '\0') + { + switch(testmode) + { + case 0: source->testval8 = (uint8_t)(atoi(Arg1) & 0xff); break; + case 1: source->testval16 = (uint16_t)(atoi(Arg1) & 0xffff); break; + case 2: source->testval32 = (uint32_t)(atoi(Arg1) & 0xffffffff); break; + } + } + else + { + source->testval8 = 0; + source->testval16 = 0; + source->testval32 = 0; + } + + switch(testmode) + { + case 0: snprintf(tmpStr, 127, "Test value uint8_t set to 0x%02x (%d)", source->testval8, source->testval8); break; + case 1: snprintf(tmpStr, 127, "Test value uint16_t set to 0x%04x (%d)", source->testval16, source->testval16); break; + case 2: snprintf(tmpStr, 127, "Test value uint32_t set to 0x%08x (%d)", source->testval32, source->testval32); break; + default: tmpStr[0] = '\0'; + } + tmpStr[127] = '\0'; + Chat->send(source, CHAT_DIRECT, "System", tmpStr); + +} diff --git a/TinNS/Source/GameServer/GameCommands/Version.cxx b/TinNS/Source/GameServer/GameCommands/Version.cxx index c694545..8b79309 100644 --- a/TinNS/Source/GameServer/GameCommands/Version.cxx +++ b/TinNS/Source/GameServer/GameCommands/Version.cxx @@ -1,11 +1,11 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -void PCommands::doCmdversion() -{ - char tmpChatMsg[300]; - snprintf(tmpChatMsg, 299, "You are on TinNS server %s runnig version %s - SVN Rev. %s", Config->GetOption("server_name").c_str(), ServerVersion, SVNRevision); - tmpChatMsg[299] = '\0'; - - Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +void PCommands::doCmdversion() +{ + char tmpChatMsg[300]; + snprintf(tmpChatMsg, 299, "You are on TinNS server %s runnig version %s - SVN Rev. %s", Config->GetOption("server_name").c_str(), ServerVersion, SVNRevision); + tmpChatMsg[299] = '\0'; + + Chat->send(source, CHAT_DIRECT, "System", tmpChatMsg); +} diff --git a/TinNS/Source/GameServer/GameScript.cxx b/TinNS/Source/GameServer/GameScript.cxx index e16caa7..6cd26e7 100644 --- a/TinNS/Source/GameServer/GameScript.cxx +++ b/TinNS/Source/GameServer/GameScript.cxx @@ -1,105 +1,105 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -#if 0 -PGameScript::PGameScript() -{ -} - -PGameScript::~PGameScript() -{ - for(HookMap::iterator it = mHooks.begin(); it != mHooks.end(); it++) - delete it->second; -} - -bool PGameScript::LoadScripts() -{ -} - -bool PGameScript::Rehash() -{ - Console->LPrint("Rehashing GameMonkey Scripts..."); - for(HookMap::iterator it = mHooks.end(); it != mHooks.begin(); it--) - mHooks.erase(it); - - if(LoadScripts() == true) - { - Console->LPrint(GREEN, BLACK, "Done"); - Console->LClose(); - return true; - } - else - { - Console->LPrint(RED, BLACK, "Failed"); - Console->LClose(); - return false; - } -} - -void PGameScript::TriggerHook(PHookTypes hook) -{ -} - - -bool PGameScript::ExecuteFile(const char* a_fileName) -{ - FILE* scriptFile = NULL; - char* fileString = NULL; - int fileSize = 0; - - GM_ASSERT(m_machine); - - if( !(scriptFile = fopen(a_fileName, "rb")) ) - { - return false; - } - - fseek(scriptFile, 0, SEEK_END); - fileSize = ftell(scriptFile); - fseek(scriptFile, 0, SEEK_SET); - fileString = new char [fileSize+1]; - fread(fileString, fileSize, 1, scriptFile); - fileString[fileSize] = 0; // Terminating null - fclose(scriptFile); - - int threadId = GM_INVALID_THREAD; - int errors = m_machine->ExecuteString(fileString, &threadId, true, a_fileName); - if(errors) - { - LogAnyMachineErrorMessages(); - } - - delete [] fileString; - - return true; -} - - -int GM_CDECL PGameScript::AddHook(gmThread *a_thread) -{ - GM_CHECK_NUM_PARAMS(2); - GM_CHECK_STRING_PARAM(tmphooktype, 0); - GM_CHECK_STRING_PARAM(tmpfunction, 1); - - mHooks.insert(std::make_pair(tmphooktype, tmpfunction)); - - return GM_OK; -} - -int PGameScript::AddTwoIntegers(int valueA, int valueB) -{ - int resultInt = 0; - - gmCall call; - - if(call.BeginGlobalFunction(&machine, "Add")) - { - call.AddParamInt(valueA); - call.AddParamInt(valueB); - call.End(); - call.GetReturnedInt(resultInt); - } - - return resultInt; -} -#endif +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +#if 0 +PGameScript::PGameScript() +{ +} + +PGameScript::~PGameScript() +{ + for(HookMap::iterator it = mHooks.begin(); it != mHooks.end(); it++) + delete it->second; +} + +bool PGameScript::LoadScripts() +{ +} + +bool PGameScript::Rehash() +{ + Console->LPrint("Rehashing GameMonkey Scripts..."); + for(HookMap::iterator it = mHooks.end(); it != mHooks.begin(); it--) + mHooks.erase(it); + + if(LoadScripts() == true) + { + Console->LPrint(GREEN, BLACK, "Done"); + Console->LClose(); + return true; + } + else + { + Console->LPrint(RED, BLACK, "Failed"); + Console->LClose(); + return false; + } +} + +void PGameScript::TriggerHook(PHookTypes hook) +{ +} + + +bool PGameScript::ExecuteFile(const char* a_fileName) +{ + FILE* scriptFile = NULL; + char* fileString = NULL; + int fileSize = 0; + + GM_ASSERT(m_machine); + + if( !(scriptFile = fopen(a_fileName, "rb")) ) + { + return false; + } + + fseek(scriptFile, 0, SEEK_END); + fileSize = ftell(scriptFile); + fseek(scriptFile, 0, SEEK_SET); + fileString = new char [fileSize+1]; + fread(fileString, fileSize, 1, scriptFile); + fileString[fileSize] = 0; // Terminating null + fclose(scriptFile); + + int threadId = GM_INVALID_THREAD; + int errors = m_machine->ExecuteString(fileString, &threadId, true, a_fileName); + if(errors) + { + LogAnyMachineErrorMessages(); + } + + delete [] fileString; + + return true; +} + + +int GM_CDECL PGameScript::AddHook(gmThread *a_thread) +{ + GM_CHECK_NUM_PARAMS(2); + GM_CHECK_STRING_PARAM(tmphooktype, 0); + GM_CHECK_STRING_PARAM(tmpfunction, 1); + + mHooks.insert(std::make_pair(tmphooktype, tmpfunction)); + + return GM_OK; +} + +int PGameScript::AddTwoIntegers(int valueA, int valueB) +{ + int resultInt = 0; + + gmCall call; + + if(call.BeginGlobalFunction(&machine, "Add")) + { + call.AddParamInt(valueA); + call.AddParamInt(valueB); + call.End(); + call.GetReturnedInt(resultInt); + } + + return resultInt; +} +#endif diff --git a/TinNS/Source/GameServer/GameScript.hxx b/TinNS/Source/GameServer/GameScript.hxx index 7df8946..89831b9 100644 --- a/TinNS/Source/GameServer/GameScript.hxx +++ b/TinNS/Source/GameServer/GameScript.hxx @@ -1,27 +1,27 @@ -#pragma once - -#if 0 -#include -#include - -enum PHookTypes { - HOOK_CHAT, - HOOK_TRADE, - HOOK_ZONE -}; - -class PGameScript { -private: - typedef std::map HookMap; - HookMap mHooks; - -public: - PGameScript(); - ~PGameScript(); - - bool LoadScripts(); - bool Rehash(); - void TriggerHook(PHookTypes hook); - bool ExecuteFile(const char* a_fileName); -}; -#endif +#pragma once + +#if 0 +#include +#include + +enum PHookTypes { + HOOK_CHAT, + HOOK_TRADE, + HOOK_ZONE +}; + +class PGameScript { +private: + typedef std::map HookMap; + HookMap mHooks; + +public: + PGameScript(); + ~PGameScript(); + + bool LoadScripts(); + bool Rehash(); + void TriggerHook(PHookTypes hook); + bool ExecuteFile(const char* a_fileName); +}; +#endif diff --git a/TinNS/Source/GameServer/GameServer.cxx b/TinNS/Source/GameServer/GameServer.cxx index 9fbc426..73ce9a4 100644 --- a/TinNS/Source/GameServer/GameServer.cxx +++ b/TinNS/Source/GameServer/GameServer.cxx @@ -1,971 +1,971 @@ -#include -#include "GameServer/Includes.hxx" -#include "GameServer/Decoder/Includes.hxx" -#include "Common/Includes.hxx" - -// TODO: -// - Deny login if char is already online (More information about the login procedure is necessary to do that) -// - Take main loop timeout setting from config file -// - Add Regex control to new char name validation -// - Add Check of Char offline (and unloaded) before deleting (from the char choosing i/f) if multiple login -// allowed for the same account -// - Check if adding to Client to Client manager shouldn't be done only one UDP connection done ? -// => Risk of sending UDP chat on non-socket ???? - -PGameServer::PGameServer() -{ - mServerStartupTime = std::time( NULL ); - mNumClients = 0; - MsgDecoder = new PUdpMsgDecoder(); -} - -PGameServer::~PGameServer() -{ - ServerSock->closeServer(); - delete MsgDecoder; -} - -void PGameServer::Start() -{ - uint16_t Port = Config->GetOptionInt( "gameserver_port" ); - Console->LPrint( "Starting gameserver on port %i...", Port ); - - if ( ServerSock->open( Port ) ) - { - Console->LPrint( GREEN, BLACK, "Success" ); - } - else - { - Console->LPrint( RED, BLACK, "Failed" ); - } - Console->LClose(); - ServerSock->settimeout( 0, 10000 ); - - SetGameTime(( 1000 / 10 )*3600*12 ); //Set initial time to 12:00 on 7 Jul 2789 - - // Init random generator - struct timespec tmpTime; - if ( !clock_gettime( CLOCK_REALTIME, &tmpTime ) ) - { - srandom(( uint32_t )tmpTime.tv_sec ); - InitRandom( tmpTime.tv_sec ); -//Console->Print("Initializing random generator. First value is %d", random()); - } - - if ( Config->GetOptionInt( "gameserver_udpport_max" ) - Config->GetOptionInt( "gameserver_udpport_min" ) + 1 < Config->GetOptionInt( "maxclients" ) ) - { - Console->Print( "%s UDP port range setting doesn't allow for the simultaneous max clients set in config", Console->ColorText( YELLOW, BLACK, "[Warning]" ) ); - } - -} - -void PGameServer::SetGameTime( uint32_t newtime ) -{ - if ( clock_gettime( CLOCK_REALTIME, &mStartTime ) ) - { - Console->Print( RED, BLACK, "[ERROR] Clock unavailable !!!" ); - perror( "clock_gettime CLOCK_REALTIME" ); - mStartTime.tv_sec = 0; - mStartTime.tv_nsec = 0; - } - mBaseGameTime = newtime; -} - -uint32_t PGameServer::GetGameTime() -{ - //const uint32_t TimeFactor = 375; - const uint32_t TimeFactor = 1000; - const uint32_t nsTimeFactor = 1000000000 / TimeFactor; - - struct timespec tmpTime; - - if ( mStartTime.tv_sec ) - { - clock_gettime( CLOCK_REALTIME, &tmpTime ); - return ( mBaseGameTime + (( tmpTime.tv_sec - mStartTime.tv_sec ) * TimeFactor ) + ( tmpTime.tv_nsec / nsTimeFactor ) - ( mStartTime.tv_nsec / nsTimeFactor ) ); - } - else - return 0; -} - -void PGameServer::Update() -{ - if ( ServerSock->newConnection() ) - { - int clid = Server->NewClient(); - if ( clid != -1 ) - { - Console->Print( GREEN, BLACK, "[Info] Gameserver: client [%i] connected", clid ); - PClient *Client = Server->GetClient( clid ); - if ( Client->getTCPConn() ) Console->Print( RED, BLACK, "WARNING: Client %d : TCP Socket NOT NULL before allocation.", Client->GetID() ); - ConnectionTCP* tcpConn = ServerSock->getTCPConnection(); - Client->setTCPConnection( tcpConn ); - - //ConnectionUDP* udpConn = ServerSock->getUDPConnection(); - //Client->setUDPConnection(udpConn); - - Console->Print( "Client address: %s", Client->GetAddress() ); - ++mNumClients; - - PGameState *state = new PGameState(); - ClientStates.insert( std::make_pair( Client, state ) ); - state->TCP.mState = PGameState::TCP::GS_CONNECTED; - - // add the new connected client to the global clientmanager for further use in chat, etc... - ClientManager->addClientToList( Client ); - } - else - { - Console->Print( YELLOW, BLACK, "[Notice] Gameserver: Client connection refused (server full?)" ); - } - } - - /*** temp check ***/ - for ( PClientMap::iterator it = ClientManager->getClientListBegin(); it != ClientManager->getClientListEnd(); it++ ) - { - if ( !it->second ) - { - Console->Print( RED, BLACK, "PANIC: NULL Client found in ClientManager Clients Map." ); - } - } - /*** end temp check ***/ - - for ( GameStateMap::iterator i = ClientStates.begin(); i != ClientStates.end(); ) - { - PClient *Client = i->first; - PGameState *State = i->second; - // node gets erased in FinalizeClient, increment iterator now - ++i; - if ( !ProcessClient( Client, State ) ) - FinalizeClient( Client, State ); - } -} - -bool PGameServer::HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize ) -{ - //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68}; - //PGameSocket *Socket = Client->GetGameSocket(); - - switch ( State->TCP.mState ) - { - case PGameState::TCP::GS_HANDSHAKE0 : - { - if ( PacketSize == 6 && *( uint16_t* )&Packet[3] == 0x0080 && Packet[5] == 0x78 ) - { - //FIXME: this packet seems to be unnecessary, - // although it appears in traffic dumps - // (causes clientside "Wrong protocol" errors) - - //Socket->Write(HANDSHAKE1A, 6); - State->TCP.mState = PGameState::TCP::GS_AUTHENTICATE; - } - else - { - Console->Print( YELLOW, BLACK, "[Notice] Gameserver protocol error (GS_HANDSHAKE0): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - return ( false ); - } - - break; - } - default: - { - break; - } - } - - return true; -} - -bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ) -{ - ConnectionTCP *Socket = Client->getTCPConn(); - - if ( PacketSize > 20 && *( uint16_t* )&Packet[3] == 0x8084 ) - { - // authentication method #1 - const uint8_t *Key = &Packet[5]; // password key - uint16_t ULen = *( uint16_t* ) & Packet[16]; // username length - uint16_t PLen = *( uint16_t* ) & Packet[18]; // password length - char *UserName = ( char* ) & Packet[20]; // account name - const uint8_t *PW = &Packet[20+ULen]; // encoded password - - // Safety controls - if ( 15 + ULen + PLen > PacketSize ) - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" ); - return false; - } - if ( strnlen( UserName, ULen ) == ULen ) - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" ); - return false; - } - - bool Failed = false; - - PAccount Account( UserName ); - if ( Account.GetID() == 0 ) - { - Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName ); - Failed = true; - } - else if ( !Account.Authenticate( PW, PLen, Key ) ) - { - Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName ); - Failed = true; - } - - if ( !Failed ) - { - Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName ); - if ( Account.GetLevel() == PAL_BANNED ) - { - Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName ); - // TODO: ban ip for an adjustable time span? - Failed = true; // player is banned - } - - if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER ) - { - if ( Server->GetNumClients() > Server->GetMaxClients() ) - { - Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName ); - Failed = true; // server full - } - } - } - - if ( Failed ) - { - // TODO: is this packet correct here? - uint8_t AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R', - 'R', 'O', 'R', 0 - }; - // TODO: send actual reason instead of ERROR - Socket->write( AUTHFAILED, 15 ); - FinalizeClientDelayed( Client, State ); - State->TCP.mState = PGameState::TCP::GS_UNKNOWN; - Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName ); - } - else - { - Client->LoggedIn( &Account ); - uint8_t AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - *( uint32_t* )&AUTHOK[5] = Account.GetID(); - Socket->write( AUTHOK, 28 ); - State->TCP.mState = PGameState::TCP::GS_GAMEDATA; - Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName ); - } - } - else if ( PacketSize > 29 && *( uint16_t* )&Packet[3] == 0x0183 ) - { - // authentication method #2, sent when game starts - const uint8_t *Key = &Packet[13]; // password key - uint16_t PLen = *( uint16_t* ) & Packet[25]; // password length - uint16_t ULen = *( uint16_t* ) & Packet[27]; // username length - char *UserName = ( char* ) & Packet[29]; // account name - const uint8_t *PW = &Packet[29+ULen]; // encoded password - - // Safety controls - if ( 24 + ULen + PLen > PacketSize ) - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" ); - return false; - } - if ( strnlen( UserName, ULen ) == ULen ) - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" ); - return false; - } - - bool Failed = false; - - PAccount Account( UserName ); - if ( Account.GetID() == 0 ) - { - Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName ); - Failed = true; - } - else if ( !Account.Authenticate( PW, PLen, Key ) ) - { - Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName ); - Failed = true; - } - - if ( !Failed ) - { - if ( Account.GetLevel() == PAL_BANNED ) - { - Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName ); - // TODO: ban ip for an adjustable time span? - Failed = true; // player is banned - } - - if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER ) - { - if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) ) - { - Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName ); - Failed = true; // server full for non-GM users - } - } - else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER ) - { - Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName ); - Failed = true; - } - else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() ) - { - Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) ); - Failed = true; - } - else if ( Server->GetNumClients() > Server->GetMaxClients() ) - { - Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName ); - Failed = true; // server full even for GM users - } - } - - - if ( !Failed ) - { - int value = *( uint32_t* ) & Packet[21];//i think here we must read uint32_t instead of uint8_t - uint32_t CharID = Account.GetCharIdBySlot( value ); - - if ( Chars->LoadChar( CharID ) ) - { - Client->SetCharID( CharID ); - } - else - { - Failed = true; - } - } - - if ( Failed ) // something strange happened - FinalizeClientDelayed( Client, State ); - else - { - Client->LoggedIn( &Account ); - /*uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - *(uint32_t*)&AUTHOK[5]=Account->GetID(); - Socket->Write(AUTHOK, 28);*/ - //Client->SetRemoteUDPAddr(*(uint32_t*)&Packet[5], *(uint16_t*)&Packet[9]); - State->TCP.mState = PGameState::TCP::GS_GETSTATUS; - Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( uint32_t* )&Packet[5], *( uint16_t* )&Packet[9] ); - Client->SetRemoteUDPPort( *( int* )&Packet[9] ); - } - } - else - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - return ( false ); - } - - return ( true ); -} - -bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet ) -{ - static const uint8_t GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a}; - ConnectionTCP *Socket = Client->getTCPConn(); - - if ( *( uint16_t* )&Packet[3] == 0x3787 ) - { - Socket->write( GAMEDATA, 5 ); - State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS; - } - else - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - return ( false ); - } - - return ( true ); -} - -bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet ) -{ - PAccount Account( Client->GetAccountID() ); - - if ( !Account.GetID() ) - return false; - - ConnectionTCP *Socket = Client->getTCPConn(); - - struct PCharList - { - uint16_t Unknown1; - uint16_t NumSlots; - uint16_t Unknown2; - } CharList; - - PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT]; - - const int CHARBASESIZE = 28; - - if ( *( uint16_t* )&Packet[3] == 0x8284 ) - { - CharList.NumSlots = MAX_CHARS_PER_ACCOUNT; - int NameLengths = 0; - - for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) - { - CharEntry[i].CharID = 0; - CharEntry[i].Type = 0; - CharEntry[i].Color0 = 0; - CharEntry[i].Location = 1; - CharEntry[i].Unknown1 = 0; - CharEntry[i].Head = 0; - CharEntry[i].Torso = 0; - CharEntry[i].Legs = 0; - CharEntry[i].Unknown3 = 1; - CharEntry[i].Unknown4 = 1; - CharEntry[i].Unknown5 = 1; - CharEntry[i].Unknown6 = 1; - CharEntry[i].Unknown7 = 1; - CharEntry[i].Unknown8 = 0; - CharEntry[i].Unknown9 = 0; - CharEntry[i].Unknown10 = 0; - CharEntry[i].Unknown11 = 0; - CharEntry[i].Unknown12 = 0; - - CharEntry[i].in_use = false; - } - - Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT ); - - for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) - { - if ( CharEntry[i].in_use ) - { - NameLengths += CharEntry[i].NameLen; - } - else - { - CharEntry[i].CharID = 0xffffffff; - CharEntry[i].NameLen = 0; - } - } - - uint8_t PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85}; - *( uint16_t* )&PacketHeader[1] = sizeof( uint16_t ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2; - Socket->write( PacketHeader, 5 ); - - CharList.Unknown1 = 0x0000; - CharList.Unknown2 = CHARBASESIZE; - Socket->write( CharList.Unknown1 ); - Socket->write( CharList.NumSlots ); - Socket->write( CharList.Unknown2 ); - - for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) - { - Socket->write( CharEntry[i].CharID ); - Socket->write( CharEntry[i].Type ); - Socket->write( CharEntry[i].Color0 ); - Socket->write( CharEntry[i].Unknown1 ); - Socket->write( CharEntry[i].Head ); - Socket->write( CharEntry[i].Torso ); - Socket->write( CharEntry[i].Legs ); - Socket->write( CharEntry[i].Location ); - Socket->write( CharEntry[i].NameLen ); - Socket->write( CharEntry[i].Unknown3 ); - Socket->write( CharEntry[i].Unknown4 ); - Socket->write( CharEntry[i].Unknown5 ); - Socket->write( CharEntry[i].Unknown6 ); - Socket->write( CharEntry[i].Unknown7 ); - Socket->write( CharEntry[i].Unknown8 ); - Socket->write( CharEntry[i].Unknown9 ); - Socket->write( CharEntry[i].Unknown10 ); - Socket->write( CharEntry[i].Unknown11 ); - Socket->write( CharEntry[i].Unknown12 ); - - if ( CharEntry[i].Name.length() > 0 ) - { - Socket->write( CharEntry[i].Name.c_str() ); - Socket->write(( uint8_t )0 ); - } - } - - State->TCP.mState = PGameState::TCP::GS_CHARLIST; - } - else - { - Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - return ( false ); - } - - return ( true ); -} - -bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ) -{ - static uint8_t Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0}; - ConnectionTCP *Socket = Client->getTCPConn(); - - if ( PacketSize > 9 && *( uint16_t* )&Packet[3] == 0x8284 ) - { - uint8_t Mode = Packet[9]; - - switch ( Mode ) - { - case 6: // request list - return ( HandleRequestChars( Client, State, Packet ) ); - - case 5: // validate name - { - if ( PacketSize < 31 ) - return ( false ); - - // check for valid name string - bool ValidString = false; - - for ( int i = 30; i < PacketSize; i++ ) - if ( Packet[i] == 0 ) - { - ValidString = true; - break; - } - - const char *Name = ( char* ) & Packet[30]; - if ( ValidString ) - { - ValidString = PChar::IsCharnameWellFormed( Name ); - } - - if ( ValidString ) - { - if ( Chars->CharExist( std::string( Name ) ) ) - { - ValidString = false; - } - } - - if ( ValidString ) - Answer[5] = 1; // ok - else - Answer[5] = 2; // 2..6 => 'char name already in use!' - - // Answer[5] = 0; // => 'unknown error' - Socket->write( Answer, 10 ); - return ( true ); - } - - case 3: // delete char - { - PAccount Acc( Client->GetAccountID() ); - uint8_t Num = Packet[PacketSize-1]; - - if ( Acc.GetID() ) - { - uint32_t CharID = Acc.GetCharIdBySlot( Num ); - - // Also check that char is out of game - if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) ) - { - char query[100]; - snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID ); - if ( MySQL->GameQuery( query ) ) - Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID ); - else - { - Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID ); - - snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID ); - if ( MySQL->GameQuery( query ) ) - Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID ); - - snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID ); - if ( MySQL->GameQuery( query ) ) - Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID ); - - snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID ); - if ( MySQL->GameQuery( query ) ) - Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID ); - - Appartements->DeleteCharAppartements( CharID ); - } - } - else - return false; - } - return ( true ); - } - - case 7: // create char - { - if ( PacketSize < 64 ) - return ( false ); - - uint32_t Slot = * ( uint32_t* ) & Packet[30]; - //uint32_t nClass =* (uint32_t*)&Packet[34]; // Not used - indirectly redundant with Profession - uint32_t Profession = * ( uint32_t* ) & Packet[38]; - uint32_t Gender = * ( uint32_t* ) & Packet[42]; - uint32_t Head = * ( uint32_t* ) & Packet[46]; - uint32_t Torso = * ( uint32_t* ) & Packet[50]; - uint32_t Legs = * ( uint32_t* ) & Packet[54]; - uint32_t Faction = * ( uint32_t* ) & Packet[58]; - uint8_t NameLen = Packet[62]; - uint8_t NZSNb = Packet[63]; - - char TempName[256]; - std::strncpy( TempName, ( const char* )&Packet[64], NameLen ); - TempName[NameLen] = 0; - - Answer[5] = 2; // return error if char creation fails - - if ( PChar::IsCharnameWellFormed( TempName ) ) - { - // check for already used char name - should not happen though - if ( ! Chars->CharExist( std::string( TempName ) ) ) - { - PAccount Acc( Client->GetAccountID() ); - PChar* nChar = new PChar(); - - if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction, - Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) ) - { - Answer[5] = 1; // return success - } - delete nChar; - } - } - - Socket->write( Answer, 10 ); - return ( true ); - } - } - } - else - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - - return ( false ); - } - - return true; -} - -bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet ) -{ - ConnectionTCP *Socket = Client->getTCPConn(); - - if ( *( uint16_t* )&Packet[3] == 0x3787 ) - { - static const uint8_t STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00}; - - Socket->write( STATUS, 9 ); - State->TCP.mState = PGameState::TCP::GS_GAMEINFO; - } - else - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - - return ( false ); - } - - return ( true ); -} - -bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet ) -{ -// Console->Print("Inside HandleGameInfo");//NEW added - - static uint8_t GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header - 0x00, 0x00, 0x00, 0x00, // account id - 0x00, 0x00, 0x00, 0x00, // char id - 0x00, 0x00, 0x00, 0x00, // udp ip - 0x00, 0x00, // udp port - 0x00, 0x00, 0x00, 0x00, // unknown - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, // session key - }; - - ConnectionTCP *Socket = Client->getTCPConn(); - - if ( *( uint16_t* )&Packet[3] == 0x3c87 ) - { - //int PortFix = Config->GetOptionInt("debug_mode"); - - ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() ); - Client->setUDPConnection( udpConn ); - if ( !udpConn ) - { - Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() ); - ClientDisconnected( Client ); - } - - uint16_t Port = Client->getUDPConn()->getPort(); - - if ( Port == 0 ) - Console->Print( RED, BLACK, "Client->OpenUDP() failed" ); - - - /* if(PortFix == 1) // removed, no more use - { - Port = Config->GetOptionInt("useudpport"); - Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!"); - }; */ - - uint32_t IP; - std::string IPServerString; -// use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0) - if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) ) - { - IPServerString = Config->GetOption( "server_nat_ip" ); - } - else // else client is "local" so use [server_ip] - { - IPServerString = Config->GetOption( "server_ip" ); - } - IP = IPStringToDWord( IPServerString.c_str() ); -//Console->Print("IP-1 %d", IP); - if ( IP == 0 ) - IP = 0x0100007f; -//Console->Print("IP-2 %d", IP); - *( uint32_t* )&GameInfo[13] = IP; - *( uint16_t* )&GameInfo[17] = Port; - Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port ); - - *( uint32_t* )&GameInfo[5] = Client->GetAccountID(); - *( uint32_t* )&GameInfo[9] = Client->GetCharID(); - Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() ); - - Socket->write( GameInfo, 31 ); - Socket->flushSendBuffer(); - - static const uint8_t READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00}; - Socket->write( READY, 7 ); - - State->TCP.mState = PGameState::TCP::GS_INGAME; - State->UDP.mState = PGameState::UDP::GUS_SYNC0; -//Console->Print("Sync Reset"); - Client->ResetTransactionID(); - - // Mark char as Online - PChar *Char = Client->GetChar(); - Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect - Client->ChangeCharLocation( Char->GetLocation(), true ); - - // hello-message from server.. - /* - std::string serverName = Config->GetOption("server_name"); - std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server."; - char* message = (char*) helloMessage.c_str(); - Chat->send(Client, CHAT_DIRECT, "System", message, false); - */ - - bool SendBC = false; - if ( Config->GetOptionInt( "broadcast_new" ) == 1 ) - { - if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 ) - { - if ( Client->GetAccountLevel() > PAL_REGPLAYER ) - SendBC = false; - else - SendBC = true; - } - else - { - SendBC = true; - } - } - if ( SendBC == true ) - { - std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName(); - std::string serverName = Config->GetOption( "server_name" ); - std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server."; - char* message = ( char* ) helloMessage.c_str(); - - Chat->sendOOCBroadcast( message ); - } - //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError())); - } - else - { - Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); - return ( false ); - } - - return ( true ); -} - -bool PGameServer::HandleGame( PClient *Client, PGameState *State ) -{ - //PGameSocket *Socket = Client->GetGameSocket(); - ConnectionUDP *UDPSocket = Client->getUDPConn(); - //Console->Print("Clientadress %s", Client->GetAddress()); - - //int Size = 0; - PMessage* NewMsg = UDPSocket->GetMessage(); - if ( NewMsg && NewMsg->GetSize() ) - { - - MsgDecoder->Init( NewMsg, Client, State ); // State used temporarily - do - { - if ( MsgDecoder->Analyse() ) - { - if ( gDevDebug && MsgDecoder->IsTraceKnownMsg() ) - Console->Print( "%s Client[%d] msg: %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), Client->GetID(), MsgDecoder->GetName().c_str() ); - - if ( MsgDecoder->IsActionReady() ) - { - MsgDecoder->DoAction(); - } - } - else if ( MsgDecoder->IsError() ) - { - Console->Print( YELLOW, BLACK, "[Info] Client[%d] Decoding error: %s", Client->GetID(), MsgDecoder->GetError().c_str() ); - } -// else if (MsgDecoder->GetState() == DECODE_UNKNOWN) - else if ( gDevDebug && ( MsgDecoder->GetState() == DECODE_UNKNOWN ) && MsgDecoder->IsTraceUnknownMsg() ) - { - Console->Print( "%s Client[%d] Unknown msg: %s", Console->ColorText( YELLOW, BLACK, "[Info]" ), Client->GetID(), MsgDecoder->GetName().c_str() ); - } - -// if (MsgDecoder->IsTraceDump()) - if ( gDevDebug && MsgDecoder->IsTraceDump() ) - { - MsgDecoder->DumpMsg(); - } - - } - while ( MsgDecoder->MoreSubMsg() ); - } - - if ( NewMsg ) - { - delete NewMsg; - } - - return ( true ); -} - -bool PGameServer::ProcessClient( PClient *Client, PGameState *State ) -{ - static const uint8_t HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66}; - - if ( !State ) - { - GameStateMap::iterator node = ClientStates.find( Client ); - if ( node == ClientStates.end() ) - return ( false ); - - State = node->second; - } - - ConnectionTCP *Socket = Client->getTCPConn(); - if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() ); - if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 ) - return ( false ); - - if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED ) - { - Socket->write( HANDSHAKE0A, 6 ); - State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0; - } - - if ( State->TCP.mState == PGameState::TCP::GS_INGAME ) - { - return ( HandleGame( Client, State ) ); - } - else - { - int PacketSize = 0; - const uint8_t *Packet = Socket->read( &PacketSize ); - - if ( PacketSize > 0 ) - { - switch ( State->TCP.mState ) - { - case PGameState::TCP::GS_HANDSHAKE0: - return ( HandleHandshake( State, Packet, PacketSize ) ); - - case PGameState::TCP::GS_AUTHENTICATE: - return ( HandleAuthenticate( Client, State, Packet, PacketSize ) ); - - case PGameState::TCP::GS_GAMEDATA: - return ( HandleGameData( Client, State, Packet ) ); - - case PGameState::TCP::GS_REQUESTCHARS: - return ( HandleRequestChars( Client, State, Packet ) ); - - case PGameState::TCP::GS_CHARLIST: - return ( HandleCharList( Client, State, Packet, PacketSize ) ); - - case PGameState::TCP::GS_GETSTATUS: - return ( HandleGetStatus( Client, State, Packet ) ); - - case PGameState::TCP::GS_GAMEINFO: - return ( HandleGameInfo( Client, State, Packet ) ); - default: - break; - } - } - } - - return ( true ); -} - -void PGameServer::ClientDisconnected( PClient *Client ) -{ - GameStateMap::iterator node = ClientStates.find( Client ); - - if ( node == ClientStates.end() ) - return; - - PGameState *State = node->second; - FinalizeClient( Client, State ); -} - -void PGameServer::UDPStreamClosed( PClient *Client ) -{ - GameStateMap::iterator node = ClientStates.find( Client ); - - if ( node == ClientStates.end() ) - return; - - PGameState *State = node->second; - FinalizeClient( Client, State ); -} - -void PGameServer::FinalizeClient( PClient *Client, PGameState *State ) -{ - Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s disconnected", Client->GetAddress() ); - - // Isnt working somehow. I assume that mID and mAccount is deleted already. - // Mark char as Offline - //PChar *Char = Chars->GetChar(Client->GetCharID()); - //Char->SetOnlineStatus(false); - - // delete client from clientmanager list => Do it before we remove network access - ClientManager->deleteClientFromList( Client->GetLocalID() ); - - Client->GameDisconnect(); - ClientStates.erase( Client ); - delete State; - --mNumClients; - -} - -void PGameServer::FinalizeClientDelayed( PClient *Client, PGameState *State ) -{ - Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s is about to be disconnected", Client->GetAddress() ); - State->TCP.mWaitSend = true; -} - -PGameState* PGameServer::GetClientState( PClient* nClient ) -{ - GameStateMap::iterator node = ClientStates.find( nClient ); - - if ( node == ClientStates.end() ) - return NULL; - else - return node->second; -} +#include +#include "GameServer/Includes.hxx" +#include "GameServer/Decoder/Includes.hxx" +#include "Common/Includes.hxx" + +// TODO: +// - Deny login if char is already online (More information about the login procedure is necessary to do that) +// - Take main loop timeout setting from config file +// - Add Regex control to new char name validation +// - Add Check of Char offline (and unloaded) before deleting (from the char choosing i/f) if multiple login +// allowed for the same account +// - Check if adding to Client to Client manager shouldn't be done only one UDP connection done ? +// => Risk of sending UDP chat on non-socket ???? + +PGameServer::PGameServer() +{ + mServerStartupTime = std::time( NULL ); + mNumClients = 0; + MsgDecoder = new PUdpMsgDecoder(); +} + +PGameServer::~PGameServer() +{ + ServerSock->closeServer(); + delete MsgDecoder; +} + +void PGameServer::Start() +{ + uint16_t Port = Config->GetOptionInt( "gameserver_port" ); + Console->LPrint( "Starting gameserver on port %i...", Port ); + + if ( ServerSock->open( Port ) ) + { + Console->LPrint( GREEN, BLACK, "Success" ); + } + else + { + Console->LPrint( RED, BLACK, "Failed" ); + } + Console->LClose(); + ServerSock->settimeout( 0, 10000 ); + + SetGameTime(( 1000 / 10 )*3600*12 ); //Set initial time to 12:00 on 7 Jul 2789 + + // Init random generator + struct timespec tmpTime; + if ( !clock_gettime( CLOCK_REALTIME, &tmpTime ) ) + { + srandom(( uint32_t )tmpTime.tv_sec ); + InitRandom( tmpTime.tv_sec ); +//Console->Print("Initializing random generator. First value is %d", random()); + } + + if ( Config->GetOptionInt( "gameserver_udpport_max" ) - Config->GetOptionInt( "gameserver_udpport_min" ) + 1 < Config->GetOptionInt( "maxclients" ) ) + { + Console->Print( "%s UDP port range setting doesn't allow for the simultaneous max clients set in config", Console->ColorText( YELLOW, BLACK, "[Warning]" ) ); + } + +} + +void PGameServer::SetGameTime( uint32_t newtime ) +{ + if ( clock_gettime( CLOCK_REALTIME, &mStartTime ) ) + { + Console->Print( RED, BLACK, "[ERROR] Clock unavailable !!!" ); + perror( "clock_gettime CLOCK_REALTIME" ); + mStartTime.tv_sec = 0; + mStartTime.tv_nsec = 0; + } + mBaseGameTime = newtime; +} + +uint32_t PGameServer::GetGameTime() +{ + //const uint32_t TimeFactor = 375; + const uint32_t TimeFactor = 1000; + const uint32_t nsTimeFactor = 1000000000 / TimeFactor; + + struct timespec tmpTime; + + if ( mStartTime.tv_sec ) + { + clock_gettime( CLOCK_REALTIME, &tmpTime ); + return ( mBaseGameTime + (( tmpTime.tv_sec - mStartTime.tv_sec ) * TimeFactor ) + ( tmpTime.tv_nsec / nsTimeFactor ) - ( mStartTime.tv_nsec / nsTimeFactor ) ); + } + else + return 0; +} + +void PGameServer::Update() +{ + if ( ServerSock->newConnection() ) + { + int clid = Server->NewClient(); + if ( clid != -1 ) + { + Console->Print( GREEN, BLACK, "[Info] Gameserver: client [%i] connected", clid ); + PClient *Client = Server->GetClient( clid ); + if ( Client->getTCPConn() ) Console->Print( RED, BLACK, "WARNING: Client %d : TCP Socket NOT NULL before allocation.", Client->GetID() ); + ConnectionTCP* tcpConn = ServerSock->getTCPConnection(); + Client->setTCPConnection( tcpConn ); + + //ConnectionUDP* udpConn = ServerSock->getUDPConnection(); + //Client->setUDPConnection(udpConn); + + Console->Print( "Client address: %s", Client->GetAddress() ); + ++mNumClients; + + PGameState *state = new PGameState(); + ClientStates.insert( std::make_pair( Client, state ) ); + state->TCP.mState = PGameState::TCP::GS_CONNECTED; + + // add the new connected client to the global clientmanager for further use in chat, etc... + ClientManager->addClientToList( Client ); + } + else + { + Console->Print( YELLOW, BLACK, "[Notice] Gameserver: Client connection refused (server full?)" ); + } + } + + /*** temp check ***/ + for ( PClientMap::iterator it = ClientManager->getClientListBegin(); it != ClientManager->getClientListEnd(); it++ ) + { + if ( !it->second ) + { + Console->Print( RED, BLACK, "PANIC: NULL Client found in ClientManager Clients Map." ); + } + } + /*** end temp check ***/ + + for ( GameStateMap::iterator i = ClientStates.begin(); i != ClientStates.end(); ) + { + PClient *Client = i->first; + PGameState *State = i->second; + // node gets erased in FinalizeClient, increment iterator now + ++i; + if ( !ProcessClient( Client, State ) ) + FinalizeClient( Client, State ); + } +} + +bool PGameServer::HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize ) +{ + //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68}; + //PGameSocket *Socket = Client->GetGameSocket(); + + switch ( State->TCP.mState ) + { + case PGameState::TCP::GS_HANDSHAKE0 : + { + if ( PacketSize == 6 && *( uint16_t* )&Packet[3] == 0x0080 && Packet[5] == 0x78 ) + { + //FIXME: this packet seems to be unnecessary, + // although it appears in traffic dumps + // (causes clientside "Wrong protocol" errors) + + //Socket->Write(HANDSHAKE1A, 6); + State->TCP.mState = PGameState::TCP::GS_AUTHENTICATE; + } + else + { + Console->Print( YELLOW, BLACK, "[Notice] Gameserver protocol error (GS_HANDSHAKE0): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + return ( false ); + } + + break; + } + default: + { + break; + } + } + + return true; +} + +bool PGameServer::HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ) +{ + ConnectionTCP *Socket = Client->getTCPConn(); + + if ( PacketSize > 20 && *( uint16_t* )&Packet[3] == 0x8084 ) + { + // authentication method #1 + const uint8_t *Key = &Packet[5]; // password key + uint16_t ULen = *( uint16_t* ) & Packet[16]; // username length + uint16_t PLen = *( uint16_t* ) & Packet[18]; // password length + char *UserName = ( char* ) & Packet[20]; // account name + const uint8_t *PW = &Packet[20+ULen]; // encoded password + + // Safety controls + if ( 15 + ULen + PLen > PacketSize ) + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" ); + return false; + } + if ( strnlen( UserName, ULen ) == ULen ) + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" ); + return false; + } + + bool Failed = false; + + PAccount Account( UserName ); + if ( Account.GetID() == 0 ) + { + Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName ); + Failed = true; + } + else if ( !Account.Authenticate( PW, PLen, Key ) ) + { + Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName ); + Failed = true; + } + + if ( !Failed ) + { + Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' authentication successful", UserName ); + if ( Account.GetLevel() == PAL_BANNED ) + { + Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName ); + // TODO: ban ip for an adjustable time span? + Failed = true; // player is banned + } + + if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER ) + { + if ( Server->GetNumClients() > Server->GetMaxClients() ) + { + Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from user '%s'", UserName ); + Failed = true; // server full + } + } + } + + if ( Failed ) + { + // TODO: is this packet correct here? + uint8_t AUTHFAILED[15] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00, 'E', 'R', + 'R', 'O', 'R', 0 + }; + // TODO: send actual reason instead of ERROR + Socket->write( AUTHFAILED, 15 ); + FinalizeClientDelayed( Client, State ); + State->TCP.mState = PGameState::TCP::GS_UNKNOWN; + Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s' login refused", UserName ); + } + else + { + Client->LoggedIn( &Account ); + uint8_t AUTHOK[28] = {0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + *( uint32_t* )&AUTHOK[5] = Account.GetID(); + Socket->write( AUTHOK, 28 ); + State->TCP.mState = PGameState::TCP::GS_GAMEDATA; + Console->Print( GREEN, BLACK, "[Info] Gameserver: User '%s' logged in", UserName ); + } + } + else if ( PacketSize > 29 && *( uint16_t* )&Packet[3] == 0x0183 ) + { + // authentication method #2, sent when game starts + const uint8_t *Key = &Packet[13]; // password key + uint16_t PLen = *( uint16_t* ) & Packet[25]; // password length + uint16_t ULen = *( uint16_t* ) & Packet[27]; // username length + char *UserName = ( char* ) & Packet[29]; // account name + const uint8_t *PW = &Packet[29+ULen]; // encoded password + + // Safety controls + if ( 24 + ULen + PLen > PacketSize ) + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): Exessive internal size fields" ); + return false; + } + if ( strnlen( UserName, ULen ) == ULen ) + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): non-terminated username field" ); + return false; + } + + bool Failed = false; + + PAccount Account( UserName ); + if ( Account.GetID() == 0 ) + { + Console->Print( YELLOW, BLACK, "[Info] Gameserver: Unknown user %s", UserName ); + Failed = true; + } + else if ( !Account.Authenticate( PW, PLen, Key ) ) + { + Console->Print( YELLOW, BLACK, "[Info] Gameserver: User '%s': authentication failed", UserName ); + Failed = true; + } + + if ( !Failed ) + { + if ( Account.GetLevel() == PAL_BANNED ) + { + Console->Print( YELLOW, BLACK, "[Info] User %s is banned, connection refused", UserName ); + // TODO: ban ip for an adjustable time span? + Failed = true; // player is banned + } + + if ( Account.GetLevel() == PAL_UNREGPLAYER || Account.GetLevel() == PAL_REGPLAYER ) + { + if ( Server->GetNumClients() > ( Server->GetMaxClients() - Server->GetGMSlots() ) ) + { + Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from regular user '%s'", UserName ); + Failed = true; // server full for non-GM users + } + } + else if ( Config->GetOptionInt( "require_validation" ) == 1 && Account.GetLevel() == PAL_UNREGPLAYER ) + { + Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', account not activated yet", UserName ); + Failed = true; + } + else if ( Config->GetOptionInt( "minlevel" ) > Account.GetLevel() ) + { + Console->Print( YELLOW, BLACK, "[Info] Rejecting connection from regular user '%s', insufficient level %d vs %d required", UserName, Account.GetLevel(), Config->GetOptionInt( "minlevel" ) ); + Failed = true; + } + else if ( Server->GetNumClients() > Server->GetMaxClients() ) + { + Console->Print( YELLOW, BLACK, "[Info] Server full, refusing connection from privileged user '%s'", UserName ); + Failed = true; // server full even for GM users + } + } + + + if ( !Failed ) + { + int value = *( uint32_t* ) & Packet[21];//i think here we must read uint32_t instead of uint8_t + uint32_t CharID = Account.GetCharIdBySlot( value ); + + if ( Chars->LoadChar( CharID ) ) + { + Client->SetCharID( CharID ); + } + else + { + Failed = true; + } + } + + if ( Failed ) // something strange happened + FinalizeClientDelayed( Client, State ); + else + { + Client->LoggedIn( &Account ); + /*uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + *(uint32_t*)&AUTHOK[5]=Account->GetID(); + Socket->Write(AUTHOK, 28);*/ + //Client->SetRemoteUDPAddr(*(uint32_t*)&Packet[5], *(uint16_t*)&Packet[9]); + State->TCP.mState = PGameState::TCP::GS_GETSTATUS; + Console->Print( "Gameserver: User '%s' entered game (%08x:%04x)", UserName, *( uint32_t* )&Packet[5], *( uint16_t* )&Packet[9] ); + Client->SetRemoteUDPPort( *( int* )&Packet[9] ); + } + } + else + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_AUTHENTICATE): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + return ( false ); + } + + return ( true ); +} + +bool PGameServer::HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet ) +{ + static const uint8_t GAMEDATA[5] = {0xfe, 0x02, 0x00, 0x87, 0x3a}; + ConnectionTCP *Socket = Client->getTCPConn(); + + if ( *( uint16_t* )&Packet[3] == 0x3787 ) + { + Socket->write( GAMEDATA, 5 ); + State->TCP.mState = PGameState::TCP::GS_REQUESTCHARS; + } + else + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEDATA): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + return ( false ); + } + + return ( true ); +} + +bool PGameServer::HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet ) +{ + PAccount Account( Client->GetAccountID() ); + + if ( !Account.GetID() ) + return false; + + ConnectionTCP *Socket = Client->getTCPConn(); + + struct PCharList + { + uint16_t Unknown1; + uint16_t NumSlots; + uint16_t Unknown2; + } CharList; + + PCharProfile CharEntry[MAX_CHARS_PER_ACCOUNT]; + + const int CHARBASESIZE = 28; + + if ( *( uint16_t* )&Packet[3] == 0x8284 ) + { + CharList.NumSlots = MAX_CHARS_PER_ACCOUNT; + int NameLengths = 0; + + for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) + { + CharEntry[i].CharID = 0; + CharEntry[i].Type = 0; + CharEntry[i].Color0 = 0; + CharEntry[i].Location = 1; + CharEntry[i].Unknown1 = 0; + CharEntry[i].Head = 0; + CharEntry[i].Torso = 0; + CharEntry[i].Legs = 0; + CharEntry[i].Unknown3 = 1; + CharEntry[i].Unknown4 = 1; + CharEntry[i].Unknown5 = 1; + CharEntry[i].Unknown6 = 1; + CharEntry[i].Unknown7 = 1; + CharEntry[i].Unknown8 = 0; + CharEntry[i].Unknown9 = 0; + CharEntry[i].Unknown10 = 0; + CharEntry[i].Unknown11 = 0; + CharEntry[i].Unknown12 = 0; + + CharEntry[i].in_use = false; + } + + Chars->GetCharProfiles( Account.GetID(), CharEntry, MAX_CHARS_PER_ACCOUNT ); + + for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) + { + if ( CharEntry[i].in_use ) + { + NameLengths += CharEntry[i].NameLen; + } + else + { + CharEntry[i].CharID = 0xffffffff; + CharEntry[i].NameLen = 0; + } + } + + uint8_t PacketHeader[5] = {0xfe, 0x00, 0x00, 0x83, 0x85}; + *( uint16_t* )&PacketHeader[1] = sizeof( uint16_t ) * 3 + ( MAX_CHARS_PER_ACCOUNT * CHARBASESIZE ) + NameLengths + 2; + Socket->write( PacketHeader, 5 ); + + CharList.Unknown1 = 0x0000; + CharList.Unknown2 = CHARBASESIZE; + Socket->write( CharList.Unknown1 ); + Socket->write( CharList.NumSlots ); + Socket->write( CharList.Unknown2 ); + + for ( int i = 0; i < MAX_CHARS_PER_ACCOUNT; i++ ) + { + Socket->write( CharEntry[i].CharID ); + Socket->write( CharEntry[i].Type ); + Socket->write( CharEntry[i].Color0 ); + Socket->write( CharEntry[i].Unknown1 ); + Socket->write( CharEntry[i].Head ); + Socket->write( CharEntry[i].Torso ); + Socket->write( CharEntry[i].Legs ); + Socket->write( CharEntry[i].Location ); + Socket->write( CharEntry[i].NameLen ); + Socket->write( CharEntry[i].Unknown3 ); + Socket->write( CharEntry[i].Unknown4 ); + Socket->write( CharEntry[i].Unknown5 ); + Socket->write( CharEntry[i].Unknown6 ); + Socket->write( CharEntry[i].Unknown7 ); + Socket->write( CharEntry[i].Unknown8 ); + Socket->write( CharEntry[i].Unknown9 ); + Socket->write( CharEntry[i].Unknown10 ); + Socket->write( CharEntry[i].Unknown11 ); + Socket->write( CharEntry[i].Unknown12 ); + + if ( CharEntry[i].Name.length() > 0 ) + { + Socket->write( CharEntry[i].Name.c_str() ); + Socket->write(( uint8_t )0 ); + } + } + + State->TCP.mState = PGameState::TCP::GS_CHARLIST; + } + else + { + Console->Print( RED, BLACK, "Gameserver protocol error (GS_REQUESTCHARS): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + return ( false ); + } + + return ( true ); +} + +bool PGameServer::HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ) +{ + static uint8_t Answer[10] = {0xfe, 0x07, 0x00, 0x83, 0x86, 0, 0, 0, 0, 0}; + ConnectionTCP *Socket = Client->getTCPConn(); + + if ( PacketSize > 9 && *( uint16_t* )&Packet[3] == 0x8284 ) + { + uint8_t Mode = Packet[9]; + + switch ( Mode ) + { + case 6: // request list + return ( HandleRequestChars( Client, State, Packet ) ); + + case 5: // validate name + { + if ( PacketSize < 31 ) + return ( false ); + + // check for valid name string + bool ValidString = false; + + for ( int i = 30; i < PacketSize; i++ ) + if ( Packet[i] == 0 ) + { + ValidString = true; + break; + } + + const char *Name = ( char* ) & Packet[30]; + if ( ValidString ) + { + ValidString = PChar::IsCharnameWellFormed( Name ); + } + + if ( ValidString ) + { + if ( Chars->CharExist( std::string( Name ) ) ) + { + ValidString = false; + } + } + + if ( ValidString ) + Answer[5] = 1; // ok + else + Answer[5] = 2; // 2..6 => 'char name already in use!' + + // Answer[5] = 0; // => 'unknown error' + Socket->write( Answer, 10 ); + return ( true ); + } + + case 3: // delete char + { + PAccount Acc( Client->GetAccountID() ); + uint8_t Num = Packet[PacketSize-1]; + + if ( Acc.GetID() ) + { + uint32_t CharID = Acc.GetCharIdBySlot( Num ); + + // Also check that char is out of game + if (( CharID != 0 ) && ( Chars->GetChar( CharID ) == NULL ) ) + { + char query[100]; + snprintf( query, 100, "DELETE FROM characters WHERE c_id = %d LIMIT 1", CharID ); + if ( MySQL->GameQuery( query ) ) + Console->Print( RED, BLACK, "[Notice] Char %d not deleted!", CharID ); + else + { + Console->Print( GREEN, BLACK, "[Info] Char %d deleted!", CharID ); + + snprintf( query, 100, "DELETE FROM buddy_list WHERE bud_charid = %d", CharID ); + if ( MySQL->GameQuery( query ) ) + Console->Print( YELLOW, BLACK, "[Notice] Char %d's buddy list not removed!", CharID ); + + snprintf( query, 100, "DELETE FROM genrep WHERE g_charid = %d", CharID ); + if ( MySQL->GameQuery( query ) ) + Console->Print( YELLOW, BLACK, "[Notice] Char %d's genrep list not removed!", CharID ); + + snprintf( query, 100, "DELETE FROM inventory WHERE inv_charid = %d", CharID ); + if ( MySQL->GameQuery( query ) ) + Console->Print( YELLOW, BLACK, "[Notice] Char %d's inventory not removed!", CharID ); + + Appartements->DeleteCharAppartements( CharID ); + } + } + else + return false; + } + return ( true ); + } + + case 7: // create char + { + if ( PacketSize < 64 ) + return ( false ); + + uint32_t Slot = * ( uint32_t* ) & Packet[30]; + //uint32_t nClass =* (uint32_t*)&Packet[34]; // Not used - indirectly redundant with Profession + uint32_t Profession = * ( uint32_t* ) & Packet[38]; + uint32_t Gender = * ( uint32_t* ) & Packet[42]; + uint32_t Head = * ( uint32_t* ) & Packet[46]; + uint32_t Torso = * ( uint32_t* ) & Packet[50]; + uint32_t Legs = * ( uint32_t* ) & Packet[54]; + uint32_t Faction = * ( uint32_t* ) & Packet[58]; + uint8_t NameLen = Packet[62]; + uint8_t NZSNb = Packet[63]; + + char TempName[256]; + std::strncpy( TempName, ( const char* )&Packet[64], NameLen ); + TempName[NameLen] = 0; + + Answer[5] = 2; // return error if char creation fails + + if ( PChar::IsCharnameWellFormed( TempName ) ) + { + // check for already used char name - should not happen though + if ( ! Chars->CharExist( std::string( TempName ) ) ) + { + PAccount Acc( Client->GetAccountID() ); + PChar* nChar = new PChar(); + + if ( nChar->CreateNewChar( Acc.GetID(), TempName, Gender, Profession, Faction, + Head, Torso, Legs, NZSNb, ( const char* )&Packet[64+NameLen], Slot ) ) + { + Answer[5] = 1; // return success + } + delete nChar; + } + } + + Socket->write( Answer, 10 ); + return ( true ); + } + } + } + else + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_CHARLIST): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + + return ( false ); + } + + return true; +} + +bool PGameServer::HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet ) +{ + ConnectionTCP *Socket = Client->getTCPConn(); + + if ( *( uint16_t* )&Packet[3] == 0x3787 ) + { + static const uint8_t STATUS[9] = {0xfe, 0x06, 0x00, 0x87, 0x3a, 0x11, 0x00, 0x00, 0x00}; + + Socket->write( STATUS, 9 ); + State->TCP.mState = PGameState::TCP::GS_GAMEINFO; + } + else + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GETSTATUS): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + + return ( false ); + } + + return ( true ); +} + +bool PGameServer::HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet ) +{ +// Console->Print("Inside HandleGameInfo");//NEW added + + static uint8_t GameInfo[31] = {0xfe, 0x1c, 0x00, 0x83, 0x05, // header + 0x00, 0x00, 0x00, 0x00, // account id + 0x00, 0x00, 0x00, 0x00, // char id + 0x00, 0x00, 0x00, 0x00, // udp ip + 0x00, 0x00, // udp port + 0x00, 0x00, 0x00, 0x00, // unknown + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, // session key + }; + + ConnectionTCP *Socket = Client->getTCPConn(); + + if ( *( uint16_t* )&Packet[3] == 0x3c87 ) + { + //int PortFix = Config->GetOptionInt("debug_mode"); + + ConnectionUDP* udpConn = ServerSock->getUDPConnection( IPStringToDWord( Client->GetAddress() ), Client->GetRemoteUDPPort() ); + Client->setUDPConnection( udpConn ); + if ( !udpConn ) + { + Console->Print( RED, BLACK, "Client %d: UDP port setup failed", Client->GetID() ); + ClientDisconnected( Client ); + } + + uint16_t Port = Client->getUDPConn()->getPort(); + + if ( Port == 0 ) + Console->Print( RED, BLACK, "Client->OpenUDP() failed" ); + + + /* if(PortFix == 1) // removed, no more use + { + Port = Config->GetOptionInt("useudpport"); + Console->Print(YELLOW, BLACK, "UDP Port set to non-standard for debugging!"); + }; */ + + uint32_t IP; + std::string IPServerString; +// use [server_nat_ip] for server if client is NOT on [no_nat_net] (and [no_nat_net]!=0) + if ( strcmp( Config->GetOption( "no_nat_net" ).c_str(), "0" ) && strncmp( Client->GetAddress(), Config->GetOption( "no_nat_net" ).c_str(), strlen( Config->GetOption( "no_nat_net" ).c_str() ) ) ) + { + IPServerString = Config->GetOption( "server_nat_ip" ); + } + else // else client is "local" so use [server_ip] + { + IPServerString = Config->GetOption( "server_ip" ); + } + IP = IPStringToDWord( IPServerString.c_str() ); +//Console->Print("IP-1 %d", IP); + if ( IP == 0 ) + IP = 0x0100007f; +//Console->Print("IP-2 %d", IP); + *( uint32_t* )&GameInfo[13] = IP; + *( uint16_t* )&GameInfo[17] = Port; + Console->Print( GREEN, BLACK, "[Info] Using UDP %s:%d on server", IPServerString.c_str(), Port ); + + *( uint32_t* )&GameInfo[5] = Client->GetAccountID(); + *( uint32_t* )&GameInfo[9] = Client->GetCharID(); + Console->Print( GREEN, BLACK, "[Info] Serving char id :%d", Client->GetCharID() ); + + Socket->write( GameInfo, 31 ); + Socket->flushSendBuffer(); + + static const uint8_t READY[7] = {0xfe, 0x04, 0x00, 0x83, 0x0d, 0x00, 0x00}; + Socket->write( READY, 7 ); + + State->TCP.mState = PGameState::TCP::GS_INGAME; + State->UDP.mState = PGameState::UDP::GUS_SYNC0; +//Console->Print("Sync Reset"); + Client->ResetTransactionID(); + + // Mark char as Online + PChar *Char = Client->GetChar(); + Char->SetOnlineStatus( true ); //Also using this info to check if Char may have to be saved at client disconnect + Client->ChangeCharLocation( Char->GetLocation(), true ); + + // hello-message from server.. + /* + std::string serverName = Config->GetOption("server_name"); + std::string helloMessage = "Welcome to " + serverName + " - A TinNS Neocron Server."; + char* message = (char*) helloMessage.c_str(); + Chat->send(Client, CHAT_DIRECT, "System", message, false); + */ + + bool SendBC = false; + if ( Config->GetOptionInt( "broadcast_new" ) == 1 ) + { + if ( Config->GetOptionInt( "broadcast_new_hidestaff" ) == 1 ) + { + if ( Client->GetAccountLevel() > PAL_REGPLAYER ) + SendBC = false; + else + SendBC = true; + } + else + { + SendBC = true; + } + } + if ( SendBC == true ) + { + std::string playerName = Chars->GetChar( Client->GetCharID() )->GetName(); + std::string serverName = Config->GetOption( "server_name" ); + std::string helloMessage = "Hello " + playerName + "! Welcome to " + serverName + " - A TinNS Neocron Server."; + char* message = ( char* ) helloMessage.c_str(); + + Chat->sendOOCBroadcast( message ); + } + //Console->Print("UDP Setup: %s", nlGetErrorStr(nlGetError())); + } + else + { + Console->Print( RED, BLACK, "[Notice] Gameserver protocol error (GS_GAMEINFO): invalid packet [%04x]", *( uint16_t* )&Packet[3] ); + return ( false ); + } + + return ( true ); +} + +bool PGameServer::HandleGame( PClient *Client, PGameState *State ) +{ + //PGameSocket *Socket = Client->GetGameSocket(); + ConnectionUDP *UDPSocket = Client->getUDPConn(); + //Console->Print("Clientadress %s", Client->GetAddress()); + + //int Size = 0; + PMessage* NewMsg = UDPSocket->GetMessage(); + if ( NewMsg && NewMsg->GetSize() ) + { + + MsgDecoder->Init( NewMsg, Client, State ); // State used temporarily + do + { + if ( MsgDecoder->Analyse() ) + { + if ( gDevDebug && MsgDecoder->IsTraceKnownMsg() ) + Console->Print( "%s Client[%d] msg: %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), Client->GetID(), MsgDecoder->GetName().c_str() ); + + if ( MsgDecoder->IsActionReady() ) + { + MsgDecoder->DoAction(); + } + } + else if ( MsgDecoder->IsError() ) + { + Console->Print( YELLOW, BLACK, "[Info] Client[%d] Decoding error: %s", Client->GetID(), MsgDecoder->GetError().c_str() ); + } +// else if (MsgDecoder->GetState() == DECODE_UNKNOWN) + else if ( gDevDebug && ( MsgDecoder->GetState() == DECODE_UNKNOWN ) && MsgDecoder->IsTraceUnknownMsg() ) + { + Console->Print( "%s Client[%d] Unknown msg: %s", Console->ColorText( YELLOW, BLACK, "[Info]" ), Client->GetID(), MsgDecoder->GetName().c_str() ); + } + +// if (MsgDecoder->IsTraceDump()) + if ( gDevDebug && MsgDecoder->IsTraceDump() ) + { + MsgDecoder->DumpMsg(); + } + + } + while ( MsgDecoder->MoreSubMsg() ); + } + + if ( NewMsg ) + { + delete NewMsg; + } + + return ( true ); +} + +bool PGameServer::ProcessClient( PClient *Client, PGameState *State ) +{ + static const uint8_t HANDSHAKE0A[6] = {0xfe, 0x03, 0x00, 0x80, 0x01, 0x66}; + + if ( !State ) + { + GameStateMap::iterator node = ClientStates.find( Client ); + if ( node == ClientStates.end() ) + return ( false ); + + State = node->second; + } + + ConnectionTCP *Socket = Client->getTCPConn(); + if ( !Socket ) Console->Print( RED, BLACK, "PANIC: Client %d : TCP Socket is NULL !!!", Client->GetID() ); + if ( State->TCP.mWaitSend && Socket->getSendBufferSize() == 0 ) + return ( false ); + + if ( State->TCP.mState == PGameState::TCP::GS_CONNECTED ) + { + Socket->write( HANDSHAKE0A, 6 ); + State->TCP.mState = PGameState::TCP::GS_HANDSHAKE0; + } + + if ( State->TCP.mState == PGameState::TCP::GS_INGAME ) + { + return ( HandleGame( Client, State ) ); + } + else + { + int PacketSize = 0; + const uint8_t *Packet = Socket->read( &PacketSize ); + + if ( PacketSize > 0 ) + { + switch ( State->TCP.mState ) + { + case PGameState::TCP::GS_HANDSHAKE0: + return ( HandleHandshake( State, Packet, PacketSize ) ); + + case PGameState::TCP::GS_AUTHENTICATE: + return ( HandleAuthenticate( Client, State, Packet, PacketSize ) ); + + case PGameState::TCP::GS_GAMEDATA: + return ( HandleGameData( Client, State, Packet ) ); + + case PGameState::TCP::GS_REQUESTCHARS: + return ( HandleRequestChars( Client, State, Packet ) ); + + case PGameState::TCP::GS_CHARLIST: + return ( HandleCharList( Client, State, Packet, PacketSize ) ); + + case PGameState::TCP::GS_GETSTATUS: + return ( HandleGetStatus( Client, State, Packet ) ); + + case PGameState::TCP::GS_GAMEINFO: + return ( HandleGameInfo( Client, State, Packet ) ); + default: + break; + } + } + } + + return ( true ); +} + +void PGameServer::ClientDisconnected( PClient *Client ) +{ + GameStateMap::iterator node = ClientStates.find( Client ); + + if ( node == ClientStates.end() ) + return; + + PGameState *State = node->second; + FinalizeClient( Client, State ); +} + +void PGameServer::UDPStreamClosed( PClient *Client ) +{ + GameStateMap::iterator node = ClientStates.find( Client ); + + if ( node == ClientStates.end() ) + return; + + PGameState *State = node->second; + FinalizeClient( Client, State ); +} + +void PGameServer::FinalizeClient( PClient *Client, PGameState *State ) +{ + Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s disconnected", Client->GetAddress() ); + + // Isnt working somehow. I assume that mID and mAccount is deleted already. + // Mark char as Offline + //PChar *Char = Chars->GetChar(Client->GetCharID()); + //Char->SetOnlineStatus(false); + + // delete client from clientmanager list => Do it before we remove network access + ClientManager->deleteClientFromList( Client->GetLocalID() ); + + Client->GameDisconnect(); + ClientStates.erase( Client ); + delete State; + --mNumClients; + +} + +void PGameServer::FinalizeClientDelayed( PClient *Client, PGameState *State ) +{ + Console->Print( GREEN, BLACK, "[Info] Gameserver: client %s is about to be disconnected", Client->GetAddress() ); + State->TCP.mWaitSend = true; +} + +PGameState* PGameServer::GetClientState( PClient* nClient ) +{ + GameStateMap::iterator node = ClientStates.find( nClient ); + + if ( node == ClientStates.end() ) + return NULL; + else + return node->second; +} diff --git a/TinNS/Source/GameServer/GameServer.hxx b/TinNS/Source/GameServer/GameServer.hxx index 177c1da..47c93a5 100644 --- a/TinNS/Source/GameServer/GameServer.hxx +++ b/TinNS/Source/GameServer/GameServer.hxx @@ -1,110 +1,110 @@ -#pragma once - -#include -#include -#include - -struct PGameState -{ - struct TCP - { - enum State - { - GS_UNKNOWN, - GS_CONNECTED, - GS_HANDSHAKE0, - GS_AUTHENTICATE, - GS_GAMEDATA, - GS_REQUESTCHARS, - GS_CHARLIST, - GS_GETSTATUS, - GS_GAMEINFO, - GS_INGAME - } mState; - - bool mWaitSend; // wait-for-completition flag - } TCP; - - struct UDP - { - enum State - { - GUS_UNKNOWN, - GUS_SYNC0, - GUS_SYNC1, - GUS_SYNC2, - GUS_SYNC3 - } mState; - - bool mSynced; - uint16_t mServerPacketNum; - uint16_t mSequence; - //uint16_t mClientPacketNum; - } UDP; - - PGameState() - { - TCP.mState = TCP::GS_UNKNOWN; - TCP.mWaitSend = false; - - UDP.mState = UDP::GUS_UNKNOWN; - UDP.mSynced = false; - UDP.mServerPacketNum = 0x9c9f; - UDP.mSequence = 2; - //UDP.mClientPacketNum = 0; - }; -}; - -class PUdpMsgDecoder; - -class PGameServer -{ - private : - time_t mServerStartupTime; - int mNumClients; - uint32_t mBaseGameTime; - struct timespec mStartTime; - - typedef std::map GameStateMap; - GameStateMap ClientStates; - PUdpMsgDecoder* MsgDecoder; - - protected : - bool ProcessClient( PClient *Client, PGameState *State = 0 ); - void FinalizeClient( PClient *Client, PGameState *State ); - void FinalizeClientDelayed( PClient *Client, PGameState *State ); - -// bool HandleHandshake(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); - bool HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize ); - - bool HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ); -// bool HandleGameData(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); - bool HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet ); - -// bool HandleRequestChars(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); - bool HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet ); - - bool HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ); -// bool HandleGetStatus(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); - bool HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet ); - -// bool HandleGameInfo(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); - bool HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet ); - - bool HandleGame( PClient *Client, PGameState *State ); - - public : - PGameServer(); - ~PGameServer(); - - void Start(); - void Update(); - void ClientDisconnected( PClient *Client ); - void UDPStreamClosed( PClient *Client ); - void SetGameTime( uint32_t newtime ); - uint32_t GetGameTime(); - - inline time_t GetStartTime() const { return mServerStartupTime; }; - - PGameState* GetClientState( PClient* nClient ); -}; +#pragma once + +#include +#include +#include + +struct PGameState +{ + struct TCP + { + enum State + { + GS_UNKNOWN, + GS_CONNECTED, + GS_HANDSHAKE0, + GS_AUTHENTICATE, + GS_GAMEDATA, + GS_REQUESTCHARS, + GS_CHARLIST, + GS_GETSTATUS, + GS_GAMEINFO, + GS_INGAME + } mState; + + bool mWaitSend; // wait-for-completition flag + } TCP; + + struct UDP + { + enum State + { + GUS_UNKNOWN, + GUS_SYNC0, + GUS_SYNC1, + GUS_SYNC2, + GUS_SYNC3 + } mState; + + bool mSynced; + uint16_t mServerPacketNum; + uint16_t mSequence; + //uint16_t mClientPacketNum; + } UDP; + + PGameState() + { + TCP.mState = TCP::GS_UNKNOWN; + TCP.mWaitSend = false; + + UDP.mState = UDP::GUS_UNKNOWN; + UDP.mSynced = false; + UDP.mServerPacketNum = 0x9c9f; + UDP.mSequence = 2; + //UDP.mClientPacketNum = 0; + }; +}; + +class PUdpMsgDecoder; + +class PGameServer +{ + private : + time_t mServerStartupTime; + int mNumClients; + uint32_t mBaseGameTime; + struct timespec mStartTime; + + typedef std::map GameStateMap; + GameStateMap ClientStates; + PUdpMsgDecoder* MsgDecoder; + + protected : + bool ProcessClient( PClient *Client, PGameState *State = 0 ); + void FinalizeClient( PClient *Client, PGameState *State ); + void FinalizeClientDelayed( PClient *Client, PGameState *State ); + +// bool HandleHandshake(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); + bool HandleHandshake( PGameState *State, const uint8_t *Packet, int PacketSize ); + + bool HandleAuthenticate( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ); +// bool HandleGameData(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); + bool HandleGameData( PClient *Client, PGameState *State, const uint8_t *Packet ); + +// bool HandleRequestChars(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); + bool HandleRequestChars( PClient *Client, PGameState *State, const uint8_t *Packet ); + + bool HandleCharList( PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize ); +// bool HandleGetStatus(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); + bool HandleGetStatus( PClient *Client, PGameState *State, const uint8_t *Packet ); + +// bool HandleGameInfo(PClient *Client, PGameState *State, const uint8_t *Packet, int PacketSize); + bool HandleGameInfo( PClient *Client, PGameState *State, const uint8_t *Packet ); + + bool HandleGame( PClient *Client, PGameState *State ); + + public : + PGameServer(); + ~PGameServer(); + + void Start(); + void Update(); + void ClientDisconnected( PClient *Client ); + void UDPStreamClosed( PClient *Client ); + void SetGameTime( uint32_t newtime ); + uint32_t GetGameTime(); + + inline time_t GetStartTime() const { return mServerStartupTime; }; + + PGameState* GetClientState( PClient* nClient ); +}; diff --git a/TinNS/Source/GameServer/GenrepList.cxx b/TinNS/Source/GameServer/GenrepList.cxx index 743d979..85cb220 100644 --- a/TinNS/Source/GameServer/GenrepList.cxx +++ b/TinNS/Source/GameServer/GenrepList.cxx @@ -1,156 +1,156 @@ -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -PGenrepList::PGenrepList(uint32_t nOwnerCharID) -{ - mOwnerCharID = nOwnerCharID; - mListMaxSize = mListSize = 0; - mGenrepList = NULL; -} - -PGenrepList::~PGenrepList() -{ - if (mGenrepList) - delete[] mGenrepList; -} - -bool PGenrepList::AddGenrep(uint16_t nWorldID, uint16_t nStationID) -{ - char query[256]; - - if ((FindEntry(nWorldID, nStationID) >= mListSize) && (mListSize < 255)) - { - if (mListSize == mListMaxSize) - { - IncreaseMaxSize(); - } - mGenrepList[mListSize].mWorldID = nWorldID; - mGenrepList[mListSize++].mStationID = nStationID; - - snprintf(query, 256, "INSERT INTO genrep (g_id,g_worldid,g_stationid,g_charid) VALUES (NULL,'%u','%u','%u');", nWorldID, nStationID, mOwnerCharID); - if ( MySQL->GameQuery(query) ) - { - Console->Print(RED, BLACK, "PGenrepList::AddGenrep could not add some genrep entry in the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return false; - } - - return true; - } - else - return false; -} - -/*bool PGenrepList::RemoveChar(uint32_t nBuddyCharID) -{ - char query[256]; - uint8_t rEntry, i; - - if ((rEntry = FindEntry(nBuddyCharID)) < mListSize) - { - --mListSize; - for (i = rEntry; i < mListSize; i++) - { - mGenrepList[i] = mGenrepList[i+1]; - } - // Remove from DB here - snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID); - if ( MySQL->GameQuery(query) ) - { - Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylist entry in the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return false; - } - - return true; - } - else - return false; -}*/ - -bool PGenrepList::SQLLoad() -{ - char query[256]; - MYSQL_RES *result; - MYSQL_ROW row; - uint8_t EntriesNum; - - snprintf(query, 256, "SELECT * FROM genrep WHERE (g_charid='%u')", mOwnerCharID); - result = MySQL->GameResQuery(query); - if(result == NULL) - { - Console->Print(RED, BLACK, "PGenrepList::SQLLoad could not load genreplist from the database"); - Console->Print("Query was:"); - Console->Print("%s", query); - MySQL->ShowGameSQLError(); - return false; - } - //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Loading Genrep list for char %d", mOwnerCharID); - mListSize = 0; - if((EntriesNum = mysql_num_rows(result))) - { - IncreaseMaxSize(EntriesNum); - - while((row = mysql_fetch_row(result))) - { - mGenrepList[mListSize].mWorldID = atoi(row[g_worldid]); - mGenrepList[mListSize++].mStationID = atoi(row[g_stationid]); - //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Genrep list entry %d : world %d station %d", mListSize, mGenrepList[mListSize-1].mWorldID,mGenrepList[mListSize-1].mStationID); - } - } - MySQL->FreeGameSQLResult(result); - return true; -} - -void PGenrepList::IncreaseMaxSize(uint8_t nNewMax) -{ - uint16_t tmpSize; - - if (!nNewMax) - { - tmpSize = mListMaxSize + GENREPLIST_ALLOC_SIZE; - } - else if (nNewMax > mListMaxSize) - { - tmpSize = nNewMax / GENREPLIST_ALLOC_SIZE; - if (nNewMax % GENREPLIST_ALLOC_SIZE) - ++tmpSize; - tmpSize *= GENREPLIST_ALLOC_SIZE; - } - else - return; - - mListMaxSize = (tmpSize < 256) ? tmpSize : 255; - - PGenrepEntry* tmpList = new PGenrepEntry[mListMaxSize]; - if (mGenrepList) - { - if (mListSize) - { - memcpy(tmpList, mGenrepList, sizeof(PGenrepEntry) * mListSize); - } - delete[] mGenrepList; - } - mGenrepList = tmpList; -} - -uint8_t PGenrepList::FindEntry(uint16_t nWorldID, uint16_t nStationID) -{ - uint8_t i = 255; - - if (mGenrepList) - { - for (i = 0; i < mListSize; i++) - { - if ((mGenrepList[i].mWorldID == nWorldID) && (mGenrepList[i].mStationID == nStationID)) - break; - } - } - - return i; -} +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +PGenrepList::PGenrepList(uint32_t nOwnerCharID) +{ + mOwnerCharID = nOwnerCharID; + mListMaxSize = mListSize = 0; + mGenrepList = NULL; +} + +PGenrepList::~PGenrepList() +{ + if (mGenrepList) + delete[] mGenrepList; +} + +bool PGenrepList::AddGenrep(uint16_t nWorldID, uint16_t nStationID) +{ + char query[256]; + + if ((FindEntry(nWorldID, nStationID) >= mListSize) && (mListSize < 255)) + { + if (mListSize == mListMaxSize) + { + IncreaseMaxSize(); + } + mGenrepList[mListSize].mWorldID = nWorldID; + mGenrepList[mListSize++].mStationID = nStationID; + + snprintf(query, 256, "INSERT INTO genrep (g_id,g_worldid,g_stationid,g_charid) VALUES (NULL,'%u','%u','%u');", nWorldID, nStationID, mOwnerCharID); + if ( MySQL->GameQuery(query) ) + { + Console->Print(RED, BLACK, "PGenrepList::AddGenrep could not add some genrep entry in the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return false; + } + + return true; + } + else + return false; +} + +/*bool PGenrepList::RemoveChar(uint32_t nBuddyCharID) +{ + char query[256]; + uint8_t rEntry, i; + + if ((rEntry = FindEntry(nBuddyCharID)) < mListSize) + { + --mListSize; + for (i = rEntry; i < mListSize; i++) + { + mGenrepList[i] = mGenrepList[i+1]; + } + // Remove from DB here + snprintf(query, 256, "DELETE FROM buddy_list WHERE ((bud_charid='%u') AND (bud_buddyid='%u')) LIMIT 1;", mOwnerCharID, nBuddyCharID); + if ( MySQL->GameQuery(query) ) + { + Console->Print(RED, BLACK, "PBuddyList::AddChar could not add some buddylist entry in the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return false; + } + + return true; + } + else + return false; +}*/ + +bool PGenrepList::SQLLoad() +{ + char query[256]; + MYSQL_RES *result; + MYSQL_ROW row; + uint8_t EntriesNum; + + snprintf(query, 256, "SELECT * FROM genrep WHERE (g_charid='%u')", mOwnerCharID); + result = MySQL->GameResQuery(query); + if(result == NULL) + { + Console->Print(RED, BLACK, "PGenrepList::SQLLoad could not load genreplist from the database"); + Console->Print("Query was:"); + Console->Print("%s", query); + MySQL->ShowGameSQLError(); + return false; + } + //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Loading Genrep list for char %d", mOwnerCharID); + mListSize = 0; + if((EntriesNum = mysql_num_rows(result))) + { + IncreaseMaxSize(EntriesNum); + + while((row = mysql_fetch_row(result))) + { + mGenrepList[mListSize].mWorldID = atoi(row[g_worldid]); + mGenrepList[mListSize++].mStationID = atoi(row[g_stationid]); + //Console->Print(GREEN, BLACK, "PGenrepList::SQLLoad Genrep list entry %d : world %d station %d", mListSize, mGenrepList[mListSize-1].mWorldID,mGenrepList[mListSize-1].mStationID); + } + } + MySQL->FreeGameSQLResult(result); + return true; +} + +void PGenrepList::IncreaseMaxSize(uint8_t nNewMax) +{ + uint16_t tmpSize; + + if (!nNewMax) + { + tmpSize = mListMaxSize + GENREPLIST_ALLOC_SIZE; + } + else if (nNewMax > mListMaxSize) + { + tmpSize = nNewMax / GENREPLIST_ALLOC_SIZE; + if (nNewMax % GENREPLIST_ALLOC_SIZE) + ++tmpSize; + tmpSize *= GENREPLIST_ALLOC_SIZE; + } + else + return; + + mListMaxSize = (tmpSize < 256) ? tmpSize : 255; + + PGenrepEntry* tmpList = new PGenrepEntry[mListMaxSize]; + if (mGenrepList) + { + if (mListSize) + { + memcpy(tmpList, mGenrepList, sizeof(PGenrepEntry) * mListSize); + } + delete[] mGenrepList; + } + mGenrepList = tmpList; +} + +uint8_t PGenrepList::FindEntry(uint16_t nWorldID, uint16_t nStationID) +{ + uint8_t i = 255; + + if (mGenrepList) + { + for (i = 0; i < mListSize; i++) + { + if ((mGenrepList[i].mWorldID == nWorldID) && (mGenrepList[i].mStationID == nStationID)) + break; + } + } + + return i; +} diff --git a/TinNS/Source/GameServer/GenrepList.hxx b/TinNS/Source/GameServer/GenrepList.hxx index ea47372..e19b9cd 100644 --- a/TinNS/Source/GameServer/GenrepList.hxx +++ b/TinNS/Source/GameServer/GenrepList.hxx @@ -1,39 +1,39 @@ -#pragma once - -#include - -#define GENREPLIST_ALLOC_SIZE 4 // atomicity of list entries allocation - -class PGenrepList { -private: - enum { // genrep DB Table fields - g_id = 0, - g_worldid, - g_stationid, - g_charid - }; - struct PGenrepEntry - { - uint16_t mWorldID; - uint16_t mStationID; - }; - - uint32_t mOwnerCharID; - uint8_t mListMaxSize; - uint8_t mListSize; - PGenrepEntry* mGenrepList; - - void IncreaseMaxSize(uint8_t nNewMax = 0); - uint8_t FindEntry(uint16_t nWorldID, uint16_t nStationID); - - public: - PGenrepList(uint32_t nOwnerCharID); - ~PGenrepList(); - bool AddGenrep(uint16_t nWorldID, uint16_t nStationID); - //bool RemoveChar(uint32_t nBuddyCharID); - inline uint8_t Count() { return mListSize; } - uint16_t GetListDataSize() { return (sizeof(PGenrepEntry) * mListSize); } - const void* GetListData() { return (const void*)mGenrepList; } - bool SQLLoad(); -// bool SQLSave(); -}; +#pragma once + +#include + +#define GENREPLIST_ALLOC_SIZE 4 // atomicity of list entries allocation + +class PGenrepList { +private: + enum { // genrep DB Table fields + g_id = 0, + g_worldid, + g_stationid, + g_charid + }; + struct PGenrepEntry + { + uint16_t mWorldID; + uint16_t mStationID; + }; + + uint32_t mOwnerCharID; + uint8_t mListMaxSize; + uint8_t mListSize; + PGenrepEntry* mGenrepList; + + void IncreaseMaxSize(uint8_t nNewMax = 0); + uint8_t FindEntry(uint16_t nWorldID, uint16_t nStationID); + + public: + PGenrepList(uint32_t nOwnerCharID); + ~PGenrepList(); + bool AddGenrep(uint16_t nWorldID, uint16_t nStationID); + //bool RemoveChar(uint32_t nBuddyCharID); + inline uint8_t Count() { return mListSize; } + uint16_t GetListDataSize() { return (sizeof(PGenrepEntry) * mListSize); } + const void* GetListData() { return (const void*)mGenrepList; } + bool SQLLoad(); +// bool SQLSave(); +}; diff --git a/TinNS/Source/GameServer/Includes.cxx b/TinNS/Source/GameServer/Includes.cxx index 28f3f3d..801f2ac 100644 --- a/TinNS/Source/GameServer/Includes.cxx +++ b/TinNS/Source/GameServer/Includes.cxx @@ -1,198 +1,198 @@ -#include -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -// TODO: - Get logfile name from config file - -const char ServerVersion[] = TINNS_GAME_VERSION; -const char SVNRevision[] = TINNS_SVN_REVISION; - -PVehicles *Vehicles = 0; -PMySQL *MySQL = 0; -PConsole *Console = 0; -PServer *Server = 0; -PConfig *Config = 0; -PConfig *CmdAccess = 0; -PGameDefs *GameDefs = 0; -PChars *Chars = 0; -PFileSystem *Filesystem = 0; -PGameServer *GameServer = 0; -ServerSocket *ServerSock = 0; -PMsgBuilder *MsgBuilder = 0; -PWorlds *Worlds = 0; -PAppartements* Appartements = 0; -PWorldActors* WorldActors = 0; -PNPCManager* NPCManager = 0; -PSubway* Subway = 0; -PTerminal* Terminal = 0; -PLuaEngine* LuaEngine = 0; -POutpost* Outposts = 0; -PMultiPart* MultiPartHandler = 0; - -//multi-user chat implementation -PClientManager *ClientManager = 0; -PChat *Chat = 0; -PCommands *GameCommands = 0; - -PISC *ISC = 0; - -const std::string EmptyString; - -// Development debug output control (set by config option dev_debug) -bool gDevDebug = false; - -bool InitTinNS() -{ - Console = new PConsole("log/gameserver.log"); // Make that from config file !!! - Console->Print("Starting TinNS Gameserver"); - Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\"); - Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |"); - Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |"); - Console->Print(WHITE, BLUE, "| maintainer Akiko |"); - Console->Print(WHITE, BLUE, "| ========================================== |"); - Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |"); - Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |"); - Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |"); - Console->Print(WHITE, BLUE, "| - Namikon - Balm |"); - Console->Print(WHITE, BLUE, "| - Hammag |"); - Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); - Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |"); - Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |"); - Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); - Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |"); - Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/"); - - //char svnrev[10]; - //GetSVNRev(svnrev); - Console->LPrint("You are running TinNS Gameserver version"); - Console->LPrint(GREEN, BLACK, " %s", ServerVersion); - Console->LPrint(WHITE, BLACK, " - SVN Rev"); - Console->LPrint(GREEN, BLACK, " %s", SVNRevision); - Console->LClose(); - - Config = new PConfig(); - if(!Config->LoadOptions(GameConfigTemplate, "./conf/gameserver.conf")) - return false; //Shutdown(); - - CmdAccess = new PConfig(); - if(!CmdAccess->LoadOptions(CommandsTemplate, "./conf/commands.conf")) - return false; //Shutdown(); - - gDevDebug = Config->GetOptionInt("dev_debug"); - std::string MyName = Config->GetOption("server_name"); - std::string IP = Config->GetOption("server_ip"); - char myCname[100], myCip[100]; - strncpy (myCname, Console->ColorText(CYAN, BLACK, MyName.c_str()), 100); - strncpy (myCip, Console->ColorText(CYAN, BLACK, IP.c_str()), 100); - Console->Print("My name is '%s', and my address is %s", myCname, myCip); - - MySQL = new PMySQL(); - if(MySQL->Connect() == false) - return false; //Shutdown(); - - Filesystem = new PFileSystem(); - - GameDefs = new PGameDefs(); - GameDefs->Init(); - - Worlds = new PWorlds(); - Worlds->LoadWorlds(); - - WorldActors = new PWorldActors(); - LuaEngine = new PLuaEngine(); - - NPCManager = new PNPCManager(); - Appartements = new PAppartements; - Subway = new PSubway; - - if (!PAccount::SetUsernameRegexFilter(Config->GetOption("username_filter").c_str())) - { - Console->Print("%s Could not creat username_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("username_filter").c_str()); - return false; - } - if(!PAccount::SetPasswordRegexFilter(Config->GetOption("password_filter").c_str())) - { - Console->Print("%s Could not creat password_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("password_filter").c_str()); - return false; - } - - if (!PChar::SetCharnameRegexFilter(Config->GetOption("charname_filter").c_str())) - { - Console->Print("%s Could not creat charname_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("charname_filter").c_str()); - return false; - } - Chars = new PChars(); - - ServerSock = new ServerSocket(); - Server = new PServer(); - GameServer = new PGameServer(); - MsgBuilder = new PMsgBuilder(); - - Vehicles = new PVehicles(); - - ClientManager = new PClientManager(); - Chat = new PChat(); - GameCommands = new PCommands(); - - ISC = new PISC(); - Terminal = new PTerminal(); - - Outposts = new POutpost(); - - MultiPartHandler = new PMultiPart(); - - return true; -} - -void Shutdown() -{ - if(MultiPartHandler) - delete MultiPartHandler; - if(Outposts) - delete Outposts; - if(LuaEngine) - delete LuaEngine; - if(Terminal) - delete Terminal; - if(WorldActors) - delete WorldActors; - if(NPCManager) - delete NPCManager; - if(ISC) - { - ISC->Shutdown(); - delete ISC; - } - if(Server) - Server->Shutdown(); - if(GameServer) - delete GameServer; - if(Chat) - delete Chat; - if(Server) - delete Server; - if(Filesystem) - delete Filesystem; - if(GameDefs) - delete GameDefs; - if(Worlds) - { - Worlds->Shutdown(); - delete Worlds; - } - if(Subway) - delete Subway; - if(Chars) - delete Chars; - if(MySQL) - delete MySQL; - if(Config) - delete Config; - if(Console) - delete Console; - if(ServerSock) - delete ServerSock; - - exit(0); -} +#include +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +// TODO: - Get logfile name from config file + +const char ServerVersion[] = TINNS_GAME_VERSION; +const char SVNRevision[] = TINNS_SVN_REVISION; + +PVehicles *Vehicles = 0; +PMySQL *MySQL = 0; +PConsole *Console = 0; +PServer *Server = 0; +PConfig *Config = 0; +PConfig *CmdAccess = 0; +PGameDefs *GameDefs = 0; +PChars *Chars = 0; +PFileSystem *Filesystem = 0; +PGameServer *GameServer = 0; +ServerSocket *ServerSock = 0; +PMsgBuilder *MsgBuilder = 0; +PWorlds *Worlds = 0; +PAppartements* Appartements = 0; +PWorldActors* WorldActors = 0; +PNPCManager* NPCManager = 0; +PSubway* Subway = 0; +PTerminal* Terminal = 0; +PLuaEngine* LuaEngine = 0; +POutpost* Outposts = 0; +PMultiPart* MultiPartHandler = 0; + +//multi-user chat implementation +PClientManager *ClientManager = 0; +PChat *Chat = 0; +PCommands *GameCommands = 0; + +PISC *ISC = 0; + +const std::string EmptyString; + +// Development debug output control (set by config option dev_debug) +bool gDevDebug = false; + +bool InitTinNS() +{ + Console = new PConsole("log/gameserver.log"); // Make that from config file !!! + Console->Print("Starting TinNS Gameserver"); + Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\"); + Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |"); + Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |"); + Console->Print(WHITE, BLUE, "| maintainer Akiko |"); + Console->Print(WHITE, BLUE, "| ========================================== |"); + Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |"); + Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |"); + Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |"); + Console->Print(WHITE, BLUE, "| - Namikon - Balm |"); + Console->Print(WHITE, BLUE, "| - Hammag |"); + Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); + Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |"); + Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |"); + Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); + Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |"); + Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/"); + + //char svnrev[10]; + //GetSVNRev(svnrev); + Console->LPrint("You are running TinNS Gameserver version"); + Console->LPrint(GREEN, BLACK, " %s", ServerVersion); + Console->LPrint(WHITE, BLACK, " - SVN Rev"); + Console->LPrint(GREEN, BLACK, " %s", SVNRevision); + Console->LClose(); + + Config = new PConfig(); + if(!Config->LoadOptions(GameConfigTemplate, "./conf/gameserver.conf")) + return false; //Shutdown(); + + CmdAccess = new PConfig(); + if(!CmdAccess->LoadOptions(CommandsTemplate, "./conf/commands.conf")) + return false; //Shutdown(); + + gDevDebug = Config->GetOptionInt("dev_debug"); + std::string MyName = Config->GetOption("server_name"); + std::string IP = Config->GetOption("server_ip"); + char myCname[100], myCip[100]; + strncpy (myCname, Console->ColorText(CYAN, BLACK, MyName.c_str()), 100); + strncpy (myCip, Console->ColorText(CYAN, BLACK, IP.c_str()), 100); + Console->Print("My name is '%s', and my address is %s", myCname, myCip); + + MySQL = new PMySQL(); + if(MySQL->Connect() == false) + return false; //Shutdown(); + + Filesystem = new PFileSystem(); + + GameDefs = new PGameDefs(); + GameDefs->Init(); + + Worlds = new PWorlds(); + Worlds->LoadWorlds(); + + WorldActors = new PWorldActors(); + LuaEngine = new PLuaEngine(); + + NPCManager = new PNPCManager(); + Appartements = new PAppartements; + Subway = new PSubway; + + if (!PAccount::SetUsernameRegexFilter(Config->GetOption("username_filter").c_str())) + { + Console->Print("%s Could not creat username_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("username_filter").c_str()); + return false; + } + if(!PAccount::SetPasswordRegexFilter(Config->GetOption("password_filter").c_str())) + { + Console->Print("%s Could not creat password_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("password_filter").c_str()); + return false; + } + + if (!PChar::SetCharnameRegexFilter(Config->GetOption("charname_filter").c_str())) + { + Console->Print("%s Could not creat charname_filter PCRE '%s'", Console->ColorText(RED, BLACK, "[Error]"), Config->GetOption("charname_filter").c_str()); + return false; + } + Chars = new PChars(); + + ServerSock = new ServerSocket(); + Server = new PServer(); + GameServer = new PGameServer(); + MsgBuilder = new PMsgBuilder(); + + Vehicles = new PVehicles(); + + ClientManager = new PClientManager(); + Chat = new PChat(); + GameCommands = new PCommands(); + + ISC = new PISC(); + Terminal = new PTerminal(); + + Outposts = new POutpost(); + + MultiPartHandler = new PMultiPart(); + + return true; +} + +void Shutdown() +{ + if(MultiPartHandler) + delete MultiPartHandler; + if(Outposts) + delete Outposts; + if(LuaEngine) + delete LuaEngine; + if(Terminal) + delete Terminal; + if(WorldActors) + delete WorldActors; + if(NPCManager) + delete NPCManager; + if(ISC) + { + ISC->Shutdown(); + delete ISC; + } + if(Server) + Server->Shutdown(); + if(GameServer) + delete GameServer; + if(Chat) + delete Chat; + if(Server) + delete Server; + if(Filesystem) + delete Filesystem; + if(GameDefs) + delete GameDefs; + if(Worlds) + { + Worlds->Shutdown(); + delete Worlds; + } + if(Subway) + delete Subway; + if(Chars) + delete Chars; + if(MySQL) + delete MySQL; + if(Config) + delete Config; + if(Console) + delete Console; + if(ServerSock) + delete ServerSock; + + exit(0); +} diff --git a/TinNS/Source/GameServer/Includes.hxx b/TinNS/Source/GameServer/Includes.hxx index e35b5f2..d399724 100644 --- a/TinNS/Source/GameServer/Includes.hxx +++ b/TinNS/Source/GameServer/Includes.hxx @@ -1,89 +1,89 @@ -#pragma once - -#include "GameServer/Accounts.hxx" -#include "GameServer/Appartements.hxx" -#include "GameServer/BuddyList.hxx" -#include "GameServer/Chars.hxx" -#include "GameServer/Chat.hxx" -#include "GameServer/Client.hxx" -#include "GameServer/ClientManager.hxx" -#include "GameServer/Commands.hxx" -#include "GameServer/ConfigTemplate.hxx" -#include "GameServer/Container.hxx" -#include "GameServer/DoorTemplate.hxx" -#include "GameServer/FurnitureTemplate.hxx" -#include "GameServer/GameScript.hxx" -#include "GameServer/GameServer.hxx" -#include "GameServer/GenrepList.hxx" -#include "GameServer/Inventory.hxx" -#include "GameServer/Isc.hxx" -#include "GameServer/Item.hxx" -#include "GameServer/LuaEngine.hxx" -#include "GameServer/Main.hxx" -#include "GameServer/MessageBuilder.hxx" -#include "GameServer/MultiPart.hxx" -#include "GameServer/Npc.hxx" -#include "GameServer/NpcTemplate.hxx" -#include "GameServer/Outpost.hxx" -#include "GameServer/RemoteConsole.hxx" -#include "GameServer/Server.hxx" -#include "GameServer/Skill.hxx" -#include "GameServer/Sql.hxx" -#include "GameServer/Subway.hxx" -#include "GameServer/Terminal.hxx" -#include "GameServer/Vehicle.hxx" -#include "GameServer/VehicleAccessRequest.hxx" -#include "GameServer/WorldActors.hxx" -#include "GameServer/WorldDataTemplate.hxx" -#include "GameServer/Worlds.hxx" -#include "GameServer/Zoning.hxx" - -extern class PLuaEngine *LuaEngine; - -extern class ServerSocket *ServerSock; -extern class PConsole *Console; -//extern class PRConsole *RemoteConsole; -extern class PConfig *Config; -extern class PConfig *CmdAccess; - -extern class PGameDefs *GameDefs; -extern class PFileSystem *Filesystem; -extern class PServer *Server; - -extern class PGameServer *GameServer; -extern class PChars *Chars; - -extern class PMsgBuilder *MsgBuilder; -extern class PWorlds *Worlds; -extern class PAppartements* Appartements; -extern class PWorldActors* WorldActors; -extern class PTerminal* Terminal; -//extern class gmMachine machine; // Virtual Machine instance - -//multiuser chat -extern class PClientManager *ClientManager; -extern class PNPCManager* NPCManager; -extern class PChat *Chat; -extern class PCommands *GameCommands; - -extern class POutpost *Outposts; -extern class PMultiPart *MultiPartHandler; - -// Development debug output control -extern bool gDevDebug; - -//MySQL-Support -extern class PMySQL* MySQL; - -//Vehicles -extern class PVehicles *Vehicles; -extern class PSubway* Subway; - -//Infoserver update -extern class PISC *ISC; - -extern const char ServerVersion[]; -extern const char SVNRevision[]; - -bool InitTinNS(); -void Shutdown(); +#pragma once + +#include "GameServer/Accounts.hxx" +#include "GameServer/Appartements.hxx" +#include "GameServer/BuddyList.hxx" +#include "GameServer/Chars.hxx" +#include "GameServer/Chat.hxx" +#include "GameServer/Client.hxx" +#include "GameServer/ClientManager.hxx" +#include "GameServer/Commands.hxx" +#include "GameServer/ConfigTemplate.hxx" +#include "GameServer/Container.hxx" +#include "GameServer/DoorTemplate.hxx" +#include "GameServer/FurnitureTemplate.hxx" +#include "GameServer/GameScript.hxx" +#include "GameServer/GameServer.hxx" +#include "GameServer/GenrepList.hxx" +#include "GameServer/Inventory.hxx" +#include "GameServer/Isc.hxx" +#include "GameServer/Item.hxx" +#include "GameServer/LuaEngine.hxx" +#include "GameServer/Main.hxx" +#include "GameServer/MessageBuilder.hxx" +#include "GameServer/MultiPart.hxx" +#include "GameServer/Npc.hxx" +#include "GameServer/NpcTemplate.hxx" +#include "GameServer/Outpost.hxx" +#include "GameServer/RemoteConsole.hxx" +#include "GameServer/Server.hxx" +#include "GameServer/Skill.hxx" +#include "GameServer/Sql.hxx" +#include "GameServer/Subway.hxx" +#include "GameServer/Terminal.hxx" +#include "GameServer/Vehicle.hxx" +#include "GameServer/VehicleAccessRequest.hxx" +#include "GameServer/WorldActors.hxx" +#include "GameServer/WorldDataTemplate.hxx" +#include "GameServer/Worlds.hxx" +#include "GameServer/Zoning.hxx" + +extern class PLuaEngine *LuaEngine; + +extern class ServerSocket *ServerSock; +extern class PConsole *Console; +//extern class PRConsole *RemoteConsole; +extern class PConfig *Config; +extern class PConfig *CmdAccess; + +extern class PGameDefs *GameDefs; +extern class PFileSystem *Filesystem; +extern class PServer *Server; + +extern class PGameServer *GameServer; +extern class PChars *Chars; + +extern class PMsgBuilder *MsgBuilder; +extern class PWorlds *Worlds; +extern class PAppartements* Appartements; +extern class PWorldActors* WorldActors; +extern class PTerminal* Terminal; +//extern class gmMachine machine; // Virtual Machine instance + +//multiuser chat +extern class PClientManager *ClientManager; +extern class PNPCManager* NPCManager; +extern class PChat *Chat; +extern class PCommands *GameCommands; + +extern class POutpost *Outposts; +extern class PMultiPart *MultiPartHandler; + +// Development debug output control +extern bool gDevDebug; + +//MySQL-Support +extern class PMySQL* MySQL; + +//Vehicles +extern class PVehicles *Vehicles; +extern class PSubway* Subway; + +//Infoserver update +extern class PISC *ISC; + +extern const char ServerVersion[]; +extern const char SVNRevision[]; + +bool InitTinNS(); +void Shutdown(); diff --git a/TinNS/Source/GameServer/Inventory.cxx b/TinNS/Source/GameServer/Inventory.cxx index 9d82354..5d82f13 100644 --- a/TinNS/Source/GameServer/Inventory.cxx +++ b/TinNS/Source/GameServer/Inventory.cxx @@ -1,118 +1,118 @@ -#include "GameServer/Includes.hxx" - -/* --- PInventory class --- */ - -PInventory::PInventory () -{ - mWorn = new PContainerWithHoles(INV_WORN_MAXSLOTS); - //mBackpack = new PContainer2D(); - mBackpack = new PContainer2DWorkaround(); // until Inside-Backpack item moving issues are solved - mBackpack->Set2DPosMax(INV_BACKPACK_COLS); - mGogo = new PContainerAutoFindFree(INV_GOGO_MAXSLOTS); -} - -PInventory::~PInventory () -{ - delete mWorn; - delete mBackpack; - delete mGogo; -} - -void PInventory::SetCharId(uint32_t CharID) -{ - mWorn->SetInfo(CharID, INV_DB_LOC_WORN); - mBackpack->SetInfo(CharID, INV_DB_LOC_BACKPACK); - mGogo->SetInfo(CharID, INV_DB_LOC_GOGO); -} - -bool PInventory::SQLLoad() -{ - return ( mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad() ); - -/*bool ret = mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad(); -Console->Print(YELLOW, BLACK, "--- Worn Inventory ---"); -mWorn->Dump(); -Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---"); -mBackpack->Dump(); -Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---"); -mGogo->Dump(); -Console->Print(YELLOW, BLACK, "--- End Inventory ---"); -return ret;*/ -} - -bool PInventory::SQLSave() -{ - return mWorn->SQLSave() && mBackpack->SQLSave() && mGogo->SQLSave(); -} - -bool PInventory::IsDirty() const -{ - return (mWorn && mWorn->IsDirty()) || (mBackpack && mBackpack->IsDirty()) || (mGogo && mGogo->IsDirty()); -} - -PContainer* PInventory::GetContainer(uint8_t nInvLoc) -{ - PContainer* tContainer; - switch(nInvLoc) - { - case INV_LOC_WORN: - tContainer = mWorn; - break; - case INV_LOC_BACKPACK: - tContainer = mBackpack; - break; - case INV_LOC_GOGO: - tContainer = mGogo; - break; - default: - tContainer = NULL; - } - return tContainer; -} - -bool PInventory::AddItem(PItem *NewItem, uint8_t nInvLoc, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty) -{ - PContainer* destContainer = GetContainer(nInvLoc); - return(destContainer ? destContainer->AddItem(NewItem, nInvID, nPosX, nPosY, SetDirty) : false); -} - -/* -bool PInventory::QB_IsFree(uint8_t nSlot) -{ - if(nSlot > 9) - return false; - - // if (gDevDebug) Console->Print("Checking QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]); - if(mQuickAccessBelt[nSlot] == 0) - return true; - else - return false; -} - -void PInventory::QB_SetSlot(uint8_t nSlot, uint16_t nItemID) -{ - if(nSlot > 9) - return; - // if (gDevDebug) Console->Print("Setting QBSlot %d. Newcontent: %d Oldcontent: %d", nSlot, nItemID, mQuickAccessBelt[nSlot]); - mQuickAccessBelt[nSlot] = nItemID; -} - -uint16_t PInventory::QB_GetSlot(uint8_t nSlot) -{ - if(nSlot > 9) - return 0; - // if (gDevDebug) Console->Print("Getting QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]); - return mQuickAccessBelt[nSlot]; -} - -void PInventory::QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST) -{ - if(nSlotSRC > 9 || nSlotDST > 9) - return; - - // if (gDevDebug) Console->Print("Moving QBSlot %d [%d] to %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]); - mQuickAccessBelt[nSlotDST] = mQuickAccessBelt[nSlotSRC]; - mQuickAccessBelt[nSlotSRC] = 0; - // if (gDevDebug) Console->Print("Moving done. %d [%d] %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]); -} -*/ +#include "GameServer/Includes.hxx" + +/* --- PInventory class --- */ + +PInventory::PInventory () +{ + mWorn = new PContainerWithHoles(INV_WORN_MAXSLOTS); + //mBackpack = new PContainer2D(); + mBackpack = new PContainer2DWorkaround(); // until Inside-Backpack item moving issues are solved + mBackpack->Set2DPosMax(INV_BACKPACK_COLS); + mGogo = new PContainerAutoFindFree(INV_GOGO_MAXSLOTS); +} + +PInventory::~PInventory () +{ + delete mWorn; + delete mBackpack; + delete mGogo; +} + +void PInventory::SetCharId(uint32_t CharID) +{ + mWorn->SetInfo(CharID, INV_DB_LOC_WORN); + mBackpack->SetInfo(CharID, INV_DB_LOC_BACKPACK); + mGogo->SetInfo(CharID, INV_DB_LOC_GOGO); +} + +bool PInventory::SQLLoad() +{ + return ( mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad() ); + +/*bool ret = mWorn->SQLLoad() && mBackpack->SQLLoad() && mGogo->SQLLoad(); +Console->Print(YELLOW, BLACK, "--- Worn Inventory ---"); +mWorn->Dump(); +Console->Print(YELLOW, BLACK, "--- Backpack Inventory ---"); +mBackpack->Dump(); +Console->Print(YELLOW, BLACK, "--- Gogo Inventory ---"); +mGogo->Dump(); +Console->Print(YELLOW, BLACK, "--- End Inventory ---"); +return ret;*/ +} + +bool PInventory::SQLSave() +{ + return mWorn->SQLSave() && mBackpack->SQLSave() && mGogo->SQLSave(); +} + +bool PInventory::IsDirty() const +{ + return (mWorn && mWorn->IsDirty()) || (mBackpack && mBackpack->IsDirty()) || (mGogo && mGogo->IsDirty()); +} + +PContainer* PInventory::GetContainer(uint8_t nInvLoc) +{ + PContainer* tContainer; + switch(nInvLoc) + { + case INV_LOC_WORN: + tContainer = mWorn; + break; + case INV_LOC_BACKPACK: + tContainer = mBackpack; + break; + case INV_LOC_GOGO: + tContainer = mGogo; + break; + default: + tContainer = NULL; + } + return tContainer; +} + +bool PInventory::AddItem(PItem *NewItem, uint8_t nInvLoc, uint32_t nInvID, uint8_t nPosX, uint8_t nPosY, bool SetDirty) +{ + PContainer* destContainer = GetContainer(nInvLoc); + return(destContainer ? destContainer->AddItem(NewItem, nInvID, nPosX, nPosY, SetDirty) : false); +} + +/* +bool PInventory::QB_IsFree(uint8_t nSlot) +{ + if(nSlot > 9) + return false; + + // if (gDevDebug) Console->Print("Checking QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]); + if(mQuickAccessBelt[nSlot] == 0) + return true; + else + return false; +} + +void PInventory::QB_SetSlot(uint8_t nSlot, uint16_t nItemID) +{ + if(nSlot > 9) + return; + // if (gDevDebug) Console->Print("Setting QBSlot %d. Newcontent: %d Oldcontent: %d", nSlot, nItemID, mQuickAccessBelt[nSlot]); + mQuickAccessBelt[nSlot] = nItemID; +} + +uint16_t PInventory::QB_GetSlot(uint8_t nSlot) +{ + if(nSlot > 9) + return 0; + // if (gDevDebug) Console->Print("Getting QBSlot %d. Content: %d", nSlot, mQuickAccessBelt[nSlot]); + return mQuickAccessBelt[nSlot]; +} + +void PInventory::QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST) +{ + if(nSlotSRC > 9 || nSlotDST > 9) + return; + + // if (gDevDebug) Console->Print("Moving QBSlot %d [%d] to %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]); + mQuickAccessBelt[nSlotDST] = mQuickAccessBelt[nSlotSRC]; + mQuickAccessBelt[nSlotSRC] = 0; + // if (gDevDebug) Console->Print("Moving done. %d [%d] %d [%d]", nSlotSRC, mQuickAccessBelt[nSlotSRC], nSlotDST, mQuickAccessBelt[nSlotDST]); +} +*/ diff --git a/TinNS/Source/GameServer/Inventory.hxx b/TinNS/Source/GameServer/Inventory.hxx index 2218a5c..34b81ff 100644 --- a/TinNS/Source/GameServer/Inventory.hxx +++ b/TinNS/Source/GameServer/Inventory.hxx @@ -1,83 +1,83 @@ -#pragma once - -#include - -//NC containers message locations -#define INV_LOC_GROUND 1 -#define INV_LOC_WORN 2 -#define INV_LOC_BACKPACK 3 -#define INV_LOC_BOX 4 -#define INV_LOC_NPCTRADE 5 -#define INV_LOC_GOGO 18 -#define INV_LOC_BOX2 255 -//PC-Trade window = ? - -//Inventory containers info -#define INV_WORN_QB_START 0 -#define INV_WORN_QB_END 9 -#define INV_WORN_QB_NONE 99 -#define INV_WORN_QB_HAND 11 - -#define INV_WORN_PROC_START 12 -#define INV_WORN_PROC_END 24 - -#define INV_WORN_IMP_START 26 -#define INV_WORN_IMP_END 38 - -#define INV_WORN_ARMOR_START 39 -#define INV_WORN_ARMOR_END 43 - -#define INV_WORN_COLS 44 -#define INV_WORN_MAXSLOTS 44 - - -#define INV_BACKPACK_COLS 10 - -#define INV_GOGO_COLS 5 -#define INV_GOGO_MAXSLOTS 50 - -#define INV_CABINET_COLS 5 -#define INV_CABINET_MAXSLOTS 33 - -// inv_loc values in database -#define INV_DB_LOC_GOGO 1 -#define INV_DB_LOC_WORN 2 -#define INV_DB_LOC_BACKPACK 3 - -class PItem; -class PContainer; -class PContainerWithHoles; -class PContainer2DWorkaround; -class PContainerAutoFindFree; - -class PInventory -{ - private: - PContainerWithHoles* mWorn; // PContainerLinearSlots - PContainer2DWorkaround* mBackpack; // PContainer2DAreas - PContainerAutoFindFree* mGogo; // PContainerLinearSlots - - public: - - PInventory(); - ~PInventory(); - - void SetCharId(uint32_t CharID); - bool SQLLoad(); - bool SQLSave(); - PContainer* GetContainer(uint8_t nInvLoc); - inline PContainer2DWorkaround* GetBackpackContainer() { return mBackpack; } - - bool IsDirty() const; - - bool AddItem(PItem* NewItem, uint8_t nInvLoc = INV_LOC_BACKPACK, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true); - //bool CheckItem(uint32_t ItemID, uint8_t StackSize = 1); - //PItem *GetItem(uint32_t ItemID, uint8_t StackSize = 1); - //PItem *GetItemByPos(uint8_t nPosX, uint8_t nPosY, uint8_t StackSize = 1); - //bool MoveItem(uint8_t oPosX, uint8_t oPosY, uint8_t dPosX, uint8_t dPosY); - - //bool QB_IsFree(uint8_t nSlot); - //void QB_SetSlot(uint8_t nSlot, uint16_t nItemID); - //uint16_t QB_GetSlot(uint8_t nSlot); - //void QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST); -}; +#pragma once + +#include + +//NC containers message locations +#define INV_LOC_GROUND 1 +#define INV_LOC_WORN 2 +#define INV_LOC_BACKPACK 3 +#define INV_LOC_BOX 4 +#define INV_LOC_NPCTRADE 5 +#define INV_LOC_GOGO 18 +#define INV_LOC_BOX2 255 +//PC-Trade window = ? + +//Inventory containers info +#define INV_WORN_QB_START 0 +#define INV_WORN_QB_END 9 +#define INV_WORN_QB_NONE 99 +#define INV_WORN_QB_HAND 11 + +#define INV_WORN_PROC_START 12 +#define INV_WORN_PROC_END 24 + +#define INV_WORN_IMP_START 26 +#define INV_WORN_IMP_END 38 + +#define INV_WORN_ARMOR_START 39 +#define INV_WORN_ARMOR_END 43 + +#define INV_WORN_COLS 44 +#define INV_WORN_MAXSLOTS 44 + + +#define INV_BACKPACK_COLS 10 + +#define INV_GOGO_COLS 5 +#define INV_GOGO_MAXSLOTS 50 + +#define INV_CABINET_COLS 5 +#define INV_CABINET_MAXSLOTS 33 + +// inv_loc values in database +#define INV_DB_LOC_GOGO 1 +#define INV_DB_LOC_WORN 2 +#define INV_DB_LOC_BACKPACK 3 + +class PItem; +class PContainer; +class PContainerWithHoles; +class PContainer2DWorkaround; +class PContainerAutoFindFree; + +class PInventory +{ + private: + PContainerWithHoles* mWorn; // PContainerLinearSlots + PContainer2DWorkaround* mBackpack; // PContainer2DAreas + PContainerAutoFindFree* mGogo; // PContainerLinearSlots + + public: + + PInventory(); + ~PInventory(); + + void SetCharId(uint32_t CharID); + bool SQLLoad(); + bool SQLSave(); + PContainer* GetContainer(uint8_t nInvLoc); + inline PContainer2DWorkaround* GetBackpackContainer() { return mBackpack; } + + bool IsDirty() const; + + bool AddItem(PItem* NewItem, uint8_t nInvLoc = INV_LOC_BACKPACK, uint32_t nInvID = 0, uint8_t nPosX = 0, uint8_t nPosY = 0, bool SetDirty = true); + //bool CheckItem(uint32_t ItemID, uint8_t StackSize = 1); + //PItem *GetItem(uint32_t ItemID, uint8_t StackSize = 1); + //PItem *GetItemByPos(uint8_t nPosX, uint8_t nPosY, uint8_t StackSize = 1); + //bool MoveItem(uint8_t oPosX, uint8_t oPosY, uint8_t dPosX, uint8_t dPosY); + + //bool QB_IsFree(uint8_t nSlot); + //void QB_SetSlot(uint8_t nSlot, uint16_t nItemID); + //uint16_t QB_GetSlot(uint8_t nSlot); + //void QB_Move(uint8_t nSlotSRC, uint8_t nSlotDST); +}; diff --git a/TinNS/Source/GameServer/Isc.cxx b/TinNS/Source/GameServer/Isc.cxx index 0fece43..5115e79 100644 --- a/TinNS/Source/GameServer/Isc.cxx +++ b/TinNS/Source/GameServer/Isc.cxx @@ -1,178 +1,178 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -// TODO: - implement ISC protocol - -PISC::PISC() -{ - use_isc = false; - use_mysql = false; -} - -PISC::~PISC() -{ -} - -void PISC::Start() -{ - isc_method = Config->GetOptionInt("isc_method"); - - if(isc_method & 1) - { - Console->Print("%s Infoserver updating over MySQL is enabled", Console->ColorText(GREEN, BLACK, "[Info]")); - use_mysql = true; - } - if(isc_method & 2) - { - Console->Print("%s Infoserver updating over ISC is enabled, update intervall: infoserver: %s", Console->ColorText(GREEN, BLACK, "[Info]"), "?"); - use_isc = true; - Console->Print("%s Infoserver updating over ISC not implemented yet. DISABLED", Console->ColorText(YELLOW, BLACK, "[Notice]")); - use_isc = false; - } - if(!(use_isc || use_mysql)) - { - Console->Print("%s ISC and MySQL are both disabled, infoserver will NOT be updated", Console->ColorText(YELLOW, BLACK, "[Notice]")); - } - - if (use_isc) - Start_isc(); - - if (use_mysql) - Start_mysql(); - -} - -void PISC::Update() -{ - if (use_isc) - Update_isc(); - - if (use_mysql) - Update_mysql(); -} - -void PISC::Shutdown() -{ - if (use_isc) - { - use_isc = false; - Shutdown_isc(); - } - - if (use_mysql) - { - use_mysql = false; - Shutdown_mysql(); - } -} - -/*** ISC protocol mode specific ***/ - -void PISC::Start_isc() -{ - uint16_t Port = Config->GetOptionInt("isc_infoserverport"); - if (Port == 0) - { - Console->Print("%s Unable to start ISC, isc_infoserverport setting is invalid"); - use_isc = false; - return; - } - Console->Print("Trying to connect to infoserver...", Port); - // Add function for initial connect here and store the connectioninfo somewhere -} - -void PISC::Update_isc() -{ -} - -void PISC::Shutdown_isc() -{ -} - -/*** IMySQL mode specific ***/ - -void PISC::Start_mysql() -{ - m_server_id = Config->GetOptionInt("isc_server_id"); - mysql_update_intervall = Config->GetOptionInt("isc_update_intervall"); - if (mysql_update_intervall < 10) - { - Console->Print("%s value for 'isc_update_intervall' too low (%d). Set to 10 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_update_intervall); - mysql_update_intervall = 10; - } - - mysql_delayed_update_intervall = Config->GetOptionInt("isc_delayed_update_intervall"); - if (mysql_delayed_update_intervall < 0) - { - Console->Print("%s value for 'isc_delayed_update_intervall' is invalid (%d). Set to 0 sec (immediate update)", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_delayed_update_intervall); - mysql_delayed_update_intervall = 0; - } - - mysql_last_update_time = 0; - mysql_last_client_count = 0; - mysql_last_count_decrease_time = 0; - - Update_mysql(); -} - -void PISC::Update_mysql() -{ - bool do_update = false; - std::time_t t = std::time(NULL); - int client_count = Server->GetNumClients(); - - if (((t - mysql_last_update_time) >= mysql_update_intervall) || (client_count > mysql_last_client_count)) - { - do_update = true; -//if(gDevDebug) Console->Print("%s ISC : time or more clients", Console->ColorText(GREEN, BLACK, "[Debug]")); - } - else if (client_count < mysql_last_client_count) - { - if(mysql_last_count_decrease_time && ((t - mysql_last_count_decrease_time) >= mysql_delayed_update_intervall)) - { - do_update = true; -//if(gDevDebug) Console->Print("%s ISC : less clients timed out", Console->ColorText(GREEN, BLACK, "[Debug]")); - } - else if (!mysql_last_count_decrease_time) - { - mysql_last_count_decrease_time = t; -//if(gDevDebug) Console->Print("%s ISC : Starting less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]")); - } - } - else if (mysql_last_count_decrease_time && (client_count == mysql_last_client_count)) - { - mysql_last_count_decrease_time = 0; -//if(gDevDebug) Console->Print("%s ISC : Canceling less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]")); - } - - if (do_update) - { - do_mysql_db_update(client_count); - mysql_last_client_count = client_count; - mysql_last_count_decrease_time = 0; - mysql_last_update_time = std::time(NULL); - } -} - -void PISC::Shutdown_mysql() -{ - use_mysql = false; - do_mysql_db_update(0,true); -} - -bool PISC::do_mysql_db_update(int players, bool shutdown) -{ - char query[256]; - snprintf (query, 256, "UPDATE `server_list` SET `s_players` = '%d', `s_lastupdate` = %s WHERE `s_id` = %d LIMIT 1;", players, (shutdown ? "'0'" : "NOW()"), m_server_id); - -//if(gDevDebug) Console->Print("%s Updating Infoserver over MySQL.", Console->ColorText(GREEN, BLACK, "[Debug]")); - if(MySQL->InfoQuery(query)) - { - use_mysql = false; - Console->Print("%s Could not update Infoserver over MySQL. Updating DISABLED. Error was:", Console->ColorText(RED, BLACK, "[ERROR]")); - MySQL->ShowInfoSQLError(); - return false; - } - else - return true; -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +// TODO: - implement ISC protocol + +PISC::PISC() +{ + use_isc = false; + use_mysql = false; +} + +PISC::~PISC() +{ +} + +void PISC::Start() +{ + isc_method = Config->GetOptionInt("isc_method"); + + if(isc_method & 1) + { + Console->Print("%s Infoserver updating over MySQL is enabled", Console->ColorText(GREEN, BLACK, "[Info]")); + use_mysql = true; + } + if(isc_method & 2) + { + Console->Print("%s Infoserver updating over ISC is enabled, update intervall: infoserver: %s", Console->ColorText(GREEN, BLACK, "[Info]"), "?"); + use_isc = true; + Console->Print("%s Infoserver updating over ISC not implemented yet. DISABLED", Console->ColorText(YELLOW, BLACK, "[Notice]")); + use_isc = false; + } + if(!(use_isc || use_mysql)) + { + Console->Print("%s ISC and MySQL are both disabled, infoserver will NOT be updated", Console->ColorText(YELLOW, BLACK, "[Notice]")); + } + + if (use_isc) + Start_isc(); + + if (use_mysql) + Start_mysql(); + +} + +void PISC::Update() +{ + if (use_isc) + Update_isc(); + + if (use_mysql) + Update_mysql(); +} + +void PISC::Shutdown() +{ + if (use_isc) + { + use_isc = false; + Shutdown_isc(); + } + + if (use_mysql) + { + use_mysql = false; + Shutdown_mysql(); + } +} + +/*** ISC protocol mode specific ***/ + +void PISC::Start_isc() +{ + uint16_t Port = Config->GetOptionInt("isc_infoserverport"); + if (Port == 0) + { + Console->Print("%s Unable to start ISC, isc_infoserverport setting is invalid"); + use_isc = false; + return; + } + Console->Print("Trying to connect to infoserver...", Port); + // Add function for initial connect here and store the connectioninfo somewhere +} + +void PISC::Update_isc() +{ +} + +void PISC::Shutdown_isc() +{ +} + +/*** IMySQL mode specific ***/ + +void PISC::Start_mysql() +{ + m_server_id = Config->GetOptionInt("isc_server_id"); + mysql_update_intervall = Config->GetOptionInt("isc_update_intervall"); + if (mysql_update_intervall < 10) + { + Console->Print("%s value for 'isc_update_intervall' too low (%d). Set to 10 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_update_intervall); + mysql_update_intervall = 10; + } + + mysql_delayed_update_intervall = Config->GetOptionInt("isc_delayed_update_intervall"); + if (mysql_delayed_update_intervall < 0) + { + Console->Print("%s value for 'isc_delayed_update_intervall' is invalid (%d). Set to 0 sec (immediate update)", Console->ColorText(YELLOW, BLACK, "[Notice]"), mysql_delayed_update_intervall); + mysql_delayed_update_intervall = 0; + } + + mysql_last_update_time = 0; + mysql_last_client_count = 0; + mysql_last_count_decrease_time = 0; + + Update_mysql(); +} + +void PISC::Update_mysql() +{ + bool do_update = false; + std::time_t t = std::time(NULL); + int client_count = Server->GetNumClients(); + + if (((t - mysql_last_update_time) >= mysql_update_intervall) || (client_count > mysql_last_client_count)) + { + do_update = true; +//if(gDevDebug) Console->Print("%s ISC : time or more clients", Console->ColorText(GREEN, BLACK, "[Debug]")); + } + else if (client_count < mysql_last_client_count) + { + if(mysql_last_count_decrease_time && ((t - mysql_last_count_decrease_time) >= mysql_delayed_update_intervall)) + { + do_update = true; +//if(gDevDebug) Console->Print("%s ISC : less clients timed out", Console->ColorText(GREEN, BLACK, "[Debug]")); + } + else if (!mysql_last_count_decrease_time) + { + mysql_last_count_decrease_time = t; +//if(gDevDebug) Console->Print("%s ISC : Starting less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]")); + } + } + else if (mysql_last_count_decrease_time && (client_count == mysql_last_client_count)) + { + mysql_last_count_decrease_time = 0; +//if(gDevDebug) Console->Print("%s ISC : Canceling less clients time count", Console->ColorText(GREEN, BLACK, "[Debug]")); + } + + if (do_update) + { + do_mysql_db_update(client_count); + mysql_last_client_count = client_count; + mysql_last_count_decrease_time = 0; + mysql_last_update_time = std::time(NULL); + } +} + +void PISC::Shutdown_mysql() +{ + use_mysql = false; + do_mysql_db_update(0,true); +} + +bool PISC::do_mysql_db_update(int players, bool shutdown) +{ + char query[256]; + snprintf (query, 256, "UPDATE `server_list` SET `s_players` = '%d', `s_lastupdate` = %s WHERE `s_id` = %d LIMIT 1;", players, (shutdown ? "'0'" : "NOW()"), m_server_id); + +//if(gDevDebug) Console->Print("%s Updating Infoserver over MySQL.", Console->ColorText(GREEN, BLACK, "[Debug]")); + if(MySQL->InfoQuery(query)) + { + use_mysql = false; + Console->Print("%s Could not update Infoserver over MySQL. Updating DISABLED. Error was:", Console->ColorText(RED, BLACK, "[ERROR]")); + MySQL->ShowInfoSQLError(); + return false; + } + else + return true; +} diff --git a/TinNS/Source/GameServer/Isc.hxx b/TinNS/Source/GameServer/Isc.hxx index dc04f9e..b0843de 100644 --- a/TinNS/Source/GameServer/Isc.hxx +++ b/TinNS/Source/GameServer/Isc.hxx @@ -1,64 +1,64 @@ -#pragma once - -#include -#include - -#define ISC_VER 2 - -// Part of mConStatus bitmask -#define ISC_CONNECTED 1 -#define ISC_ADMIN 2 - -class PISC { - private: - enum PISC_Status - { - ISC_NOTCONNECTED, - ISC_HANDSHAKE01, // "Hello" msg sent, awaiting answer - ISC_HANDSHAKE02, // PW sent, awaiting answer - ISC_GSDATA01, // Servername sent, awaiting answer - ISC_GSDATA02, // IP, Port & Patchlevel sent, awaiting blabla.. - ISC_GSDATA03, // Players / Staff onlinecounter sent, ... - ISC_GSDATA04, // Minlevel to connect, minlevel to see Playercount, minlevel to see server sent,.... - ISC_CLIENTIDENT, // Awaiting client identification answer - ISC_ADMINLOGIN, // Awaiting answer to Infoserver control login request - ISC_ICTRL_AUTOACC,// Infoserver control: Awaiting response to AutoAccount command - ISC_ICTRL_LOGLV, // Infoserver control: Awaiting response to LoginLevel command - ISC_ICTRL_RELOAD, // Infoserver control: Awaiting response to Reload command - ISC_ICTRL_SHUTD, // Infoserver control: Awaiting response to Shutdown command - ISC_ICTRL_HIDE, // Infoserver control: Awaiting response to HidePeople command - ISC_IDLE // Updateloop running - } mLinkStatus; - - uint16_t mConStatus; // Bitmask of Connection status - - int isc_method; - - bool use_isc; - char isc_pwd; - - bool use_mysql; - int m_server_id; - time_t mysql_update_intervall; - time_t mysql_delayed_update_intervall; - time_t mysql_last_update_time; - int mysql_last_client_count; - time_t mysql_last_count_decrease_time; - - void Start_isc(); - void Update_isc(); - void Shutdown_isc(); - - void Start_mysql(); - void Update_mysql(); - bool do_mysql_db_update(int players, bool shutdown = false); - void Shutdown_mysql(); - - public: - PISC(); - ~PISC(); - - void Start(); - void Update(); - void Shutdown(); -}; +#pragma once + +#include +#include + +#define ISC_VER 2 + +// Part of mConStatus bitmask +#define ISC_CONNECTED 1 +#define ISC_ADMIN 2 + +class PISC { + private: + enum PISC_Status + { + ISC_NOTCONNECTED, + ISC_HANDSHAKE01, // "Hello" msg sent, awaiting answer + ISC_HANDSHAKE02, // PW sent, awaiting answer + ISC_GSDATA01, // Servername sent, awaiting answer + ISC_GSDATA02, // IP, Port & Patchlevel sent, awaiting blabla.. + ISC_GSDATA03, // Players / Staff onlinecounter sent, ... + ISC_GSDATA04, // Minlevel to connect, minlevel to see Playercount, minlevel to see server sent,.... + ISC_CLIENTIDENT, // Awaiting client identification answer + ISC_ADMINLOGIN, // Awaiting answer to Infoserver control login request + ISC_ICTRL_AUTOACC,// Infoserver control: Awaiting response to AutoAccount command + ISC_ICTRL_LOGLV, // Infoserver control: Awaiting response to LoginLevel command + ISC_ICTRL_RELOAD, // Infoserver control: Awaiting response to Reload command + ISC_ICTRL_SHUTD, // Infoserver control: Awaiting response to Shutdown command + ISC_ICTRL_HIDE, // Infoserver control: Awaiting response to HidePeople command + ISC_IDLE // Updateloop running + } mLinkStatus; + + uint16_t mConStatus; // Bitmask of Connection status + + int isc_method; + + bool use_isc; + char isc_pwd; + + bool use_mysql; + int m_server_id; + time_t mysql_update_intervall; + time_t mysql_delayed_update_intervall; + time_t mysql_last_update_time; + int mysql_last_client_count; + time_t mysql_last_count_decrease_time; + + void Start_isc(); + void Update_isc(); + void Shutdown_isc(); + + void Start_mysql(); + void Update_mysql(); + bool do_mysql_db_update(int players, bool shutdown = false); + void Shutdown_mysql(); + + public: + PISC(); + ~PISC(); + + void Start(); + void Update(); + void Shutdown(); +}; diff --git a/TinNS/Source/GameServer/Item.cxx b/TinNS/Source/GameServer/Item.cxx index ce2b4b1..5a3a8e5 100644 --- a/TinNS/Source/GameServer/Item.cxx +++ b/TinNS/Source/GameServer/Item.cxx @@ -1,180 +1,180 @@ -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" - -PItem::PItem(uint32_t ItemID, uint8_t nStackSize, uint8_t CurDur, uint8_t MaxDur, uint8_t Dmg, uint8_t Freq, uint8_t Hand, uint8_t Rng) -{ - mDefItem = GameDefs->Items()->GetDef(ItemID); - if (mDefItem) { - mItemID = ItemID; - mStackable = mDefItem->IsStackable(); - mStackSize = mStackable ? nStackSize : 1; - - mLoadedAmmoId = 0; - mLoadedAmmoNb = 0; - - mPropertiesFlags = 0; - - mUsedSlots = mMaxSlots = 0; - mModificators = 0; - - mConstructorId = 0; - //mType = mDefItem->GetType(); - //mValue1 = mDefItem->GetValue1(); - //mValue2 = mDefItem->GetValue2(); - //mValue3 = mDefItem->GetValue3(); - //mSizeX = mDefItem->GetSizeX(); - //mSizeY = mDefItem->GetSizeY(); - //mWeight = mDefItem->GetWeight(); - //mFillWeight = mDefItem->GetFillWeight(); - //mQualifier = mDefItem->GetQualifier(); - //mItemGroupID = mDefItem->GetItemGroupID(); - //mBasePrice = mDefItem->GetBasePrice(); - //mTechlevel = mDefItem->GetTechlevel(); - //mItemflags = mDefItem->GetItemflags(); - - //if (!mStackable) // only non-stackable items can have quality stats (?) - //{ - // mStackSize = 1; - mCurDuration = CurDur; - mMaxDuration = MaxDur; - mDamages = Dmg; - mFrequency = Freq; - mHandling = Hand; - mRange = Rng; - //} - } - else - { - mItemID = 0; - Console->Print(YELLOW, BLACK, "PItem::PItem: Invalid item ID %d", ItemID); - } -} - -void PItem::MakeItemStandard(uint8_t GlobalQualityMin, uint8_t GlobalQualityMax) -{ - if(GlobalQualityMin > GlobalQualityMax) GlobalQualityMin = GlobalQualityMax; - - mCurDuration = 255; - mMaxDuration = 255; - if(GlobalQualityMin == GlobalQualityMax) - { - mDamages = GlobalQualityMin; - mFrequency = GlobalQualityMin; - mHandling = GlobalQualityMin; - mRange = GlobalQualityMin; - } - else - { - mDamages = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); - mFrequency = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); - mHandling = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); - mRange = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); - } -} - -uint32_t PItem::GetItemID() -{ - return mItemID; -} - -int PItem::GetType() -{ - return mDefItem->GetType(); -} - -uint8_t PItem::GetItemflags() -{ - return mDefItem->GetItemflags(); -} - -const std::string &PItem::GetName() const -{ - return mDefItem->GetName(); -} - -uint8_t PItem::GetSizeX() -{ - return mDefItem->GetSizeX(); -} - -uint8_t PItem::GetSizeY() -{ - return mDefItem->GetSizeY(); -} - -float PItem::GetWeight() -{ - return mStackSize * mDefItem->GetWeight(); -} - -float PItem::GetSingleUnitWeight() -{ - return mDefItem->GetWeight(); -} - -float PItem::GetFillWeight() -{ - return mDefItem->GetFillWeight(); -} - -uint32_t PItem::GetBasePrice() -{ - return mDefItem->GetBasePrice(); -} - -uint16_t PItem::GetTechlevel() -{ - return mDefItem->GetTechlevel(); -} - -int PItem::GetValue1() -{ - return mDefItem->GetValue1(); -} - -int PItem::GetValue2() -{ - return mDefItem->GetValue2(); -} - -int PItem::GetValue3() -{ - return mDefItem->GetValue3(); -} - -int PItem::GetQualifier() -{ - return mDefItem->GetQualifier(); -} - -bool PItem::IsStackable() -{ - return mDefItem->IsStackable(); -} - -uint8_t PItem::GetStackSize() -{ - return mStackSize; -} - -uint8_t PItem::AddToStack(uint8_t ItemNb) // returns nb of items not added -{ - uint8_t addedItems = 0; - if (mStackable) - { - addedItems = (ItemNb <= (MAX_ITEMSTACK_SIZE - mStackSize)) ? ItemNb : (MAX_ITEMSTACK_SIZE - mStackSize); - mStackSize += addedItems; - } - return (ItemNb - addedItems); -} - -uint8_t PItem::TakeFromStack(uint8_t ItemNb) -{ - uint8_t retreivedItems = 0; - if (mStackable) - { - retreivedItems = std::min(mStackSize, ItemNb); - mStackSize -= retreivedItems; - } - return retreivedItems; -} +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" + +PItem::PItem(uint32_t ItemID, uint8_t nStackSize, uint8_t CurDur, uint8_t MaxDur, uint8_t Dmg, uint8_t Freq, uint8_t Hand, uint8_t Rng) +{ + mDefItem = GameDefs->Items()->GetDef(ItemID); + if (mDefItem) { + mItemID = ItemID; + mStackable = mDefItem->IsStackable(); + mStackSize = mStackable ? nStackSize : 1; + + mLoadedAmmoId = 0; + mLoadedAmmoNb = 0; + + mPropertiesFlags = 0; + + mUsedSlots = mMaxSlots = 0; + mModificators = 0; + + mConstructorId = 0; + //mType = mDefItem->GetType(); + //mValue1 = mDefItem->GetValue1(); + //mValue2 = mDefItem->GetValue2(); + //mValue3 = mDefItem->GetValue3(); + //mSizeX = mDefItem->GetSizeX(); + //mSizeY = mDefItem->GetSizeY(); + //mWeight = mDefItem->GetWeight(); + //mFillWeight = mDefItem->GetFillWeight(); + //mQualifier = mDefItem->GetQualifier(); + //mItemGroupID = mDefItem->GetItemGroupID(); + //mBasePrice = mDefItem->GetBasePrice(); + //mTechlevel = mDefItem->GetTechlevel(); + //mItemflags = mDefItem->GetItemflags(); + + //if (!mStackable) // only non-stackable items can have quality stats (?) + //{ + // mStackSize = 1; + mCurDuration = CurDur; + mMaxDuration = MaxDur; + mDamages = Dmg; + mFrequency = Freq; + mHandling = Hand; + mRange = Rng; + //} + } + else + { + mItemID = 0; + Console->Print(YELLOW, BLACK, "PItem::PItem: Invalid item ID %d", ItemID); + } +} + +void PItem::MakeItemStandard(uint8_t GlobalQualityMin, uint8_t GlobalQualityMax) +{ + if(GlobalQualityMin > GlobalQualityMax) GlobalQualityMin = GlobalQualityMax; + + mCurDuration = 255; + mMaxDuration = 255; + if(GlobalQualityMin == GlobalQualityMax) + { + mDamages = GlobalQualityMin; + mFrequency = GlobalQualityMin; + mHandling = GlobalQualityMin; + mRange = GlobalQualityMin; + } + else + { + mDamages = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); + mFrequency = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); + mHandling = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); + mRange = (uint8_t) GetRandom(GlobalQualityMax, GlobalQualityMin); + } +} + +uint32_t PItem::GetItemID() +{ + return mItemID; +} + +int PItem::GetType() +{ + return mDefItem->GetType(); +} + +uint8_t PItem::GetItemflags() +{ + return mDefItem->GetItemflags(); +} + +const std::string &PItem::GetName() const +{ + return mDefItem->GetName(); +} + +uint8_t PItem::GetSizeX() +{ + return mDefItem->GetSizeX(); +} + +uint8_t PItem::GetSizeY() +{ + return mDefItem->GetSizeY(); +} + +float PItem::GetWeight() +{ + return mStackSize * mDefItem->GetWeight(); +} + +float PItem::GetSingleUnitWeight() +{ + return mDefItem->GetWeight(); +} + +float PItem::GetFillWeight() +{ + return mDefItem->GetFillWeight(); +} + +uint32_t PItem::GetBasePrice() +{ + return mDefItem->GetBasePrice(); +} + +uint16_t PItem::GetTechlevel() +{ + return mDefItem->GetTechlevel(); +} + +int PItem::GetValue1() +{ + return mDefItem->GetValue1(); +} + +int PItem::GetValue2() +{ + return mDefItem->GetValue2(); +} + +int PItem::GetValue3() +{ + return mDefItem->GetValue3(); +} + +int PItem::GetQualifier() +{ + return mDefItem->GetQualifier(); +} + +bool PItem::IsStackable() +{ + return mDefItem->IsStackable(); +} + +uint8_t PItem::GetStackSize() +{ + return mStackSize; +} + +uint8_t PItem::AddToStack(uint8_t ItemNb) // returns nb of items not added +{ + uint8_t addedItems = 0; + if (mStackable) + { + addedItems = (ItemNb <= (MAX_ITEMSTACK_SIZE - mStackSize)) ? ItemNb : (MAX_ITEMSTACK_SIZE - mStackSize); + mStackSize += addedItems; + } + return (ItemNb - addedItems); +} + +uint8_t PItem::TakeFromStack(uint8_t ItemNb) +{ + uint8_t retreivedItems = 0; + if (mStackable) + { + retreivedItems = std::min(mStackSize, ItemNb); + mStackSize -= retreivedItems; + } + return retreivedItems; +} diff --git a/TinNS/Source/GameServer/Item.hxx b/TinNS/Source/GameServer/Item.hxx index fbe9668..dce8925 100644 --- a/TinNS/Source/GameServer/Item.hxx +++ b/TinNS/Source/GameServer/Item.hxx @@ -1,112 +1,112 @@ -#pragma once - -#include -#include - -class PDefItems; - -// TODO: Add CreatorID (for "named" item), CurrentMunitionID, CurrentMunitionNb (for weapons & charge-items: muns, -// medkit, etc.) to DB, equipped/free slots, & corresponding code - -#define MAX_ITEMSTACK_SIZE 250 - -//Type -#define ITEM_TYPE_VARIOUS 0 -#define ITEM_TYPE_WEAPON 1 -#define ITEM_TYPE_AMMO 2 -#define ITEM_TYPE_HEALTH 3 -#define ITEM_TYPE_IMPLANT 4 -#define ITEM_TYPE_DRUG 5 -#define ITEM_TYPE_MOD 6 -#define ITEM_TYPE_GFXMOD 7 -#define ITEM_TYPE_BLUEPRINT 8 -#define ITEM_TYPE_ARMOR 9 -#define ITEM_TYPE_PSIMOD 10 -#define ITEM_TYPE_PSIMODREADY 11 -#define ITEM_TYPE_REPAIR 12 -#define ITEM_TYPE_RECYCLER 13 -#define ITEM_TYPE_DATACUBE 14 -#define ITEM_TYPE_CONSTRUCTOR 15 -#define ITEM_TYPE_RESEARCHER 16 -#define ITEM_TYPE_IMPLANTER 17 -#define ITEM_TYPE_APARTMENTKEY 18 -#define ITEM_TYPE_CLANKEY 19 -#define ITEM_TYPE_CASHCUBE 20 -#define ITEM_TYPE_AUTOWEAPON 21 -#define ITEM_TYPE_VHCKEY 22 -#define ITEM_TYPE_UNIDENTPART 24 -#define ITEM_TYPE_WRECKEDPART 25 -#define ITEM_TYPE_SALVAGE 26 -#define ITEM_TYPE_VHCCOMPONENT 27 -#define ITEM_TYPE_RECORDABLE 28 - -// gfxmodflags -#define ITEM_MOD_FLASHLIGHT 1 -#define ITEM_MOD_SCOP 2 -#define ITEM_MOD_SILENCER 4 -#define ITEM_MOD_LASERPOINTER 8 - -// itemflags: -#define ITEM_FLAG_RESEARCHABLE 1 -#define ITEM_FLAG_NO_DROP 2 -#define ITEM_FLAG_NO_MAX_REPAIRE_DECAY 4 -#define ITEM_FLAG_AMMO 8 // for loadable ammo -// not sure for ITEM_FLAG_AMMO - -class PItem { - friend class PContainerEntry; - friend class PMsgBuilder; - - private: - uint32_t mItemID; - const PDefItems* mDefItem; - - bool mStackable; - uint8_t mStackSize; - - uint32_t mLoadedAmmoId; - uint8_t mLoadedAmmoNb; - - uint8_t mPropertiesFlags; - - uint8_t mCurDuration; - uint8_t mMaxDuration; - uint8_t mDamages; - uint8_t mFrequency; - uint8_t mHandling; - uint8_t mRange; - - uint8_t mUsedSlots; - uint8_t mMaxSlots; - uint8_t mSlot[5]; - uint8_t mModificators; - - uint32_t mConstructorId; - - public: - PItem(uint32_t ItemID, uint8_t nStackSize = 1, uint8_t CurDur = 0, uint8_t MaxDur = 0, uint8_t Dmg = 0, uint8_t Freq = 0, uint8_t Hand = 0, uint8_t Rng = 0); - //~PItem(); - void MakeItemStandard(uint8_t GlobalQualityMin = 120, uint8_t GlobalQualityMax = 180); - - uint32_t GetItemID(); - int GetType(); - uint8_t GetItemflags(); - const std::string &GetName() const; - uint8_t GetSizeX(); - uint8_t GetSizeY(); - float GetWeight(); - float GetSingleUnitWeight(); - float GetFillWeight(); - uint32_t GetBasePrice(); - uint16_t GetTechlevel(); - int GetValue1(); - int GetValue2(); - int GetValue3(); - int GetQualifier(); - bool IsStackable(); - uint8_t GetStackSize(); - uint8_t AddToStack(uint8_t ItemNb); // return the nb of items NOT added - uint8_t TakeFromStack(uint8_t ItemNb); // return the nb of retreived items - - //mItemGroupID = def->GetItemGroupID(); -}; +#pragma once + +#include +#include + +class PDefItems; + +// TODO: Add CreatorID (for "named" item), CurrentMunitionID, CurrentMunitionNb (for weapons & charge-items: muns, +// medkit, etc.) to DB, equipped/free slots, & corresponding code + +#define MAX_ITEMSTACK_SIZE 250 + +//Type +#define ITEM_TYPE_VARIOUS 0 +#define ITEM_TYPE_WEAPON 1 +#define ITEM_TYPE_AMMO 2 +#define ITEM_TYPE_HEALTH 3 +#define ITEM_TYPE_IMPLANT 4 +#define ITEM_TYPE_DRUG 5 +#define ITEM_TYPE_MOD 6 +#define ITEM_TYPE_GFXMOD 7 +#define ITEM_TYPE_BLUEPRINT 8 +#define ITEM_TYPE_ARMOR 9 +#define ITEM_TYPE_PSIMOD 10 +#define ITEM_TYPE_PSIMODREADY 11 +#define ITEM_TYPE_REPAIR 12 +#define ITEM_TYPE_RECYCLER 13 +#define ITEM_TYPE_DATACUBE 14 +#define ITEM_TYPE_CONSTRUCTOR 15 +#define ITEM_TYPE_RESEARCHER 16 +#define ITEM_TYPE_IMPLANTER 17 +#define ITEM_TYPE_APARTMENTKEY 18 +#define ITEM_TYPE_CLANKEY 19 +#define ITEM_TYPE_CASHCUBE 20 +#define ITEM_TYPE_AUTOWEAPON 21 +#define ITEM_TYPE_VHCKEY 22 +#define ITEM_TYPE_UNIDENTPART 24 +#define ITEM_TYPE_WRECKEDPART 25 +#define ITEM_TYPE_SALVAGE 26 +#define ITEM_TYPE_VHCCOMPONENT 27 +#define ITEM_TYPE_RECORDABLE 28 + +// gfxmodflags +#define ITEM_MOD_FLASHLIGHT 1 +#define ITEM_MOD_SCOP 2 +#define ITEM_MOD_SILENCER 4 +#define ITEM_MOD_LASERPOINTER 8 + +// itemflags: +#define ITEM_FLAG_RESEARCHABLE 1 +#define ITEM_FLAG_NO_DROP 2 +#define ITEM_FLAG_NO_MAX_REPAIRE_DECAY 4 +#define ITEM_FLAG_AMMO 8 // for loadable ammo +// not sure for ITEM_FLAG_AMMO + +class PItem { + friend class PContainerEntry; + friend class PMsgBuilder; + + private: + uint32_t mItemID; + const PDefItems* mDefItem; + + bool mStackable; + uint8_t mStackSize; + + uint32_t mLoadedAmmoId; + uint8_t mLoadedAmmoNb; + + uint8_t mPropertiesFlags; + + uint8_t mCurDuration; + uint8_t mMaxDuration; + uint8_t mDamages; + uint8_t mFrequency; + uint8_t mHandling; + uint8_t mRange; + + uint8_t mUsedSlots; + uint8_t mMaxSlots; + uint8_t mSlot[5]; + uint8_t mModificators; + + uint32_t mConstructorId; + + public: + PItem(uint32_t ItemID, uint8_t nStackSize = 1, uint8_t CurDur = 0, uint8_t MaxDur = 0, uint8_t Dmg = 0, uint8_t Freq = 0, uint8_t Hand = 0, uint8_t Rng = 0); + //~PItem(); + void MakeItemStandard(uint8_t GlobalQualityMin = 120, uint8_t GlobalQualityMax = 180); + + uint32_t GetItemID(); + int GetType(); + uint8_t GetItemflags(); + const std::string &GetName() const; + uint8_t GetSizeX(); + uint8_t GetSizeY(); + float GetWeight(); + float GetSingleUnitWeight(); + float GetFillWeight(); + uint32_t GetBasePrice(); + uint16_t GetTechlevel(); + int GetValue1(); + int GetValue2(); + int GetValue3(); + int GetQualifier(); + bool IsStackable(); + uint8_t GetStackSize(); + uint8_t AddToStack(uint8_t ItemNb); // return the nb of items NOT added + uint8_t TakeFromStack(uint8_t ItemNb); // return the nb of retreived items + + //mItemGroupID = def->GetItemGroupID(); +}; diff --git a/TinNS/Source/GameServer/Main.hxx b/TinNS/Source/GameServer/Main.hxx index c5b65d7..d153ace 100644 --- a/TinNS/Source/GameServer/Main.hxx +++ b/TinNS/Source/GameServer/Main.hxx @@ -1,52 +1,52 @@ -#pragma once - -//#include "version.h" - -//basic includes -//#include "include/external.h" - -//tinns includes -//#include "include/types.h" -//#include "common/netcode.h" -/* -#include "../gamemonkey/gmMachine.h" -#include "../gamemonkey/gmCall.h" -*/ -//#include "common/console.h" -//#include "common/misc.h" - -// MySQL Support -/* -#ifdef MYSQL_INC_DIR -#include -#else -#include -#endif - -#include "include/sql.h" - -#include "common/config.h" -#include "common/filesystem.h" -#include "include/defparser.h" - -#include "include/skill.h" -#include "include/chars.h" -#include "include/accounts.h" -#include "include/client.h" -#include "include/server.h" -#include "include/gameserver.h" -#include "include/globals.h" -#include "include/defs.h" -#include "include/zoning.h" -#include "include/item.h" -#include "include/inventory.h" -#include "include/worldactors.h" -#include "include/npc.h" -#include "include/outpost.h" -#include "include/multipart.h" -#include "include/terminal.h" - -#include "include/lua_engine.h" -#include "include/chat.h" -#include "include/commands.h" -#include "include/clientmanager.h" */ +#pragma once + +//#include "version.h" + +//basic includes +//#include "include/external.h" + +//tinns includes +//#include "include/types.h" +//#include "common/netcode.h" +/* +#include "../gamemonkey/gmMachine.h" +#include "../gamemonkey/gmCall.h" +*/ +//#include "common/console.h" +//#include "common/misc.h" + +// MySQL Support +/* +#ifdef MYSQL_INC_DIR +#include +#else +#include +#endif + +#include "include/sql.h" + +#include "common/config.h" +#include "common/filesystem.h" +#include "include/defparser.h" + +#include "include/skill.h" +#include "include/chars.h" +#include "include/accounts.h" +#include "include/client.h" +#include "include/server.h" +#include "include/gameserver.h" +#include "include/globals.h" +#include "include/defs.h" +#include "include/zoning.h" +#include "include/item.h" +#include "include/inventory.h" +#include "include/worldactors.h" +#include "include/npc.h" +#include "include/outpost.h" +#include "include/multipart.h" +#include "include/terminal.h" + +#include "include/lua_engine.h" +#include "include/chat.h" +#include "include/commands.h" +#include "include/clientmanager.h" */ diff --git a/TinNS/Source/GameServer/MessageBuilder.cxx b/TinNS/Source/GameServer/MessageBuilder.cxx index c9cd3f9..3456d3a 100644 --- a/TinNS/Source/GameServer/MessageBuilder.cxx +++ b/TinNS/Source/GameServer/MessageBuilder.cxx @@ -155,160 +155,160 @@ PMessage* PMsgBuilder::BuildCharHelloMsg( PClient* nClient ) return tmpMsg; } -PMessage* PMsgBuilder::BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript ) - { - PMessage* tmpMsg; - - tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x19; - *tmpMsg << ( uint16_t )0x0006; // InfoQuery - *tmpMsg << ( uint16_t )0x0003; // NPC Script - *tmpMsg << ( uint32_t )nInfoId; - *tmpMsg << nNPCScript->c_str(); - - return tmpMsg; - - } - -PMessage* PMsgBuilder::BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount ) - { - PMessage* tmpMsg = new PMessage(); - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x0c; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )nClient->GetLocalID(); - *tmpMsg << ( uint8_t )0x3d; - *tmpMsg << ( uint8_t )0x0c; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )nMailCount; - - return tmpMsg; - } - -PMessage* PMsgBuilder::BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string *nCommandName, uint16_t nNumRows, uint16_t nNumFields) - { - PMessage* tmpMsg = new PMessage(); -/* nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x2b; - *tmpMsg << ( uint8_t )0x1a; - if(nCommandName->length() > 0) - *tmpMsg << ( uint8_t )0x01; - else - *tmpMsg << ( uint8_t )0x00; - - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << *nCommandName; - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - // 2nd message - *tmpMsg << ( uint16_t )(13 + nCommandName->length() + nResultBuffer->GetSize()); // ?? - */ - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x2b; - *tmpMsg << ( uint8_t )0x17; - *tmpMsg << ( uint16_t )(nCommandName->length()+1); - *tmpMsg << ( uint16_t )nNumRows; - *tmpMsg << ( uint16_t )nNumFields; - *tmpMsg << *nCommandName; - *tmpMsg << *nResultBuffer; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - - return tmpMsg; - //len = (unsigned int)strlen(DB); - //SendBuffer[0] = 0x13; - //SendBuffer[5] = 11 + len; - //SendBuffer[6] = 0x03; - //Network_IncrementUDP (ClientNum); - //*(unsigned short*)&SendBuffer[7] = Client_Sockets[ClientNum].UDP_ID; - // SendBuffer[9] = 0x2b; - // SendBuffer[10] = 0x1a; - // *(unsigned short*)&SendBuffer[11] = len; - // if (num == 0) - // SendBuffer[13] = 0x00; - // else - // SendBuffer[13] = 0x01; - // SendBuffer[14] = 0x00; - // SendBuffer[15] = 0x00; - // strcpy (SendBuffer+16, DB); - // plen = 17+len; - - // SendBuffer[plen] = 13+len+slen; - // SendBuffer[plen+1] = 0x03; - // Network_IncrementUDP (ClientNum); - // *(unsigned short*)&SendBuffer[plen+2] = Client_Sockets[ClientNum].UDP_ID; - // *(unsigned short*)&SendBuffer[1] = Client_Sockets[ClientNum].UDP_ID; - // *(unsigned short*)&SendBuffer[3] = Client_Sockets[ClientNum].UDP_ID_HIGH; - // SendBuffer[plen+4] = 0x2b; - // SendBuffer[plen+5] = 0x17; - // *(unsigned short*)&SendBuffer[plen+6] = len+1; - // *(unsigned short*)&SendBuffer[plen+8] = num; - // *(unsigned short*)&SendBuffer[plen+10] = Fields; - // //Fieldnum is defined in each DB below - // strcpy (SendBuffer+plen+12, DB); - // plen += 13+len; - - // for (i=0;iIncreaseUDP_ID(); - - *tmpMsg << (uint8_t)0x13; - *tmpMsg << (uint16_t)nClient->GetUDP_ID(); - *tmpMsg << (uint16_t)nClient->GetSessionID(); - *tmpMsg << (uint8_t)0x00; - *tmpMsg << (uint8_t)0x03; - *tmpMsg << (uint16_t)nClient->GetUDP_ID(); - *tmpMsg << (uint8_t)0x2b; - *tmpMsg << (uint8_t)0x1a; - *tmpMsg << (uint16_t)(strlen(nArea)+1); - - if(nAllowed) - *tmpMsg << (uint8_t)0x01; - else - *tmpMsg << (uint8_t)0x00; - - *tmpMsg << (uint8_t)0x00; - *tmpMsg << (uint8_t)0x00; - *tmpMsg << nArea; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - return tmpMsg; - } +PMessage* PMsgBuilder::BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript ) + { + PMessage* tmpMsg; + + tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x19; + *tmpMsg << ( uint16_t )0x0006; // InfoQuery + *tmpMsg << ( uint16_t )0x0003; // NPC Script + *tmpMsg << ( uint32_t )nInfoId; + *tmpMsg << nNPCScript->c_str(); + + return tmpMsg; + + } + +PMessage* PMsgBuilder::BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount ) + { + PMessage* tmpMsg = new PMessage(); + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x0c; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )nClient->GetLocalID(); + *tmpMsg << ( uint8_t )0x3d; + *tmpMsg << ( uint8_t )0x0c; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )nMailCount; + + return tmpMsg; + } + +PMessage* PMsgBuilder::BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string *nCommandName, uint16_t nNumRows, uint16_t nNumFields) + { + PMessage* tmpMsg = new PMessage(); +/* nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x2b; + *tmpMsg << ( uint8_t )0x1a; + if(nCommandName->length() > 0) + *tmpMsg << ( uint8_t )0x01; + else + *tmpMsg << ( uint8_t )0x00; + + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << *nCommandName; + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + // 2nd message + *tmpMsg << ( uint16_t )(13 + nCommandName->length() + nResultBuffer->GetSize()); // ?? + */ + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x2b; + *tmpMsg << ( uint8_t )0x17; + *tmpMsg << ( uint16_t )(nCommandName->length()+1); + *tmpMsg << ( uint16_t )nNumRows; + *tmpMsg << ( uint16_t )nNumFields; + *tmpMsg << *nCommandName; + *tmpMsg << *nResultBuffer; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + + return tmpMsg; + //len = (unsigned int)strlen(DB); + //SendBuffer[0] = 0x13; + //SendBuffer[5] = 11 + len; + //SendBuffer[6] = 0x03; + //Network_IncrementUDP (ClientNum); + //*(unsigned short*)&SendBuffer[7] = Client_Sockets[ClientNum].UDP_ID; + // SendBuffer[9] = 0x2b; + // SendBuffer[10] = 0x1a; + // *(unsigned short*)&SendBuffer[11] = len; + // if (num == 0) + // SendBuffer[13] = 0x00; + // else + // SendBuffer[13] = 0x01; + // SendBuffer[14] = 0x00; + // SendBuffer[15] = 0x00; + // strcpy (SendBuffer+16, DB); + // plen = 17+len; + + // SendBuffer[plen] = 13+len+slen; + // SendBuffer[plen+1] = 0x03; + // Network_IncrementUDP (ClientNum); + // *(unsigned short*)&SendBuffer[plen+2] = Client_Sockets[ClientNum].UDP_ID; + // *(unsigned short*)&SendBuffer[1] = Client_Sockets[ClientNum].UDP_ID; + // *(unsigned short*)&SendBuffer[3] = Client_Sockets[ClientNum].UDP_ID_HIGH; + // SendBuffer[plen+4] = 0x2b; + // SendBuffer[plen+5] = 0x17; + // *(unsigned short*)&SendBuffer[plen+6] = len+1; + // *(unsigned short*)&SendBuffer[plen+8] = num; + // *(unsigned short*)&SendBuffer[plen+10] = Fields; + // //Fieldnum is defined in each DB below + // strcpy (SendBuffer+plen+12, DB); + // plen += 13+len; + + // for (i=0;iIncreaseUDP_ID(); + + *tmpMsg << (uint8_t)0x13; + *tmpMsg << (uint16_t)nClient->GetUDP_ID(); + *tmpMsg << (uint16_t)nClient->GetSessionID(); + *tmpMsg << (uint8_t)0x00; + *tmpMsg << (uint8_t)0x03; + *tmpMsg << (uint16_t)nClient->GetUDP_ID(); + *tmpMsg << (uint8_t)0x2b; + *tmpMsg << (uint8_t)0x1a; + *tmpMsg << (uint16_t)(strlen(nArea)+1); + + if(nAllowed) + *tmpMsg << (uint8_t)0x01; + else + *tmpMsg << (uint8_t)0x00; + + *tmpMsg << (uint8_t)0x00; + *tmpMsg << (uint8_t)0x00; + *tmpMsg << nArea; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + return tmpMsg; + } PMessage* PMsgBuilder::BuildReqInfoAnswerMsg( PClient* nClient, uint16_t nReqType, uint32_t nInfoId, void* nResponse, uint16_t nResponseLength ) { @@ -1463,334 +1463,334 @@ PMessage* PMsgBuilder::BuildSubskillIncMsg( PClient* nClient, uint8_t nSubskill, return tmpMsg; } - */ -// NPC Dialog. Start dialog with NPC -PMessage* PMsgBuilder::BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript ) - { - PMessage* tmpMsg = new PMessage(); - nClient->IncreaseUDP_ID(); - - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder - *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder - *tmpMsg << ( uint8_t )0x00; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )nClient->GetLocalID(); - *tmpMsg << ( uint8_t )0x18; - *tmpMsg << ( uint32_t ) nNPCWorldID; - - // Todo: is this correct? random uint32_t value?? - *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 ); - *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 ); - *tmpMsg << ( uint32_t ) 0x0000; - *tmpMsg << nDialogScript->c_str(); - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x0a; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )nClient->GetLocalID(); - *tmpMsg << ( uint8_t )0x1a; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x00; - - tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID(); - tmpMsg->U16Data( 3 ) = nClient->GetSessionID(); - - return tmpMsg; - } -// NPC Dialog. Send next node number in lua script to client -PMessage* PMsgBuilder::BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector*nResultBuffer) - { - PMessage* tmpMsg = new PMessage(); - - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID();; - *tmpMsg << ( uint16_t )nClient->GetSessionID();; - *tmpMsg << ( uint8_t )0x00; // SubMessage length; - - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID();; - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )nClient->GetLocalID(); - *tmpMsg << ( uint8_t )0x1a; - *tmpMsg << ( uint16_t )nNextNode; - //*tmpMsg << ( uint8_t )nNumResults; - *tmpMsg << ( uint8_t )nResultBuffer->size(); - - std::vector::const_iterator it; - - for(it = nResultBuffer->begin(); it != nResultBuffer->end(); it++) - { - *tmpMsg << ( float )*(it); - } - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - return tmpMsg; - } - -PMessage* PMsgBuilder::BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID ) - { - PMessage* tmpMsg = new PMessage(); - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x00; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )nClient->GetLocalID(); - *tmpMsg << ( uint8_t )0x26; - *tmpMsg << ( uint32_t ) nWorldID; - *tmpMsg << ( uint8_t )0x01; // Traders inventory - *tmpMsg << ( uint16_t )0xFFFF; // Traders inventory - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - return tmpMsg; - } - -PMessage* PMsgBuilder::BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality) - { - PMessage* tmpMsg = new PMessage(); - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x00; // Message length - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x1f; - *tmpMsg << ( uint16_t )nClient->GetLocalID(); - *tmpMsg << ( uint8_t )0x26; - *tmpMsg << ( uint32_t ) nWorldID; - *tmpMsg << ( uint8_t )0x01; // Traders inventory - *tmpMsg << ( uint16_t )( nContentList->GetSize() / 6 ); // List entries - *tmpMsg << ( uint8_t )nItemQuality; // Items quality - *tmpMsg << *nContentList; - - ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); - - return tmpMsg; - } - -// ========================== -PMessage* PMsgBuilder::BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, -uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nUnknown, -uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName) -// Initial NPC Packet that defines how the NPC look, etc - { -// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size(); - - PMessage* tmpMsg = new PMessage(); - nClient->IncreaseUDP_ID(); - - *tmpMsg << ( uint8_t )0x13; // Begin UDP message - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint8_t )0x28; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x01; - *tmpMsg << ( uint32_t )nWorldID; - *tmpMsg << ( uint16_t )nTypeID; - *tmpMsg << ( uint16_t )nClothing; - *tmpMsg << ( uint16_t )nNameID; - *tmpMsg << ( uint16_t )nPosY; - *tmpMsg << ( uint16_t )nPosZ; - *tmpMsg << ( uint16_t )nPosX; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint16_t )nUnknown; - *tmpMsg << ( uint16_t )nTraderID; - *tmpMsg << nNpcName->c_str(); - *tmpMsg << nAngleStr->c_str(); - if(nCustomName->length() > 1) - *tmpMsg << nCustomName->c_str(); - - (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6); - return tmpMsg; - } - -PMessage* PMsgBuilder::BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, -uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, -uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName) -// Initial NPC Packet that defines how the NPC look, etc - { -// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size(); - - PMessage* tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x13; // Begin UDP message - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x03; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint8_t )0x28; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )0x01; - *tmpMsg << ( uint32_t )nWorldID; - *tmpMsg << ( uint16_t )nTypeID; - *tmpMsg << ( uint16_t )nClothing; - *tmpMsg << ( uint16_t )nNameID; - *tmpMsg << ( uint16_t )nPosY; - *tmpMsg << ( uint16_t )nPosZ; - *tmpMsg << ( uint16_t )nPosX; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint16_t )nHealth; - *tmpMsg << ( uint16_t )nTraderID; - *tmpMsg << nNpcName->c_str(); - *tmpMsg << nAngleStr->c_str(); - if(nCustomName->length() > 1) - *tmpMsg << nCustomName->c_str(); - - (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6); - return tmpMsg; - } - -// ************** -PMessage* PMsgBuilder::BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID) - { - PMessage* tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x13; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint8_t )0x00; // len - *tmpMsg << ( uint8_t )0x1b; // NPC Update - *tmpMsg << ( uint32_t )nWorldID; // NPCs world ID - *tmpMsg << ( uint8_t )0x1f; // Parameters - *tmpMsg << ( uint16_t )nPosY; // Position Y - *tmpMsg << ( uint16_t )nPosZ; // Position Z - *tmpMsg << ( uint16_t )nPosX; // Position X - *tmpMsg << ( uint8_t )nActionBM; // NPCs current action-bitmask - *tmpMsg << ( uint16_t )nHealth; // Health value - if(nTargetID > 0) - *tmpMsg << ( uint32_t )nTargetID; // WorldID of NPCs target (if any) - *tmpMsg << ( uint8_t )nUnknown; - *tmpMsg << ( uint8_t )nWeaponState; - - (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6); - - return tmpMsg; - } -// ************** - -PMessage* PMsgBuilder::BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ) - { - PMessage* tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x13; // Begin UDP message - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x11; - *tmpMsg << ( uint8_t )0x1B; - *tmpMsg << ( uint32_t )nWorldID; - *tmpMsg << ( uint8_t )0x1F; - *tmpMsg << ( uint16_t )nY; - *tmpMsg << ( uint16_t )nZ; - *tmpMsg << ( uint16_t )nX; - *tmpMsg << ( uint8_t )nActionStatus; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )nHealth; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )nAction; - - return tmpMsg; - } - -PMessage* PMsgBuilder::BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ) - { - PMessage* tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x13; // Begin UDP message - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint8_t )0x11; - *tmpMsg << ( uint8_t )0x1B; - *tmpMsg << ( uint32_t )nWorldID; - *tmpMsg << ( uint8_t )0x1F; - *tmpMsg << ( uint16_t )nY; - *tmpMsg << ( uint16_t )nZ; - *tmpMsg << ( uint16_t )nX; - *tmpMsg << ( uint8_t )nActionStatus; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )nHealth; - *tmpMsg << ( uint8_t )0x00; - *tmpMsg << ( uint8_t )nAction; - - return tmpMsg; - } - -PMessage* PMsgBuilder::BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ) - { - PMessage* tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x13; // Begin UDP message - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint16_t )0x0000; - *tmpMsg << ( uint8_t )0x15; // Message length - *tmpMsg << ( uint8_t )0x1b; - *tmpMsg << ( uint32_t )nWorldID; - *tmpMsg << ( uint8_t )0x1F; - *tmpMsg << ( uint16_t )nY; - *tmpMsg << ( uint16_t )nZ; - *tmpMsg << ( uint16_t )nX; - *tmpMsg << ( uint8_t )nActionStatus; - *tmpMsg << ( uint8_t )0x77; // ? - *tmpMsg << ( uint8_t )nHealth; - *tmpMsg << ( uint16_t )nTarget; - *tmpMsg << ( uint8_t )0x00; // ? - *tmpMsg << ( uint8_t )0x00; // ? - *tmpMsg << ( uint8_t )0x00; // ? - *tmpMsg << ( uint8_t )nAction; - - return tmpMsg; - } - -// ========================== - -PMessage* PMsgBuilder::BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ) - { - PMessage* tmpMsg = new PMessage(); - - *tmpMsg << ( uint8_t )0x13; // Begin UDP message - *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); - *tmpMsg << ( uint16_t )nClient->GetSessionID(); - *tmpMsg << ( uint8_t )0x15; // Message length - *tmpMsg << ( uint8_t )0x1b; - *tmpMsg << ( uint32_t )nWorldID; - *tmpMsg << ( uint8_t )0x1F; - *tmpMsg << ( uint16_t )nY; - *tmpMsg << ( uint16_t )nZ; - *tmpMsg << ( uint16_t )nX; - *tmpMsg << ( uint8_t )nActionStatus; - *tmpMsg << ( uint8_t )0x77; // ? - *tmpMsg << ( uint8_t )nHealth; - *tmpMsg << ( uint16_t )nTarget; - *tmpMsg << ( uint8_t )0x00; // ? - *tmpMsg << ( uint8_t )0x00; // ? - *tmpMsg << ( uint8_t )0x00; // ? - *tmpMsg << ( uint8_t )nAction; - - return tmpMsg; - } -// ========================== + */ +// NPC Dialog. Start dialog with NPC +PMessage* PMsgBuilder::BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript ) + { + PMessage* tmpMsg = new PMessage(); + nClient->IncreaseUDP_ID(); + + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder + *tmpMsg << ( uint16_t ) 0x0000; // UDP Placeholder + *tmpMsg << ( uint8_t )0x00; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )nClient->GetLocalID(); + *tmpMsg << ( uint8_t )0x18; + *tmpMsg << ( uint32_t ) nNPCWorldID; + + // Todo: is this correct? random uint32_t value?? + *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 ); + *tmpMsg << ( uint16_t ) GetRandom( 65535, 4369 ); + *tmpMsg << ( uint32_t ) 0x0000; + *tmpMsg << nDialogScript->c_str(); + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x0a; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )nClient->GetLocalID(); + *tmpMsg << ( uint8_t )0x1a; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x00; + + tmpMsg->U16Data( 1 ) = nClient->GetUDP_ID(); + tmpMsg->U16Data( 3 ) = nClient->GetSessionID(); + + return tmpMsg; + } +// NPC Dialog. Send next node number in lua script to client +PMessage* PMsgBuilder::BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector*nResultBuffer) + { + PMessage* tmpMsg = new PMessage(); + + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID();; + *tmpMsg << ( uint16_t )nClient->GetSessionID();; + *tmpMsg << ( uint8_t )0x00; // SubMessage length; + + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID();; + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )nClient->GetLocalID(); + *tmpMsg << ( uint8_t )0x1a; + *tmpMsg << ( uint16_t )nNextNode; + //*tmpMsg << ( uint8_t )nNumResults; + *tmpMsg << ( uint8_t )nResultBuffer->size(); + + std::vector::const_iterator it; + + for(it = nResultBuffer->begin(); it != nResultBuffer->end(); it++) + { + *tmpMsg << ( float )*(it); + } + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + return tmpMsg; + } + +PMessage* PMsgBuilder::BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID ) + { + PMessage* tmpMsg = new PMessage(); + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x00; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )nClient->GetLocalID(); + *tmpMsg << ( uint8_t )0x26; + *tmpMsg << ( uint32_t ) nWorldID; + *tmpMsg << ( uint8_t )0x01; // Traders inventory + *tmpMsg << ( uint16_t )0xFFFF; // Traders inventory + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + return tmpMsg; + } + +PMessage* PMsgBuilder::BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality) + { + PMessage* tmpMsg = new PMessage(); + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x00; // Message length + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x1f; + *tmpMsg << ( uint16_t )nClient->GetLocalID(); + *tmpMsg << ( uint8_t )0x26; + *tmpMsg << ( uint32_t ) nWorldID; + *tmpMsg << ( uint8_t )0x01; // Traders inventory + *tmpMsg << ( uint16_t )( nContentList->GetSize() / 6 ); // List entries + *tmpMsg << ( uint8_t )nItemQuality; // Items quality + *tmpMsg << *nContentList; + + ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); + + return tmpMsg; + } + +// ========================== +PMessage* PMsgBuilder::BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, +uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nUnknown, +uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName) +// Initial NPC Packet that defines how the NPC look, etc + { +// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size(); + + PMessage* tmpMsg = new PMessage(); + nClient->IncreaseUDP_ID(); + + *tmpMsg << ( uint8_t )0x13; // Begin UDP message + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint8_t )0x28; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x01; + *tmpMsg << ( uint32_t )nWorldID; + *tmpMsg << ( uint16_t )nTypeID; + *tmpMsg << ( uint16_t )nClothing; + *tmpMsg << ( uint16_t )nNameID; + *tmpMsg << ( uint16_t )nPosY; + *tmpMsg << ( uint16_t )nPosZ; + *tmpMsg << ( uint16_t )nPosX; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint16_t )nUnknown; + *tmpMsg << ( uint16_t )nTraderID; + *tmpMsg << nNpcName->c_str(); + *tmpMsg << nAngleStr->c_str(); + if(nCustomName->length() > 1) + *tmpMsg << nCustomName->c_str(); + + (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6); + return tmpMsg; + } + +PMessage* PMsgBuilder::BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, +uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, +uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName) +// Initial NPC Packet that defines how the NPC look, etc + { +// uint8_t tMsgLen = 29 + nNpcName->size() + nAngleStr->size() + nCustomName->size(); + + PMessage* tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x13; // Begin UDP message + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x03; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint8_t )0x28; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )0x01; + *tmpMsg << ( uint32_t )nWorldID; + *tmpMsg << ( uint16_t )nTypeID; + *tmpMsg << ( uint16_t )nClothing; + *tmpMsg << ( uint16_t )nNameID; + *tmpMsg << ( uint16_t )nPosY; + *tmpMsg << ( uint16_t )nPosZ; + *tmpMsg << ( uint16_t )nPosX; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint16_t )nHealth; + *tmpMsg << ( uint16_t )nTraderID; + *tmpMsg << nNpcName->c_str(); + *tmpMsg << nAngleStr->c_str(); + if(nCustomName->length() > 1) + *tmpMsg << nCustomName->c_str(); + + (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6); + return tmpMsg; + } + +// ************** +PMessage* PMsgBuilder::BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID) + { + PMessage* tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x13; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint8_t )0x00; // len + *tmpMsg << ( uint8_t )0x1b; // NPC Update + *tmpMsg << ( uint32_t )nWorldID; // NPCs world ID + *tmpMsg << ( uint8_t )0x1f; // Parameters + *tmpMsg << ( uint16_t )nPosY; // Position Y + *tmpMsg << ( uint16_t )nPosZ; // Position Z + *tmpMsg << ( uint16_t )nPosX; // Position X + *tmpMsg << ( uint8_t )nActionBM; // NPCs current action-bitmask + *tmpMsg << ( uint16_t )nHealth; // Health value + if(nTargetID > 0) + *tmpMsg << ( uint32_t )nTargetID; // WorldID of NPCs target (if any) + *tmpMsg << ( uint8_t )nUnknown; + *tmpMsg << ( uint8_t )nWeaponState; + + (*tmpMsg)[5] = (uint8_t)(tmpMsg->GetSize() - 6); + + return tmpMsg; + } +// ************** + +PMessage* PMsgBuilder::BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ) + { + PMessage* tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x13; // Begin UDP message + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x11; + *tmpMsg << ( uint8_t )0x1B; + *tmpMsg << ( uint32_t )nWorldID; + *tmpMsg << ( uint8_t )0x1F; + *tmpMsg << ( uint16_t )nY; + *tmpMsg << ( uint16_t )nZ; + *tmpMsg << ( uint16_t )nX; + *tmpMsg << ( uint8_t )nActionStatus; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )nHealth; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )nAction; + + return tmpMsg; + } + +PMessage* PMsgBuilder::BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ) + { + PMessage* tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x13; // Begin UDP message + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint8_t )0x11; + *tmpMsg << ( uint8_t )0x1B; + *tmpMsg << ( uint32_t )nWorldID; + *tmpMsg << ( uint8_t )0x1F; + *tmpMsg << ( uint16_t )nY; + *tmpMsg << ( uint16_t )nZ; + *tmpMsg << ( uint16_t )nX; + *tmpMsg << ( uint8_t )nActionStatus; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )nHealth; + *tmpMsg << ( uint8_t )0x00; + *tmpMsg << ( uint8_t )nAction; + + return tmpMsg; + } + +PMessage* PMsgBuilder::BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ) + { + PMessage* tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x13; // Begin UDP message + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint16_t )0x0000; + *tmpMsg << ( uint8_t )0x15; // Message length + *tmpMsg << ( uint8_t )0x1b; + *tmpMsg << ( uint32_t )nWorldID; + *tmpMsg << ( uint8_t )0x1F; + *tmpMsg << ( uint16_t )nY; + *tmpMsg << ( uint16_t )nZ; + *tmpMsg << ( uint16_t )nX; + *tmpMsg << ( uint8_t )nActionStatus; + *tmpMsg << ( uint8_t )0x77; // ? + *tmpMsg << ( uint8_t )nHealth; + *tmpMsg << ( uint16_t )nTarget; + *tmpMsg << ( uint8_t )0x00; // ? + *tmpMsg << ( uint8_t )0x00; // ? + *tmpMsg << ( uint8_t )0x00; // ? + *tmpMsg << ( uint8_t )nAction; + + return tmpMsg; + } + +// ========================== + +PMessage* PMsgBuilder::BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ) + { + PMessage* tmpMsg = new PMessage(); + + *tmpMsg << ( uint8_t )0x13; // Begin UDP message + *tmpMsg << ( uint16_t )nClient->GetUDP_ID(); + *tmpMsg << ( uint16_t )nClient->GetSessionID(); + *tmpMsg << ( uint8_t )0x15; // Message length + *tmpMsg << ( uint8_t )0x1b; + *tmpMsg << ( uint32_t )nWorldID; + *tmpMsg << ( uint8_t )0x1F; + *tmpMsg << ( uint16_t )nY; + *tmpMsg << ( uint16_t )nZ; + *tmpMsg << ( uint16_t )nX; + *tmpMsg << ( uint8_t )nActionStatus; + *tmpMsg << ( uint8_t )0x77; // ? + *tmpMsg << ( uint8_t )nHealth; + *tmpMsg << ( uint16_t )nTarget; + *tmpMsg << ( uint8_t )0x00; // ? + *tmpMsg << ( uint8_t )0x00; // ? + *tmpMsg << ( uint8_t )0x00; // ? + *tmpMsg << ( uint8_t )nAction; + + return tmpMsg; + } +// ========================== PMessage* PMsgBuilder::BuildSubskillIncMsg( PClient* nClient, uint8_t nSubskill, uint16_t nSkillPoints ) { PMessage* tmpMsg = new PMessage( 33 ); @@ -3612,8 +3612,8 @@ PMessage* PMsgBuilder::BuildNpcCleanupMsg( uint32_t nNpcId, uint8_t nCmd ) ( *tmpMsg )[5] = ( uint8_t )( tmpMsg->GetSize() - 6 ); return tmpMsg; - } - + } + /* void Cmd_GiveItem (int ItemId, int Amount, int ClientNum) diff --git a/TinNS/Source/GameServer/MessageBuilder.hxx b/TinNS/Source/GameServer/MessageBuilder.hxx index df307f5..5e8d2d1 100644 --- a/TinNS/Source/GameServer/MessageBuilder.hxx +++ b/TinNS/Source/GameServer/MessageBuilder.hxx @@ -48,32 +48,32 @@ public: // Temp. NPC update message for testing PMessage* BuildNpcDeathMsg( PClient* nClient, uint32_t nNpcId, uint8_t unknown1 = 0x4a, uint8_t npcAction = 0x1e ); - PMessage* BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName); - PMessage* BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ); - PMessage* BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ); - // Moved here since its a zone broadcast! - PMessage* BuildNpcCleanupMsg( uint32_t nNpcId, uint8_t nCmd = 6 ); // see implementation about nCmd + PMessage* BuildNPCMassInfoMsg( uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName); + PMessage* BuildNPCMassAliveMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ); + PMessage* BuildNPCMassUpdateMsg( uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ); + // Moved here since its a zone broadcast! + PMessage* BuildNpcCleanupMsg( uint32_t nNpcId, uint8_t nCmd = 6 ); // see implementation about nCmd // Following methods for unicast messages DO include UDP_ID increment and // UDP_ID / SessionID setting when needed (at least for now) - PMessage* BuildOutpostClanInfoMsg( PClient* nClient, uint32_t nClanID, uint8_t nFaction ); - PMessage* BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed); - PMessage* BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string* nCommandName, uint16_t nNumRows, uint16_t nNumFields); - PMessage* BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount ); - - PMessage* BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript ); - PMessage* BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector*nResultBuffer); - PMessage* BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript ); - PMessage* BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality); - PMessage* BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID ); - - PMessage* BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName); - PMessage* BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ); - PMessage* BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ); - - // NEW for testing. Combined update message - PMessage* BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID = 0); - + PMessage* BuildOutpostClanInfoMsg( PClient* nClient, uint32_t nClanID, uint8_t nFaction ); + PMessage* BuildTryAccessAnswerMsg(PClient* nClient, char *nArea, bool nAllowed); + PMessage* BuildReceiveDBAnswerMsg( PClient* nClient, PMessage* nResultBuffer, std::string* nCommandName, uint16_t nNumRows, uint16_t nNumFields); + PMessage* BuildYouGotEmailsMsg( PClient* nClient, uint8_t nMailCount ); + + PMessage* BuildNPCStartDialogMsg( PClient* nClient, uint32_t nNPCWorldID, std::string *nDialogScript ); + PMessage* BuildNPCDialogReplyMsg( PClient* nClient, uint16_t nNextNode, std::vector*nResultBuffer); + PMessage* BuildReqNPCScriptAnswerMsg( uint32_t nInfoId, std::string *nNPCScript ); + PMessage* BuildNPCShoppingListMsg( PClient* nClient, PMessage* nContentList, int nWorldID, uint8_t nItemQuality); + PMessage* BuildNPCBeginAllBuyerTradeMsg( PClient* nClient, int nWorldID ); + + PMessage* BuildNPCSingleInfoMsg( PClient* nClient, uint32_t nWorldID, uint16_t nTypeID, uint16_t nClothing, uint16_t nNameID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint16_t nHealth, uint16_t nTraderID, std::string *nAngleStr, std::string *nNpcName, std::string *nCustomName); + PMessage* BuildNPCSingleAliveMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint8_t nAction ); + PMessage* BuildNPCSingleUpdateMsg( PClient* nClient, uint32_t nWorldID, uint16_t nX, uint16_t nY, uint16_t nZ, uint8_t nActionStatus, uint8_t nHealth, uint16_t nTarget, uint8_t nAction ); + + // NEW for testing. Combined update message + PMessage* BuildNPCUpdateMsg(uint32_t nWorldID, uint16_t nPosY, uint16_t nPosZ, uint16_t nPosX, uint8_t nActionBM, uint16_t nHealth, uint8_t nWeaponState, uint8_t nUnknown, uint32_t nTargetID = 0); + PMessage* BuildReqInfoAnswerMsg( PClient* nClient, uint16_t nReqType, uint32_t nInfoId, void* nResponse, uint16_t nResponseLength ); PMessage* BuildPacket0Msg( PClient* nClient ); diff --git a/TinNS/Source/GameServer/Npc.cxx b/TinNS/Source/GameServer/Npc.cxx index bf585b9..b08c947 100644 --- a/TinNS/Source/GameServer/Npc.cxx +++ b/TinNS/Source/GameServer/Npc.cxx @@ -10,29 +10,29 @@ void PNPC::PushUpdateTimer() }; // Reload LUA script while running, in case we modified it and dont want to restart the entire server -bool PNPC::ReloadLUAScript() -{ - // Erase current LUA script - mLUAFile = ""; - - // Reload it - return LoadLUAScript(); -} +bool PNPC::ReloadLUAScript() +{ + // Erase current LUA script + mLUAFile = ""; + + // Reload it + return LoadLUAScript(); +} bool PNPC::DEF_Load(uint32_t nWorldID) { if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from DEF", mWorldID ); const PNPCTemplate* t_defNPC = Worlds->GetWorld(nWorldID)->GetNPCTemplate(mWorldID); - mNameID = (uint16_t)t_defNPC->GetNPCTypeID(); // 16 or 32?? - const PDefNpc* t_NpcTypeDef = GameDefs->Npcs()->GetDef(mNameID); - if(!t_NpcTypeDef) - { - Console->Print("%s [PNPC::DEF_Load()] Unknown NPC Type %d in .dat file found", Console->ColorText(RED,BLACK, "[Error]"), mNameID); - return false; + mNameID = (uint16_t)t_defNPC->GetNPCTypeID(); // 16 or 32?? + const PDefNpc* t_NpcTypeDef = GameDefs->Npcs()->GetDef(mNameID); + if(!t_NpcTypeDef) + { + Console->Print("%s [PNPC::DEF_Load()] Unknown NPC Type %d in .dat file found", Console->ColorText(RED,BLACK, "[Error]"), mNameID); + return false; } - // TODO: Find out what exactly these TypeID and ClothingID values do and where they are generated/read + // TODO: Find out what exactly these TypeID and ClothingID values do and where they are generated/read // Possible (working) solution: Random seed for name generation that happens clientside mTypeID = GetRandom(32767, 1); mClothing = GetRandom(32767, 1); @@ -43,7 +43,7 @@ bool PNPC::DEF_Load(uint32_t nWorldID) mPosZ = t_defNPC->GetPosZ()+32768; mAngle = atoi( t_defNPC->GetAngle().c_str() ); mLoot = t_NpcTypeDef->GetLoot(); - mHealth = t_NpcTypeDef->GetHealth() * NPC_HEALTHFACTOR; + mHealth = t_NpcTypeDef->GetHealth() * NPC_HEALTHFACTOR; mMaxHealth = mHealth; mTrader = t_defNPC->GetTradeID(); mFaction = t_NpcTypeDef->GetFaction(); @@ -51,254 +51,254 @@ bool PNPC::DEF_Load(uint32_t nWorldID) mFromDEF = true; mName = t_defNPC->GetActorName(); - - - // Load dialogscript for this NPC right uppon startup - mDialogScript = t_NpcTypeDef->GetDialogScript(); - CleanUpString(&mDialogScript); - - // Try to load any lua scripts - // Checks are done in target function - LoadLUAScript(); + + + // Load dialogscript for this NPC right uppon startup + mDialogScript = t_NpcTypeDef->GetDialogScript(); + CleanUpString(&mDialogScript); + + // Try to load any lua scripts + // Checks are done in target function + LoadLUAScript(); if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ); - if ( gDevDebug ) Console->Print( "ANG:%d HITPOINTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() ); + if ( gDevDebug ) Console->Print( "ANG:%d HITPOINTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() ); if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() ); return true; } - -bool PNPC::SQL_Load() -{ - if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from SQL", mID ); - MYSQL_RES *result = NULL; - MYSQL_ROW row; - char query[100]; - - snprintf( query, 100, "SELECT * FROM `npc_spawns` WHERE `npc_id` = %d", mID ); - if ( gDevDebug ) Console->Print( "[DEBUG] Executing query %s", query ); - result = MySQL->GameResQuery( query ); - if ( result == NULL ) - { - Console->Print( RED, BLACK, "PNPC::SQL_Load could not load NPC definition" ); - Console->Print( "Query was:" ); - Console->Print( "%s", query ); - MySQL->ShowGameSQLError(); - return false; - } - if ( mysql_num_rows( result ) == 0 ) - { - if ( gDevDebug ) Console->Print( "[DEBUG] No NPCs found, returning false" ); - MySQL->FreeGameSQLResult( result ); - return false; - } - else if ( mysql_num_rows( result ) > 1 ) - { - Console->Print( RED, BLACK, "PNPC::SQL_Load Duplicate entry for NPC %d", mID ); - MySQL->FreeGameSQLResult( result ); - return false; - } - if ( gDevDebug ) Console->Print( "[DEBUG] One NPC found for my ID. Now grabbing data..." ); - row = mysql_fetch_row( result ); - - mWorldID = atoi( row[npc_worldid] ); - mNameID = atoi( row[npc_nameid] ); - mTypeID = atoi( row[npc_typeid] ); - mClothing = atoi( row[npc_clothing] ); - mPosX = atoi( row[npc_x] ); - mPosY = atoi( row[npc_y] ); - mPosZ = atoi( row[npc_z] ); - mAngle = atoi( row[npc_angle] ); - mLoot = atoi( row[npc_loot] ); - mHealth = atoi( row[npc_unknown] ); - mMaxHealth = mHealth; - mTrader = atoi( row[npc_trader] ); - mItemQuality = atoi( row[npc_shop_quality] ); - if(atoi(row[npc_scripting]) == 1) - mScripting = true; - else - mScripting = false; - - if ( row[npc_name] != NULL ) - mName = row[npc_name]; - - if ( row[npc_customname] != NULL ) - mCustomName = row[npc_customname]; - - if ( row[npc_customscript] != NULL ) - mCustomLua = row[npc_customscript]; - - // Now make sure we have an valid NPC here. Besides we need some more information - const PDefNpc* t_npc = GameDefs->Npcs()->GetDef(mNameID); - if(!t_npc) - { - Console->Print( RED, BLACK, "PNPC::SQL_Load Invalid NPC Type found; SQL ID: %d", mID ); - return false; - } - mFaction = t_npc->GetFaction(); - - // Load dialogscript for this NPC right uppon startup - // !-> Only if no custom lua script is attached <-! - if(mCustomLua.length() < 1) - { - if(t_npc->GetDialogScript().length() > 3) - { - size_t tfound; - std::string t_dialogscript = t_npc->GetDialogScript(); - std::string t_replacechr ("\""); - - tfound = t_dialogscript.find(t_replacechr); - while(tfound != std::string::npos) - { - t_dialogscript.replace(tfound, 1, " "); - tfound = t_dialogscript.find( t_replacechr, tfound +1 ); - } - Trim(&t_dialogscript); - if(t_dialogscript.length() > 1) - { - mDialogScript = t_dialogscript; - } - } - } - // Try to load any lua scripts - // Checks are done in target function - LoadLUAScript(); - - if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ); - if ( gDevDebug ) Console->Print( "ANG:%d HITPTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() ); - if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() ); - MySQL->FreeGameSQLResult( result ); - return true; -} - -bool PNPC::LoadLUAScript() -{ - uint32_t tFileLen = 0; - PFile* fLua = NULL; - std::string tLuaFile = ""; - std::string tHDRFile = ""; - - // Load LUA script and include the correct header file - // based in mDialogScript - // if mDialogScript is empty, look at mCustomLua and load this file. Standart include header for custom - // script files is dialogheader.lua since we dont know (yet) what standart header the NC Client uses - // for custom loaded scripts. - - if(mDialogScript.length() > 1) - { - // Get LUA filename from defs - const PDefScripts* tDefScripts = NULL; - std::map::const_iterator itScrStart = GameDefs->Scripts()->ConstIteratorBegin(); - std::map::const_iterator itScrEnd = GameDefs->Scripts()->ConstIteratorEnd(); - for ( std::map::const_iterator i = itScrStart; i != itScrEnd; i++ ) - { - tDefScripts = i->second; - // Console->Print("[DEBUG PNPC::LoadLUAScript] Identifier: [%s] LUA: [%s]", tDefScripts->GetIdentifier().c_str(), tDefScripts->GetLuaFile().c_str()); - - if(tDefScripts->GetIdentifier().compare(mDialogScript) == 0) - { - break; - } - } - // If we left the loop without an positive match.. false! - if(tDefScripts->GetIdentifier().compare(mDialogScript) != 0) - { - return false; - } - - // Assign our LUA file to load later - tLuaFile = tDefScripts->GetLuaFile(); - // MaKe ThE sTrInG aLl lowercase! :) - std::transform(tLuaFile.begin(), tLuaFile.end(), tLuaFile.begin(), (int(*)(int))std::tolower); - - - // We only have 2 headerfiles, so this one is hardcoded - if(tDefScripts->GetScriptHeader() == "DIALOGHEADER") - { - tHDRFile = "scripts/lua/dialogheader.lua"; - } - else if(tDefScripts->GetScriptHeader() == "MISSIONHEADER") - { - tHDRFile = "scripts/lua/missionheader.lua"; - } - } - // Customlua is set? - else if(mCustomLua.length() > 1) - { - // Assign lua file and header - tLuaFile = mCustomLua; - tHDRFile = "scripts/lua/dialogheader.lua"; - } - else - { - // No LUA Scripts to load. Skipping - return true; - } - - // Load HEADER file - fLua = Filesystem->Open( "", tHDRFile.c_str(), Config->GetOption( "nc_data_path" ) ); - if(fLua) - { - tFileLen = fLua->GetSize(); - char* t_content = new char[tFileLen+1]; - memset(t_content, '\0', tFileLen+1); - - fLua->Read( t_content, tFileLen ); - Filesystem->Close( fLua ); - mLUAFile = t_content; - delete t_content; - if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Header Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tHDRFile.c_str() ); - } - else - { - Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Header script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() ); - // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC! - mLUAFile = ""; - mCustomLua = ""; - mDialogScript = ""; - return false; - } - - // Reset vars - tFileLen = 0; - fLua = NULL; - - fLua = Filesystem->Open( "", tLuaFile.c_str(), Config->GetOption( "nc_data_path" ) ); - if(fLua) - { - tFileLen = fLua->GetSize(); - char* t_content = new char[tFileLen+1]; - memset(t_content, '\0', tFileLen+1); - - fLua->Read( t_content, tFileLen ); - Filesystem->Close( fLua ); - mLUAFile += t_content; // APPEND the script to our existing lua headerfile - delete t_content; - if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tLuaFile.c_str() ); - //Console->Print( "%s", mLUAFile.c_str() ); - } - else - { - Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() ); - // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC! - mLUAFile = ""; - mCustomLua = ""; - mDialogScript = ""; - return false; - } - // LUA file prepared. Check if LUA file is valid - if(LuaEngine->CheckLUAFile(mLUAFile) == true) - { - // Everything is fine. NPC is ready for action - return true; - } - else - { - // LUA file seems to be corrupt - mLUAFile = ""; - mCustomLua = ""; - mDialogScript = ""; - return false; - } -} + +bool PNPC::SQL_Load() +{ + if ( gDevDebug ) Console->Print( "[DEBUG] Now loading NPC data for NPC id %d from SQL", mID ); + MYSQL_RES *result = NULL; + MYSQL_ROW row; + char query[100]; + + snprintf( query, 100, "SELECT * FROM `npc_spawns` WHERE `npc_id` = %d", mID ); + if ( gDevDebug ) Console->Print( "[DEBUG] Executing query %s", query ); + result = MySQL->GameResQuery( query ); + if ( result == NULL ) + { + Console->Print( RED, BLACK, "PNPC::SQL_Load could not load NPC definition" ); + Console->Print( "Query was:" ); + Console->Print( "%s", query ); + MySQL->ShowGameSQLError(); + return false; + } + if ( mysql_num_rows( result ) == 0 ) + { + if ( gDevDebug ) Console->Print( "[DEBUG] No NPCs found, returning false" ); + MySQL->FreeGameSQLResult( result ); + return false; + } + else if ( mysql_num_rows( result ) > 1 ) + { + Console->Print( RED, BLACK, "PNPC::SQL_Load Duplicate entry for NPC %d", mID ); + MySQL->FreeGameSQLResult( result ); + return false; + } + if ( gDevDebug ) Console->Print( "[DEBUG] One NPC found for my ID. Now grabbing data..." ); + row = mysql_fetch_row( result ); + + mWorldID = atoi( row[npc_worldid] ); + mNameID = atoi( row[npc_nameid] ); + mTypeID = atoi( row[npc_typeid] ); + mClothing = atoi( row[npc_clothing] ); + mPosX = atoi( row[npc_x] ); + mPosY = atoi( row[npc_y] ); + mPosZ = atoi( row[npc_z] ); + mAngle = atoi( row[npc_angle] ); + mLoot = atoi( row[npc_loot] ); + mHealth = atoi( row[npc_unknown] ); + mMaxHealth = mHealth; + mTrader = atoi( row[npc_trader] ); + mItemQuality = atoi( row[npc_shop_quality] ); + if(atoi(row[npc_scripting]) == 1) + mScripting = true; + else + mScripting = false; + + if ( row[npc_name] != NULL ) + mName = row[npc_name]; + + if ( row[npc_customname] != NULL ) + mCustomName = row[npc_customname]; + + if ( row[npc_customscript] != NULL ) + mCustomLua = row[npc_customscript]; + + // Now make sure we have an valid NPC here. Besides we need some more information + const PDefNpc* t_npc = GameDefs->Npcs()->GetDef(mNameID); + if(!t_npc) + { + Console->Print( RED, BLACK, "PNPC::SQL_Load Invalid NPC Type found; SQL ID: %d", mID ); + return false; + } + mFaction = t_npc->GetFaction(); + + // Load dialogscript for this NPC right uppon startup + // !-> Only if no custom lua script is attached <-! + if(mCustomLua.length() < 1) + { + if(t_npc->GetDialogScript().length() > 3) + { + size_t tfound; + std::string t_dialogscript = t_npc->GetDialogScript(); + std::string t_replacechr ("\""); + + tfound = t_dialogscript.find(t_replacechr); + while(tfound != std::string::npos) + { + t_dialogscript.replace(tfound, 1, " "); + tfound = t_dialogscript.find( t_replacechr, tfound +1 ); + } + Trim(&t_dialogscript); + if(t_dialogscript.length() > 1) + { + mDialogScript = t_dialogscript; + } + } + } + // Try to load any lua scripts + // Checks are done in target function + LoadLUAScript(); + + if ( gDevDebug ) Console->Print( "[DEBUG] NPC: WID:%d NID:%d TID:%d CL:%d PX:%d PY:%d PZ:%d ", mWorldID, mNameID, mTypeID, mClothing, mPosX, mPosY, mPosZ); + if ( gDevDebug ) Console->Print( "ANG:%d HITPTS:%d TRADE:%d LOOT:%d NAME:%s CNAME:%s CUSTOMSCRIPT:%s", mAngle, mHealth, mTrader, mLoot, mName.c_str(), mCustomName.c_str(), mCustomLua.c_str() ); + if ( gDevDebug ) Console->Print( "DIALOGSCR:%s", mDialogScript.c_str() ); + MySQL->FreeGameSQLResult( result ); + return true; +} + +bool PNPC::LoadLUAScript() +{ + uint32_t tFileLen = 0; + PFile* fLua = NULL; + std::string tLuaFile = ""; + std::string tHDRFile = ""; + + // Load LUA script and include the correct header file + // based in mDialogScript + // if mDialogScript is empty, look at mCustomLua and load this file. Standart include header for custom + // script files is dialogheader.lua since we dont know (yet) what standart header the NC Client uses + // for custom loaded scripts. + + if(mDialogScript.length() > 1) + { + // Get LUA filename from defs + const PDefScripts* tDefScripts = NULL; + std::map::const_iterator itScrStart = GameDefs->Scripts()->ConstIteratorBegin(); + std::map::const_iterator itScrEnd = GameDefs->Scripts()->ConstIteratorEnd(); + for ( std::map::const_iterator i = itScrStart; i != itScrEnd; i++ ) + { + tDefScripts = i->second; + // Console->Print("[DEBUG PNPC::LoadLUAScript] Identifier: [%s] LUA: [%s]", tDefScripts->GetIdentifier().c_str(), tDefScripts->GetLuaFile().c_str()); + + if(tDefScripts->GetIdentifier().compare(mDialogScript) == 0) + { + break; + } + } + // If we left the loop without an positive match.. false! + if(tDefScripts->GetIdentifier().compare(mDialogScript) != 0) + { + return false; + } + + // Assign our LUA file to load later + tLuaFile = tDefScripts->GetLuaFile(); + // MaKe ThE sTrInG aLl lowercase! :) + std::transform(tLuaFile.begin(), tLuaFile.end(), tLuaFile.begin(), (int(*)(int))std::tolower); + + + // We only have 2 headerfiles, so this one is hardcoded + if(tDefScripts->GetScriptHeader() == "DIALOGHEADER") + { + tHDRFile = "scripts/lua/dialogheader.lua"; + } + else if(tDefScripts->GetScriptHeader() == "MISSIONHEADER") + { + tHDRFile = "scripts/lua/missionheader.lua"; + } + } + // Customlua is set? + else if(mCustomLua.length() > 1) + { + // Assign lua file and header + tLuaFile = mCustomLua; + tHDRFile = "scripts/lua/dialogheader.lua"; + } + else + { + // No LUA Scripts to load. Skipping + return true; + } + + // Load HEADER file + fLua = Filesystem->Open( "", tHDRFile.c_str(), Config->GetOption( "nc_data_path" ) ); + if(fLua) + { + tFileLen = fLua->GetSize(); + char* t_content = new char[tFileLen+1]; + memset(t_content, '\0', tFileLen+1); + + fLua->Read( t_content, tFileLen ); + Filesystem->Close( fLua ); + mLUAFile = t_content; + delete t_content; + if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Header Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tHDRFile.c_str() ); + } + else + { + Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Header script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() ); + // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC! + mLUAFile = ""; + mCustomLua = ""; + mDialogScript = ""; + return false; + } + + // Reset vars + tFileLen = 0; + fLua = NULL; + + fLua = Filesystem->Open( "", tLuaFile.c_str(), Config->GetOption( "nc_data_path" ) ); + if(fLua) + { + tFileLen = fLua->GetSize(); + char* t_content = new char[tFileLen+1]; + memset(t_content, '\0', tFileLen+1); + + fLua->Read( t_content, tFileLen ); + Filesystem->Close( fLua ); + mLUAFile += t_content; // APPEND the script to our existing lua headerfile + delete t_content; + if (gDevDebug) Console->Print( "%s [PNPC::LoadLUAScript] Loaded LUA Script %s", Console->ColorText( GREEN, BLACK, "[SUCCESS]" ), tLuaFile.c_str() ); + //Console->Print( "%s", mLUAFile.c_str() ); + } + else + { + Console->Print( "%s [PNPC::LoadLUAScript] Unable to load LUA Script %s NPC is now DISABLED for scripting", Console->ColorText( RED, BLACK, "[ERROR]" ), tLuaFile.c_str() ); + // We encountered an error while loading. Make sure this NPC will never act as Dialog NPC! + mLUAFile = ""; + mCustomLua = ""; + mDialogScript = ""; + return false; + } + // LUA file prepared. Check if LUA file is valid + if(LuaEngine->CheckLUAFile(mLUAFile) == true) + { + // Everything is fine. NPC is ready for action + return true; + } + else + { + // LUA file seems to be corrupt + mLUAFile = ""; + mCustomLua = ""; + mDialogScript = ""; + return false; + } +} void PNPC::Die() { @@ -310,18 +310,18 @@ bool PNPC::LoadLUAScript() } void PNPC::Update() -{ +{ // Has to be changed for mobs later if ( std::time( NULL ) >= mRespawn && (mAction&NPC_ACTIONSTATE_DEATH) ) - { + { if ( gDevDebug ) Console->Print( "[DEBUG] NPC Update: Respawn timer triggered! Setting NPC back to life" ); mHealth = mMaxHealth; - mAction = NPC_ACTIONSTATE_IDLE; + mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; mDirty = true; - } + } } - + void PNPC::InitVars() { mID = 0; @@ -333,39 +333,39 @@ void PNPC::InitVars() mPosY = 0; mPosZ = 0; mAngle = 0; - mHealth = 0; + mHealth = 0; mUnknown = 0; mTrader = 0; - mLoot = 0; + mLoot = 0; mDialogScript = ""; mName = ""; mCustomName = ""; mCustomLua = ""; - mAction = NPC_ACTIONSTATE_IDLE; + mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; //mDeath = false; mTarget = 0; mDirty = false; // No need to send instand update // WorldID Fix 10.10.2009 - mFromDEF = false; - mItemQuality = 50; - mScripting = true; - mFaction = 0; - - // Set next update timer for this NPC to 10 - 30 seconds - // Note: this is for regular heartbeats only. If npc is dirty, - // an update is sent anyway + mFromDEF = false; + mItemQuality = 50; + mScripting = true; + mFaction = 0; + + // Set next update timer for this NPC to 10 - 30 seconds + // Note: this is for regular heartbeats only. If npc is dirty, + // an update is sent anyway mNextUpdate = std::time(NULL) + GetRandom(30, 10); } - -void PNPC::Attack( uint32_t nWorldID, uint8_t nType, uint8_t nUnknown ) -{ - mDirty = true; - mTarget = nWorldID; - mAction = NPC_ACTIONSTATE_ATTACK; - mWeaponStatus = nType; - mUnknown = nUnknown; -} + +void PNPC::Attack( uint32_t nWorldID, uint8_t nType, uint8_t nUnknown ) +{ + mDirty = true; + mTarget = nWorldID; + mAction = NPC_ACTIONSTATE_ATTACK; + mWeaponStatus = nType; + mUnknown = nUnknown; +} PNPC::PNPC( int nSQLID ) { @@ -408,83 +408,83 @@ PNPC::PNPC( int nDEFID, uint32_t nWorldID ) */ ///*********************************************************************** ///*********************************************************************** - -// Broadcast a single NPC -void PNPCWorld::BroadcastNewNPC(PNPC* nNpc) -{ - std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle ); - PMessage* tmpMsg = MsgBuilder->BuildNPCMassInfoMsg (nNpc->mWorldID, nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY, - nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr, - &nNpc->mName, &nNpc->mCustomName); - - ClientManager->UDPBroadcast( tmpMsg, mWorldID ); -} - - -bool PNPCWorld::AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID) -{ - PNPC* tmpNpc = new PNPC( nSQL_ID ); - if(tmpNpc->mSuccess == true) - { - // Now broadcast the new NPC to all clients - BroadcastNewNPC(tmpNpc); - mNPCs.insert( std::make_pair( nRaw_ID, tmpNpc ) ); - tmpNpc = NULL; - if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC added" ); - } - else - { - if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC not added due error" ); - delete tmpNpc; - return false; - } - - return true; -} - -void PNPCWorld::DelNPC(uint32_t nWorldID) -{ - PNPCMap::iterator it = mNPCs.find( nWorldID ); - if ( it == mNPCs.end() ) - return; - - // Delete NPC from Map - mNPCs.erase(it); - - // Send Vanish message to clients - PMessage* tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg(nWorldID); - ClientManager->UDPBroadcast( tmpMsg, mWorldID ); - - return; -} - -void PNPCWorld::SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ) -{ - std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle ); - PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY, - nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr, - &nNpc->mName, &nNpc->mCustomName); - - nClient->SendUDPMessage( tmpMsg ); - return; -} + +// Broadcast a single NPC +void PNPCWorld::BroadcastNewNPC(PNPC* nNpc) +{ + std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle ); + PMessage* tmpMsg = MsgBuilder->BuildNPCMassInfoMsg (nNpc->mWorldID, nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY, + nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr, + &nNpc->mName, &nNpc->mCustomName); + + ClientManager->UDPBroadcast( tmpMsg, mWorldID ); +} + + +bool PNPCWorld::AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID) +{ + PNPC* tmpNpc = new PNPC( nSQL_ID ); + if(tmpNpc->mSuccess == true) + { + // Now broadcast the new NPC to all clients + BroadcastNewNPC(tmpNpc); + mNPCs.insert( std::make_pair( nRaw_ID, tmpNpc ) ); + tmpNpc = NULL; + if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC added" ); + } + else + { + if ( gDevDebug ) Console->Print( "[PNPCWorld::AddNPC] Custom NPC not added due error" ); + delete tmpNpc; + return false; + } + + return true; +} + +void PNPCWorld::DelNPC(uint32_t nWorldID) +{ + PNPCMap::iterator it = mNPCs.find( nWorldID ); + if ( it == mNPCs.end() ) + return; + + // Delete NPC from Map + mNPCs.erase(it); + + // Send Vanish message to clients + PMessage* tmpMsg = MsgBuilder->BuildRemoveWorldObjectMsg(nWorldID); + ClientManager->UDPBroadcast( tmpMsg, mWorldID ); + + return; +} + +void PNPCWorld::SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ) +{ + std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle ); + PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY, + nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr, + &nNpc->mName, &nNpc->mCustomName); + + nClient->SendUDPMessage( tmpMsg ); + return; +} void PNPCWorld::MSG_SendNPCs( PClient* nClient ) -{ - PNPC* nNpc = NULL; - for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ ) - { - nNpc = it->second; - - std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle ); - PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY, - nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr, - &nNpc->mName, &nNpc->mCustomName); - - nClient->SendUDPMessage( tmpMsg ); - } - - return; +{ + PNPC* nNpc = NULL; + for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ ) + { + nNpc = it->second; + + std::string tAngleStr = Ssprintf( "%d", nNpc->mAngle ); + PMessage* tmpMsg = MsgBuilder->BuildNPCSingleInfoMsg (nClient, nNpc->GetRealWorldID(), nNpc->mTypeID, nNpc->mClothing, nNpc->mNameID, nNpc->mPosY, + nNpc->mPosZ, nNpc->mPosX, nNpc->mHealth, nNpc->mTrader, &tAngleStr, + &nNpc->mName, &nNpc->mCustomName); + + nClient->SendUDPMessage( tmpMsg ); + } + + return; } bool PNPCWorld::LoadNPCfromSQL() @@ -584,89 +584,89 @@ bool PNPCWorld::LoadNPCfromDEF() delete it->second; mNPCs.erase( it ); } -} - -void PNPCWorld::Update() // v2; New send function -{ - // Updates NPC in a World. - // If NPC is dirty, send "large" update. Else - // send small "i'm alive" message - std::time_t tNow = std::time(NULL); - PNPC* tNPC = NULL; - for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ ) - { - if ( it->second ) - { - tNPC = it->second; - // Check for enemies nearby - CheckForEnemies(tNPC); - // Let NPC make themselfs "dirty" - tNPC->Update(); - // Only update dirty npcs - if ( tNPC->mDirty == true || tNPC->mNextUpdate <= tNow) - { - PMessage* tmpMsg = MsgBuilder->BuildNPCUpdateMsg(tNPC->GetRealWorldID(), - tNPC->mPosY, - tNPC->mPosZ, - tNPC->mPosX, - tNPC->GetActionStatus(), - tNPC->mHealth, - tNPC->GetWeaponStatus(), - tNPC->mUnknown, - tNPC->mTarget); - - ClientManager->UDPBroadcast( tmpMsg, mWorldID ); - tNPC->mDirty = false; - tNPC->PushUpdateTimer(); - } - } - } - - return; +} + +void PNPCWorld::Update() // v2; New send function +{ + // Updates NPC in a World. + // If NPC is dirty, send "large" update. Else + // send small "i'm alive" message + std::time_t tNow = std::time(NULL); + PNPC* tNPC = NULL; + for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ ) + { + if ( it->second ) + { + tNPC = it->second; + // Check for enemies nearby + CheckForEnemies(tNPC); + // Let NPC make themselfs "dirty" + tNPC->Update(); + // Only update dirty npcs + if ( tNPC->mDirty == true || tNPC->mNextUpdate <= tNow) + { + PMessage* tmpMsg = MsgBuilder->BuildNPCUpdateMsg(tNPC->GetRealWorldID(), + tNPC->mPosY, + tNPC->mPosZ, + tNPC->mPosX, + tNPC->GetActionStatus(), + tNPC->mHealth, + tNPC->GetWeaponStatus(), + tNPC->mUnknown, + tNPC->mTarget); + + ClientManager->UDPBroadcast( tmpMsg, mWorldID ); + tNPC->mDirty = false; + tNPC->PushUpdateTimer(); + } + } + } + + return; } -/* +/* void PNPCWorld::Update() -{ - // Updates NPC in a World. - // If NPC is dirty, send "large" update. Else - // send small "i'm alive" message - std::time_t tNow = std::time(NULL); - PNPC* tNPC = NULL; - for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ ) - { - if ( it->second ) - { - tNPC = it->second; - // Check for enemies nearby - CheckForEnemies(tNPC); - // Let NPC make themselfs "dirty" - tNPC->Update(); - // Only update dirty npcs - if ( tNPC->mDirty == true ) - { - PMessage* tmpMsg = MsgBuilder->BuildNPCMassUpdateMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY, - tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mTarget, tNPC->mAction); - - ClientManager->UDPBroadcast( tmpMsg, mWorldID ); - tNPC->mDirty = false; - // Large update also counts as small one, inc update counter - tNPC->PushUpdateTimer(); - } - else if(tNPC->mNextUpdate <= tNow) - { - PMessage* tmpMsg = MsgBuilder->BuildNPCMassAliveMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY, - tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mAction); - - ClientManager->UDPBroadcast( tmpMsg, mWorldID ); - tNPC->PushUpdateTimer(); - } - } - } - - return; +{ + // Updates NPC in a World. + // If NPC is dirty, send "large" update. Else + // send small "i'm alive" message + std::time_t tNow = std::time(NULL); + PNPC* tNPC = NULL; + for ( PNPCMap::iterator it = mNPCs.begin(); it != mNPCs.end(); it++ ) + { + if ( it->second ) + { + tNPC = it->second; + // Check for enemies nearby + CheckForEnemies(tNPC); + // Let NPC make themselfs "dirty" + tNPC->Update(); + // Only update dirty npcs + if ( tNPC->mDirty == true ) + { + PMessage* tmpMsg = MsgBuilder->BuildNPCMassUpdateMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY, + tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mTarget, tNPC->mAction); + + ClientManager->UDPBroadcast( tmpMsg, mWorldID ); + tNPC->mDirty = false; + // Large update also counts as small one, inc update counter + tNPC->PushUpdateTimer(); + } + else if(tNPC->mNextUpdate <= tNow) + { + PMessage* tmpMsg = MsgBuilder->BuildNPCMassAliveMsg( tNPC->GetRealWorldID(), tNPC->mPosX, tNPC->mPosY, + tNPC->mPosZ, tNPC->GetActionStatus(), tNPC->mHealth, tNPC->mAction); + + ClientManager->UDPBroadcast( tmpMsg, mWorldID ); + tNPC->PushUpdateTimer(); + } + } + } + + return; } -*/ +*/ PNPC* PNPCWorld::GetNPC( uint32_t nNPCID ) { if ( gDevDebug ) Console->Print( "[DEBUG] Searching for NPC %d in list", nNPCID ); diff --git a/TinNS/Source/GameServer/Npc.hxx b/TinNS/Source/GameServer/Npc.hxx index 30835d2..678f804 100644 --- a/TinNS/Source/GameServer/Npc.hxx +++ b/TinNS/Source/GameServer/Npc.hxx @@ -6,18 +6,18 @@ #include #include -// Healthfactor for NPCs (see old npc.def) -#define NPC_HEALTHFACTOR 15 - -// Minimum time in seconds that has to pass before an NPC -// gets his heartbeat send -#define NPC_HEARTBEAT_MIN 5 -// Maximum time in seconds that is allowed to pass without -// an NPC heartbeat -#define NPC_HEARTBEAT_MAX 20 - -// If no custom NPC is set in this Zone, what ID to start with? -#define NEW_NPC_ZONEID_START 1000 +// Healthfactor for NPCs (see old npc.def) +#define NPC_HEALTHFACTOR 15 + +// Minimum time in seconds that has to pass before an NPC +// gets his heartbeat send +#define NPC_HEARTBEAT_MIN 5 +// Maximum time in seconds that is allowed to pass without +// an NPC heartbeat +#define NPC_HEARTBEAT_MAX 20 + +// If no custom NPC is set in this Zone, what ID to start with? +#define NEW_NPC_ZONEID_START 1000 // How many seconds have to pass until the zone gets reset? // Reset in: NPCs and PWorld object gets deleted and reloaded when @@ -29,37 +29,37 @@ // How many seconds have to pass until we need an NPC "keepalive" packet? #define NPC_ALIVE_MSG 15 - -// How often a NPC should check if an enemy is nearby? -#define NPC_ENEMYCHECK 5 - -#define NPC_ACTIONSTATE_SITGND 0x00 -#define NPC_ACTIONSTATE_ATTACK 0x01 -//#define NPC_ACTIONSTATE_? 0x02 -//#define NPC_ACTIONSTATE_? 0x04 -//#define NPC_ACTIONSTATE_? 0x08 -#define NPC_ACTIONSTATE_KNEEL 0x10 -#define NPC_ACTIONSTATE_PASSIVE 0x20 -#define NPC_ACTIONSTATE_IDLE 0x40 -#define NPC_ACTIONSTATE_DEATH 0x80 - -#define NPC_SHOOT_IDLE 15 -#define NPC_SHOOT_SINGLE 16 -#define NPC_SHOOT_AUTO1 17 -#define NPC_SHOOT_AUTO2 18 - + +// How often a NPC should check if an enemy is nearby? +#define NPC_ENEMYCHECK 5 + +#define NPC_ACTIONSTATE_SITGND 0x00 +#define NPC_ACTIONSTATE_ATTACK 0x01 +//#define NPC_ACTIONSTATE_? 0x02 +//#define NPC_ACTIONSTATE_? 0x04 +//#define NPC_ACTIONSTATE_? 0x08 +#define NPC_ACTIONSTATE_KNEEL 0x10 +#define NPC_ACTIONSTATE_PASSIVE 0x20 +#define NPC_ACTIONSTATE_IDLE 0x40 +#define NPC_ACTIONSTATE_DEATH 0x80 + +#define NPC_SHOOT_IDLE 15 +#define NPC_SHOOT_SINGLE 16 +#define NPC_SHOOT_AUTO1 17 +#define NPC_SHOOT_AUTO2 18 + class PNPC; class PNPCWorld; typedef std::map PNPCMap; typedef std::map PNPCWorldMap; - + typedef struct { - uint16_t ItemID; + uint16_t ItemID; uint32_t Price; } stShopListEntry; - + class PNPC { private: @@ -81,13 +81,13 @@ private: npc_unknown, npc_trader, // trader.def entry, or clan/faction data! npc_customname, - npc_customscript, - npc_shop_quality, + npc_customscript, + npc_shop_quality, npc_scripting }; - - time_t mNextUpdate; // Timestamp for next heartbeat - time_t mNextEnemyCheck; // Timestamp for next enemycheck + + time_t mNextUpdate; // Timestamp for next heartbeat + time_t mNextEnemyCheck; // Timestamp for next enemycheck void PushUpdateTimer(); // SQL values @@ -101,18 +101,18 @@ private: uint16_t mPosZ; int8_t mAngle; uint16_t mLoot; - uint16_t mTrader; - uint8_t mItemQuality; // Used for Shopping stuff - uint8_t mUnknown; - - std::string mDialogScript; - std::string mLUAFile; // Load File; Preloaded uppon NPC creation - - std::vector mVectItemsInShop; // We need to keep track of the itemorder for shopping - void AddToVectorList(uint16_t nItemID, uint32_t nPrice); - inline const stShopListEntry* GetItemNum(uint32_t nIdx) const { if(nIdx > mVectItemsInShop.size()) { return NULL; } else { return &mVectItemsInShop[nIdx]; }}; - - bool mScripting; // Manual override to disable scripting for an NPC TRUE: Scripts will be executed FALSE: Scripts will be ignored + uint16_t mTrader; + uint8_t mItemQuality; // Used for Shopping stuff + uint8_t mUnknown; + + std::string mDialogScript; + std::string mLUAFile; // Load File; Preloaded uppon NPC creation + + std::vector mVectItemsInShop; // We need to keep track of the itemorder for shopping + void AddToVectorList(uint16_t nItemID, uint32_t nPrice); + inline const stShopListEntry* GetItemNum(uint32_t nIdx) const { if(nIdx > mVectItemsInShop.size()) { return NULL; } else { return &mVectItemsInShop[nIdx]; }}; + + bool mScripting; // Manual override to disable scripting for an NPC TRUE: Scripts will be executed FALSE: Scripts will be ignored std::string mName; std::string mCustomName; @@ -121,63 +121,63 @@ private: time_t mRespawn; // Respawn timer // Runtime values - //bool mDeath; // Death... - uint8_t mFaction; // NPC's faction + //bool mDeath; // Death... + uint8_t mFaction; // NPC's faction - uint16_t mHealth; // NPC Current Health-Value - uint16_t mMaxHealth; // NPC Max Health value + uint16_t mHealth; // NPC Current Health-Value + uint16_t mMaxHealth; // NPC Max Health value uint32_t mTarget; // Current focused player bool mDirty; // Needs update to clients // WorldID Fix 10.10.2009 bool mFromDEF; // to differ DEF NPCs from SQL NPCs - bool mSuccess; // NPC load successfull? - - - uint8_t mAction; // Current action - inline uint8_t GetActionStatus() const { return mAction; }; - // 00000001 ( 1) 0x01: Attack-Mode (Depends on WeaponStatus) - // 00000010 ( 2) 0x02: ? - // 00000100 ( 4) 0x04: ? - // 00001000 ( 8) 0x08: ? - // 00010000 ( 16) 0x10: kneel - // 00100000 ( 32) 0x20: Passive-Mode (Depends on WeaponStatus. Difference between 0x01: NPC does NOT open fire) - // 01000000 ( 64) 0x40: Idle - // 10000000 (128) 0x80: Die - - uint8_t mWeaponStatus; - inline uint8_t GetWeaponStatus() const { return mWeaponStatus; }; - // 00001111 (15) 0x0F: Follow given target with eyes / Put weapon away if pulled - // 00010000 (16) 0x10: Pull weapon if not pulled / If pulled, attack - // 00010001 (17) 0x11: Pull weapon and attack - - + bool mSuccess; // NPC load successfull? + + + uint8_t mAction; // Current action + inline uint8_t GetActionStatus() const { return mAction; }; + // 00000001 ( 1) 0x01: Attack-Mode (Depends on WeaponStatus) + // 00000010 ( 2) 0x02: ? + // 00000100 ( 4) 0x04: ? + // 00001000 ( 8) 0x08: ? + // 00010000 ( 16) 0x10: kneel + // 00100000 ( 32) 0x20: Passive-Mode (Depends on WeaponStatus. Difference between 0x01: NPC does NOT open fire) + // 01000000 ( 64) 0x40: Idle + // 10000000 (128) 0x80: Die + + uint8_t mWeaponStatus; + inline uint8_t GetWeaponStatus() const { return mWeaponStatus; }; + // 00001111 (15) 0x0F: Follow given target with eyes / Put weapon away if pulled + // 00010000 (16) 0x10: Pull weapon if not pulled / If pulled, attack + // 00010001 (17) 0x11: Pull weapon and attack + + bool SQL_Load(); bool DEF_Load(uint32_t nWorldID); - - PNPC( int nSQLID ); - PNPC( int nDEFID, uint32_t nWorldID ); - ~PNPC(); - - void InitVars(); - void ContentListAddItem(PMessage* nContentList, uint16_t nItemID, uint32_t nBasePrice = 0, bool nAddToList = true); - void ContentListAddItemGroup(PMessage* nContentList, uint32_t nItemGroupID); - void StartDialog( PClient* nClient/*, string &nDialogscript */); - - bool DoSQLShoppingList( PClient* nClient, PMessage* nContentList ); - bool HasSQLShoppingList( PClient* nClient ); - bool IsAllbuyer( PClient* nClient ); - bool LoadLUAScript(); - + + PNPC( int nSQLID ); + PNPC( int nDEFID, uint32_t nWorldID ); + ~PNPC(); + + void InitVars(); + void ContentListAddItem(PMessage* nContentList, uint16_t nItemID, uint32_t nBasePrice = 0, bool nAddToList = true); + void ContentListAddItemGroup(PMessage* nContentList, uint32_t nItemGroupID); + void StartDialog( PClient* nClient/*, string &nDialogscript */); + + bool DoSQLShoppingList( PClient* nClient, PMessage* nContentList ); + bool HasSQLShoppingList( PClient* nClient ); + bool IsAllbuyer( PClient* nClient ); + bool LoadLUAScript(); + inline uint32_t GetRealWorldID() { if(mFromDEF == true) return mWorldID+255; else return mWorldID; }; public: friend class PNPCWorld; - - inline void StopAttack() { mDirty = true; mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; }; - inline void Attack( PClient* nClient, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 ) { Attack(nClient->GetChar()->GetID(), nType, nUnknown); }; - void Attack( uint32_t nWorldID, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 ); - + + inline void StopAttack() { mDirty = true; mAction = NPC_ACTIONSTATE_IDLE; mWeaponStatus = NPC_SHOOT_IDLE; }; + inline void Attack( PClient* nClient, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 ) { Attack(nClient->GetChar()->GetID(), nType, nUnknown); }; + void Attack( uint32_t nWorldID, uint8_t nType = NPC_SHOOT_SINGLE, uint8_t nUnknown = 90 ); + inline void Move( uint16_t nNewX, uint16_t nNewY, uint16_t nNewZ ) { mPosX = nNewX; @@ -188,19 +188,19 @@ public: void Die(); // ... die? void Update(); // Check respawn timer - void StartConversation( PClient* nClient ); - void DoConversation( PClient* nClient, uint8_t nAnswer ) ; - - // GameCommands - bool ReloadLUAScript(); - bool ReloadShopList(); - bool SetShopQuality(uint8_t nNewVal); - inline bool IsSQLNPC() const { return !mFromDEF; }; - inline int GetNPCID() const { return mWorldID; }; - inline int GetNPCSQLID() const { return mID; }; - inline void SetTrader( uint16_t nTraderDef ) { mTrader = nTraderDef; }; - inline void SetScripting(bool nVal) { mScripting = nVal; }; - inline uint8_t GetFaction() const { return mFaction; }; + void StartConversation( PClient* nClient ); + void DoConversation( PClient* nClient, uint8_t nAnswer ) ; + + // GameCommands + bool ReloadLUAScript(); + bool ReloadShopList(); + bool SetShopQuality(uint8_t nNewVal); + inline bool IsSQLNPC() const { return !mFromDEF; }; + inline int GetNPCID() const { return mWorldID; }; + inline int GetNPCSQLID() const { return mID; }; + inline void SetTrader( uint16_t nTraderDef ) { mTrader = nTraderDef; }; + inline void SetScripting(bool nVal) { mScripting = nVal; }; + inline uint8_t GetFaction() const { return mFaction; }; }; // ***************************************** @@ -236,19 +236,19 @@ private: //void MSG_SendAlive(); bool LoadNPCfromSQL(); - bool LoadNPCfromDEF(); - - void BroadcastNewNPC(PNPC* nNpc); + bool LoadNPCfromDEF(); + + void BroadcastNewNPC(PNPC* nNpc); void CheckForEnemies(PNPC* nNPC); public: friend class PNPCManager; - PNPC* GetNPC( uint32_t nNPCID ); - - // Functions to add/remove an NPC while server is running - void SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ); // Send - bool AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID); // Load single SQL NPC from given SQL ID - void DelNPC(uint32_t nWorldID); // Remove given NPC from list. Works for *all* npcs + PNPC* GetNPC( uint32_t nNPCID ); + + // Functions to add/remove an NPC while server is running + void SendSingleNPCInfo( PClient* nClient, PNPC* nNpc ); // Send + bool AddNPC(uint32_t nSQL_ID, uint32_t nRaw_ID); // Load single SQL NPC from given SQL ID + void DelNPC(uint32_t nWorldID); // Remove given NPC from list. Works for *all* npcs // but uppon zone reset they're back. }; diff --git a/TinNS/Source/GameServer/RemoteConsole.cxx b/TinNS/Source/GameServer/RemoteConsole.cxx index 3417479..a03dbd4 100644 --- a/TinNS/Source/GameServer/RemoteConsole.cxx +++ b/TinNS/Source/GameServer/RemoteConsole.cxx @@ -1,230 +1,230 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -#if 0 -static const int RCON_INPUTLEN = 512; - -struct PRConClient -{ - enum - { - RCCS_AUTH, - RCCS_AUTH_USER, - RCCS_AUTH_PASS, - RCCS_VALID, - RCCS_DISCONNECT - } mState; - - PSocket *mSocket; - PAccount *mAccount; - char mInput[RCON_INPUTLEN]; - int mInputLen; - bool mEcho; - std::clock_t mSleep, mSleepStart; - int mNumFailures; - - inline PRConClient(NLsocket &Sock) - { - mSocket = new PSocket(Sock); - mAccount = 0; - mInputLen = 0; - mEcho = true; - mSleep = 0; - mSleepStart = 0; - mNumFailures = 0; - } - - inline ~PRConClient() - { - delete mSocket; - } - - inline void Print(const char *Fmt, ...) - { - static char Str[256]; - va_list args; - va_start(args, Fmt); - vsnprintf(Str, 255, Fmt, args); - va_end(args); - mSocket->Write(Str); - } - -}; - -PRConsole::PRConsole() -{ - mListener = NL_INVALID; -} - -PRConsole::~PRConsole() -{ - if(mListener != NL_INVALID) - nlClose(mListener); - - for(ClientList::iterator i=mClients.begin(); i!=mClients.end(); i++) - delete *i; -} - -void PRConsole::Start() -{ - // CHECK FOR rconsole enabled!!! - Console->LPrint("Starting remote console..."); - uint16_t Port = Config->GetOptionInt("rconsole_port"); - mListener = nlOpen(Port, NL_TCP); - if(mListener == NL_INVALID) - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LPrint(" Remote console failed"); - Console->LClose(); - return; - } - - Console->LPrint(GREEN, BLACK, "Success"); - Console->LClose(); - nlListen(mListener); -} - -void PRConsole::Update() -{ - if(mListener==NL_INVALID) - return; - - NLsocket temp = nlAcceptConnection(mListener); - if(temp != NL_INVALID) - { - // TODO: print client ip addr - Console->Print("RConsole: client connected"); - PRConClient *cl = new PRConClient(temp); - cl->mState = PRConClient::RCCS_AUTH; - mClients.push_back(cl); - cl->Print("TinNS shell [%s]\r\n", TINNS_VERSION); - } - - for(ClientList::iterator i=mClients.begin(); i!=mClients.end();) - { - ClientList::iterator j=i; - PRConClient *cl = *i; - ++i; - if(!cl->mSocket->Update() || cl->mSocket->TimeOut()) - { - Console->Print("RConsole: client disconnected"); - mClients.erase(j); - delete cl; - continue; - } - - if(cl->mSleep > 0) - { - std::clock_t t = std::clock(); - cl->mSleep -= (t-cl->mSleepStart); - cl->mSleepStart = t; - - if(cl->mSleep < 0) - cl->mSleep = 0; - - // flush socket while sleeping - int Size=0; - cl->mSocket->Read(&Size); - - continue; - } - - if(cl->mState==PRConClient::RCCS_AUTH) - { - cl->Print("\r\nlogin: "); - cl->mState = PRConClient::RCCS_AUTH_USER; - } - - const uint8_t *Buf = 0; - int Size=0; - if((bool)(Buf = cl->mSocket->Read(&Size))) - { - for(int i=0; imInputLen < RCON_INPUTLEN) - { - switch(Buf[i]) - { - case 0x08 : - { - if(cl->mInputLen > 0) - { - if(cl->mEcho) - cl->mSocket->Write(Buf[i]); - cl->mInput[cl->mInputLen]=0; - --cl->mInputLen; - } - break; - } - - case '\n' : - { - if(cl->mEcho) - cl->mSocket->Write(Buf[i]); - cl->mInput[cl->mInputLen]=0; - ProcessClient(cl); - cl->mInputLen = 0; - break; - } - - default : - { - cl->mInput[cl->mInputLen++]=Buf[i]; - if(cl->mEcho) - cl->mSocket->Write(Buf[i]); - break; - } - } - } - } - } -} - -void PRConsole::ProcessClient(PRConClient* Client) -{ - Console->Print(">%s", Client->mInput); - if(Client->mInputLen > 1) - { - if(Client->mInput[Client->mInputLen-1] == '\r') - Client->mInput[Client->mInputLen-1]=0; - - if(Client->mState == PRConClient::RCCS_AUTH_USER) - { - Client->mAccount = Database->GetAccount(Client->mInput); - Client->mState = PRConClient::RCCS_AUTH_PASS; - Client->Print("password: "); - Client->mEcho = false; - } else - if(Client->mState == PRConClient::RCCS_AUTH_PASS) - { - Client->mEcho = true; - if((!Client->mAccount) || (Client->mAccount->GetPassword() != Client->mInput) || (!Client->mAccount->IsConsoleAllowed())) - { - Client->Print("Invalid user or password\r\n"); - Client->mSleepStart = std::clock(); - ++Client->mNumFailures; - if(Client->mNumFailures >= 3) - { - // sleep 1 minute - Client->mSleep = 60*CLOCKS_PER_SEC; - Client->mNumFailures = 0; - } else - Client->mSleep = 5*CLOCKS_PER_SEC; - - Client->mState = PRConClient::RCCS_AUTH; - } else - { - Client->Print("\r\n\nUser %s logged in\r\n", Client->mAccount->GetName().c_str()); - Client->mState = PRConClient::RCCS_VALID; - // disconnect after 30 minutes lacking socket activity - Client->mSocket->SetTimeOutValue(1800); - Prompt(Client); - } - } - } -} - -void PRConsole::Prompt(PRConClient *Client) -{ - Client->Print("$ ", Client->mAccount->GetName().c_str(), Config->GetOption("server_name").c_str()); -} -#endif +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +#if 0 +static const int RCON_INPUTLEN = 512; + +struct PRConClient +{ + enum + { + RCCS_AUTH, + RCCS_AUTH_USER, + RCCS_AUTH_PASS, + RCCS_VALID, + RCCS_DISCONNECT + } mState; + + PSocket *mSocket; + PAccount *mAccount; + char mInput[RCON_INPUTLEN]; + int mInputLen; + bool mEcho; + std::clock_t mSleep, mSleepStart; + int mNumFailures; + + inline PRConClient(NLsocket &Sock) + { + mSocket = new PSocket(Sock); + mAccount = 0; + mInputLen = 0; + mEcho = true; + mSleep = 0; + mSleepStart = 0; + mNumFailures = 0; + } + + inline ~PRConClient() + { + delete mSocket; + } + + inline void Print(const char *Fmt, ...) + { + static char Str[256]; + va_list args; + va_start(args, Fmt); + vsnprintf(Str, 255, Fmt, args); + va_end(args); + mSocket->Write(Str); + } + +}; + +PRConsole::PRConsole() +{ + mListener = NL_INVALID; +} + +PRConsole::~PRConsole() +{ + if(mListener != NL_INVALID) + nlClose(mListener); + + for(ClientList::iterator i=mClients.begin(); i!=mClients.end(); i++) + delete *i; +} + +void PRConsole::Start() +{ + // CHECK FOR rconsole enabled!!! + Console->LPrint("Starting remote console..."); + uint16_t Port = Config->GetOptionInt("rconsole_port"); + mListener = nlOpen(Port, NL_TCP); + if(mListener == NL_INVALID) + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LPrint(" Remote console failed"); + Console->LClose(); + return; + } + + Console->LPrint(GREEN, BLACK, "Success"); + Console->LClose(); + nlListen(mListener); +} + +void PRConsole::Update() +{ + if(mListener==NL_INVALID) + return; + + NLsocket temp = nlAcceptConnection(mListener); + if(temp != NL_INVALID) + { + // TODO: print client ip addr + Console->Print("RConsole: client connected"); + PRConClient *cl = new PRConClient(temp); + cl->mState = PRConClient::RCCS_AUTH; + mClients.push_back(cl); + cl->Print("TinNS shell [%s]\r\n", TINNS_VERSION); + } + + for(ClientList::iterator i=mClients.begin(); i!=mClients.end();) + { + ClientList::iterator j=i; + PRConClient *cl = *i; + ++i; + if(!cl->mSocket->Update() || cl->mSocket->TimeOut()) + { + Console->Print("RConsole: client disconnected"); + mClients.erase(j); + delete cl; + continue; + } + + if(cl->mSleep > 0) + { + std::clock_t t = std::clock(); + cl->mSleep -= (t-cl->mSleepStart); + cl->mSleepStart = t; + + if(cl->mSleep < 0) + cl->mSleep = 0; + + // flush socket while sleeping + int Size=0; + cl->mSocket->Read(&Size); + + continue; + } + + if(cl->mState==PRConClient::RCCS_AUTH) + { + cl->Print("\r\nlogin: "); + cl->mState = PRConClient::RCCS_AUTH_USER; + } + + const uint8_t *Buf = 0; + int Size=0; + if((bool)(Buf = cl->mSocket->Read(&Size))) + { + for(int i=0; imInputLen < RCON_INPUTLEN) + { + switch(Buf[i]) + { + case 0x08 : + { + if(cl->mInputLen > 0) + { + if(cl->mEcho) + cl->mSocket->Write(Buf[i]); + cl->mInput[cl->mInputLen]=0; + --cl->mInputLen; + } + break; + } + + case '\n' : + { + if(cl->mEcho) + cl->mSocket->Write(Buf[i]); + cl->mInput[cl->mInputLen]=0; + ProcessClient(cl); + cl->mInputLen = 0; + break; + } + + default : + { + cl->mInput[cl->mInputLen++]=Buf[i]; + if(cl->mEcho) + cl->mSocket->Write(Buf[i]); + break; + } + } + } + } + } +} + +void PRConsole::ProcessClient(PRConClient* Client) +{ + Console->Print(">%s", Client->mInput); + if(Client->mInputLen > 1) + { + if(Client->mInput[Client->mInputLen-1] == '\r') + Client->mInput[Client->mInputLen-1]=0; + + if(Client->mState == PRConClient::RCCS_AUTH_USER) + { + Client->mAccount = Database->GetAccount(Client->mInput); + Client->mState = PRConClient::RCCS_AUTH_PASS; + Client->Print("password: "); + Client->mEcho = false; + } else + if(Client->mState == PRConClient::RCCS_AUTH_PASS) + { + Client->mEcho = true; + if((!Client->mAccount) || (Client->mAccount->GetPassword() != Client->mInput) || (!Client->mAccount->IsConsoleAllowed())) + { + Client->Print("Invalid user or password\r\n"); + Client->mSleepStart = std::clock(); + ++Client->mNumFailures; + if(Client->mNumFailures >= 3) + { + // sleep 1 minute + Client->mSleep = 60*CLOCKS_PER_SEC; + Client->mNumFailures = 0; + } else + Client->mSleep = 5*CLOCKS_PER_SEC; + + Client->mState = PRConClient::RCCS_AUTH; + } else + { + Client->Print("\r\n\nUser %s logged in\r\n", Client->mAccount->GetName().c_str()); + Client->mState = PRConClient::RCCS_VALID; + // disconnect after 30 minutes lacking socket activity + Client->mSocket->SetTimeOutValue(1800); + Prompt(Client); + } + } + } +} + +void PRConsole::Prompt(PRConClient *Client) +{ + Client->Print("$ ", Client->mAccount->GetName().c_str(), Config->GetOption("server_name").c_str()); +} +#endif diff --git a/TinNS/Source/GameServer/RemoteConsole.hxx b/TinNS/Source/GameServer/RemoteConsole.hxx index 82bea20..752e21a 100644 --- a/TinNS/Source/GameServer/RemoteConsole.hxx +++ b/TinNS/Source/GameServer/RemoteConsole.hxx @@ -1,22 +1,22 @@ -#pragma once - -#if 0 -#include - -struct PRConClient; - -class PRConsole { -private : - typedef std::list ClientList; - ClientList mClients; - - void ProcessClient(PRConClient* Client); - void Prompt(PRConClient *Client); -public : - PRConsole(); - ~PRConsole(); - - void Start(); - void Update(); -}; -#endif +#pragma once + +#if 0 +#include + +struct PRConClient; + +class PRConsole { +private : + typedef std::list ClientList; + ClientList mClients; + + void ProcessClient(PRConClient* Client); + void Prompt(PRConClient *Client); +public : + PRConsole(); + ~PRConsole(); + + void Start(); + void Update(); +}; +#endif diff --git a/TinNS/Source/GameServer/Server.cxx b/TinNS/Source/GameServer/Server.cxx index a5f9932..3adb838 100644 --- a/TinNS/Source/GameServer/Server.cxx +++ b/TinNS/Source/GameServer/Server.cxx @@ -1,82 +1,82 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -PServer::PServer() -{ - mNumClients = 0; - mMaxClients = Config->GetOptionInt("maxclients"); - mGMSlots = Config->GetOptionInt("gm_slots"); - if(mMaxClients==0) - mMaxClients=1; - if(mGMSlots==0) - mGMSlots=1; - Console->Print("Max clients: %i / GM slots: %i", mMaxClients, mGMSlots); - mClients.reserve(mMaxClients + mGMSlots); - for(int i=0; i= mMaxClients+mGMSlots) - return 0; - - return mClients[Client]; -} - -void PServer::Update() -{ - for(int i=0; iUpdate(); - if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0) - { - Console->Print("Removing client %i...", i); - delete mClients[i]; - mClients[i]=0; - --mNumClients; - } - } - } -} - -void PServer::Shutdown() -{ - Console->Print("======================"); - Console->Print("Shutting down Gameserver..."); - for(int i=0; iGetOptionInt("maxclients"); + mGMSlots = Config->GetOptionInt("gm_slots"); + if(mMaxClients==0) + mMaxClients=1; + if(mGMSlots==0) + mGMSlots=1; + Console->Print("Max clients: %i / GM slots: %i", mMaxClients, mGMSlots); + mClients.reserve(mMaxClients + mGMSlots); + for(int i=0; i= mMaxClients+mGMSlots) + return 0; + + return mClients[Client]; +} + +void PServer::Update() +{ + for(int i=0; iUpdate(); + if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0) + { + Console->Print("Removing client %i...", i); + delete mClients[i]; + mClients[i]=0; + --mNumClients; + } + } + } +} + +void PServer::Shutdown() +{ + Console->Print("======================"); + Console->Print("Shutting down Gameserver..."); + for(int i=0; i -#include - -class PClient; - -class PServer{ -private: - int32_t mMaxClients; - int32_t mGMSlots; - int32_t mNumClients; - std::vector mClients; - -public: - PServer(); - ~PServer(); - - inline int32_t GetMaxClients() const { return mMaxClients; } - inline int32_t GetGMSlots() const { return mGMSlots; } - inline int32_t GetNumClients() const { return mNumClients; } - int NewClient(); - PClient *GetClient(int Client) const; - void Update(); - void Shutdown(); -}; +#pragma once + +#include +#include + +class PClient; + +class PServer{ +private: + int32_t mMaxClients; + int32_t mGMSlots; + int32_t mNumClients; + std::vector mClients; + +public: + PServer(); + ~PServer(); + + inline int32_t GetMaxClients() const { return mMaxClients; } + inline int32_t GetGMSlots() const { return mGMSlots; } + inline int32_t GetNumClients() const { return mNumClients; } + int NewClient(); + PClient *GetClient(int Client) const; + void Update(); + void Shutdown(); +}; diff --git a/TinNS/Source/GameServer/Sql.cxx b/TinNS/Source/GameServer/Sql.cxx index ff2fd8e..9b11437 100644 --- a/TinNS/Source/GameServer/Sql.cxx +++ b/TinNS/Source/GameServer/Sql.cxx @@ -1,429 +1,429 @@ -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -PMySQL::PMySQL() -{ - InfoDBInuse = 0; - GameDBInuse = 0; - info_port = Config->GetOptionInt("info_sql_port"); - strncpy(info_host, Config->GetOption("info_sql_host").c_str(), 100); - strncpy(info_userName, Config->GetOption("info_sql_username").c_str(), 100); - strncpy(info_password, Config->GetOption("info_sql_password").c_str(), 100); - strncpy(info_database, Config->GetOption("info_sql_database").c_str(), 100); - - game_port = Config->GetOptionInt("game_sql_port"); - strncpy(game_host, Config->GetOption("game_sql_host").c_str(), 100); - strncpy(game_userName, Config->GetOption("game_sql_username").c_str(), 100); - strncpy(game_password, Config->GetOption("game_sql_password").c_str(), 100); - strncpy(game_database, Config->GetOption("game_sql_database").c_str(), 100); - - mKeepaliveDelay = (std::time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive - if (mKeepaliveDelay == 0) - { - Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]")); - } - else if (mKeepaliveDelay < 60) - { - Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay); - mKeepaliveDelay = 60; - } - mLastKeepaliveSent = 0; -} - -PMySQL::~PMySQL() -{ - Console->Print("Closing MySQL connection..."); - mysql_close(info_dbHandle); - mysql_close(game_dbHandle); -} - -void PMySQL::Update() -{ - CheckResCount(); // Check for MYSQL_RES mem leak - - // MySQL keepalive - std::time_t t = std::time(NULL); - if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay)) - { - MYSQL_RES *result; - char query[24]; - snprintf (query, 24, "SELECT NOW()"); - - result = GameResQuery(query); - if(!result) - { - Console->Print("%s Can't send GameDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - ShowGameSQLError(); - return; - } - else - FreeGameSQLResult(result); - - result = InfoResQuery(query); - if(!result) - { - Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - ShowInfoSQLError(); - return; - } - else - FreeInfoSQLResult(result); - - mLastKeepaliveSent = std::time(NULL); - if (gDevDebug) Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]")); - } -} - -void PMySQL::CheckResCount() -{ - static int MaxInfoDBCount = 0; - static int MaxGameDBCount = 0; - - if (InfoDBInuse > MaxInfoDBCount) - { - Console->Print("%s Max In-use InfoDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), InfoDBInuse, InfoDBInuse-MaxInfoDBCount); - MaxInfoDBCount = InfoDBInuse; - } - - if (GameDBInuse > MaxGameDBCount) - { - Console->Print("%s Max In-use GameDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), GameDBInuse, GameDBInuse-MaxGameDBCount); - MaxGameDBCount = GameDBInuse; - } -} - -bool PMySQL::Connect() -{ - Console->LPrint("Establishing link to Infoserver Database..."); - - info_dbHandle = mysql_init(NULL); - - if(!info_dbHandle) - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LClose(); - Console->Print(" Unable to create MySQL-Handle!"); - exit(0); - } - - if(!mysql_real_connect(info_dbHandle, info_host, info_userName, info_password, info_database, info_port, NULL, 0)) - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LClose(); - Console->Print("Unable to connect to Infoserver Database. MySQL returned: %s", mysql_error(info_dbHandle)); - } - else - { - Console->LPrint(GREEN, BLACK, "Success"); - Console->LClose(); - } -// <><><><><><><><> Gameserver DB <><><><><><><><> - Console->LPrint("Establishing link to Gameserver Database..."); - - game_dbHandle = mysql_init(NULL); - - if(!game_dbHandle) - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LClose(); - Console->Print(" Unable to create MySQL-Handle!"); - exit(0); - } - - if(!mysql_real_connect(game_dbHandle, game_host, game_userName, game_password, game_database, game_port, NULL, 0)) - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LClose(); - Console->Print("Unable to connect to Gameserver Database. MySQL returned: %s", mysql_error(game_dbHandle)); - return false; - } - else - { - Console->LPrint(GREEN, BLACK, "Success"); - Console->LClose(); - return true; - } - -} -// ---------------------------------------------------- -MYSQL_RES *PMySQL::InfoResQuery(const char *query) -{ - int sql_result = 0; - MYSQL_RES *result; - - sql_result = mysql_real_query(info_dbHandle, query, strlen(query)); - if(sql_result) - { - return NULL; - } - result = mysql_store_result(info_dbHandle); - if(!result) - { - return NULL; - } - //if(InfoDBInuse == true) - /*if(InfoDBInuse > 0) - { - Console->Print("%s another (%d) info_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), InfoDBInuse); - }*/ - - //InfoDBInuse = true; - InfoDBInuse++; - return result; -} - -int PMySQL::InfoQuery(const char *query) -{ - int sql_result = 0; - sql_result = mysql_real_query(info_dbHandle, query, strlen(query)); - - return sql_result; -} - -void PMySQL::ShowInfoSQLError() -{ - Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(info_dbHandle)); -} -void PMySQL::FreeInfoSQLResult(MYSQL_RES *res) -{ - if(InfoDBInuse > 0) - { - mysql_free_result(res); - InfoDBInuse--; - } - else - Console->Print("PMySQL::FreeInfoSQLResult: Nothing to free..."); -} -// ---------------------------------------------------- -MYSQL_RES *PMySQL::GameResQuery(const char *query) -{ - int sql_result = 0; - MYSQL_RES *result; - - sql_result = mysql_real_query(game_dbHandle, query, strlen(query)); - if(sql_result) - { - return NULL; - } - result = mysql_store_result(game_dbHandle); - if(!result) - { - return NULL; - } - /*if(GameDBInuse > 0) - { - Console->Print("%s another (%d) game_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), GameDBInuse); - }*/ - - //GameDBInuse = true; - GameDBInuse++; - return result; -} - -int PMySQL::GameQuery(const char *query) -{ - int sql_result = 0; - sql_result = mysql_real_query(game_dbHandle, query, strlen(query)); - - return sql_result; -} - -void PMySQL::ShowGameSQLError() -{ - Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(game_dbHandle)); -} - -void PMySQL::FreeGameSQLResult(MYSQL_RES *res) -{ - if(GameDBInuse > 0) - { - mysql_free_result(res); - GameDBInuse--; - } - else - Console->Print("PMySQL::FreeGameSQLResult: Nothing to free..."); -} - -uint32_t PMySQL::EscapeString(const char* nText, char* dText, uint32_t dMaxLength) -{ - uint32_t nLength = strlen(nText); - uint32_t tMax = (dMaxLength - 1)/2; - if(nLength > tMax) - { - nLength = tMax; - } - - return mysql_real_escape_string(game_dbHandle, dText, nText, nLength); -} - -// ---------------------------------------------------- -/* -int PMySQL::GetWorldItemType(unsigned short ID, int Location) -{ - char query[2048]; - MYSQL_RES *result; - MYSQL_ROW row; - - if (Location > 100000) - { - //int nAppLoc = GetAptLocation(Location); - int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID - if (nAppLoc) - snprintf(query, 2048, "SELECT ai_type FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", ID, nAppLoc); - else - return 0; - } - else - snprintf(query, 2048, "SELECT wi_type FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", ID, Location); - - result = GameResQuery(query); - if(!result) - { - Console->Print("%s Cannot get WorldItemType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - ShowGameSQLError(); - return 0; - } - else - { - if(mysql_num_rows(result) > 1) - { - FreeGameSQLResult(result); - return -2; - } - else - { - row = mysql_fetch_row(result); - if(row == NULL) - { - FreeGameSQLResult(result); - return -1; - } - int ret_val = std::atoi(row[0]); - FreeGameSQLResult(result); - return ret_val; - } - } -// else -// { -// FreeGameSQLResult(result); -// return -1; -// } -// - return -1; -} - -int PMySQL::GetWorldItemOption(unsigned short ID, int Location, int option) -{ - char query[2048]; - MYSQL_RES *result; - MYSQL_ROW row; - if(option != 1 && option != 2 && option != 3) - { - return -1; - } - - if (Location > 100000) - { - //int nAppLoc = GetAptLocation(Location); - int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID - if (nAppLoc) - snprintf(query, 2048, "SELECT ai_option%d FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", option, ID, nAppLoc); - else - return 0; - } - else - snprintf(query, 2048, "SELECT wi_option%d FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", option, ID, Location); - - result = GameResQuery(query); - if(!result) - { - Console->Print("%s Cannot get WorldItemOption; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - ShowGameSQLError(); - return 0; - } - else - { - if(mysql_num_rows(result) > 1) - { - FreeGameSQLResult(result); - return -2; - } - else - { - row = mysql_fetch_row(result); - if(row == NULL) - { - FreeGameSQLResult(result); - return -1; - } - int ret_val = std::atoi(row[0]); - FreeGameSQLResult(result); - return ret_val; - } - } -// -// else -// { -// FreeGameSQLResult(result); -// return -1; -// } - - return -1; -} - -int PMySQL::GetWorldDoorType(unsigned int ID, int Location) // To be removed -{ - char query[2048]; - MYSQL_RES *result; - MYSQL_ROW row; - -Console->Print(RED, BLACK, "PMySQL::GetWorldDoorType: DATABASE MUST NOT BE USED ANYMORE FOR DOORS INFO !!!"); - if (Location > 100000) - { - //int nAppLoc = GetAptLocation(Location); - int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID - if (nAppLoc) - snprintf(query, 2048, "SELECT ad_type FROM apt_doors, apartments WHERE apt_doors.ad_apt_map = apartments.apt_type AND apt_doors.ad_apt_id = %i AND apartments.apt_id = %i", ID, nAppLoc); - else - return 0; - } - else - { - snprintf(query, 2048, "SELECT wd_type FROM world_doors WHERE wd_world_id = %d AND wd_world_map = %d", ID, Location); - } - result = GameResQuery(query); - - if(!result) - { - Console->Print("%s Cannot get WorldDoorType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - ShowGameSQLError(); - return 0; - } else { - if(mysql_num_rows(result) > 1) - { - FreeGameSQLResult(result); - return -2; - } - else - { - row = mysql_fetch_row(result); - if(row == NULL) - { - FreeGameSQLResult(result); - return -1; - } - int ret_val = std::atoi(row[0]); - FreeGameSQLResult(result); - return ret_val; - } - } -// -// else -// { -// FreeGameSQLResult(result); -// return -1; -// } -// - return -1; -}*/ +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +PMySQL::PMySQL() +{ + InfoDBInuse = 0; + GameDBInuse = 0; + info_port = Config->GetOptionInt("info_sql_port"); + strncpy(info_host, Config->GetOption("info_sql_host").c_str(), 100); + strncpy(info_userName, Config->GetOption("info_sql_username").c_str(), 100); + strncpy(info_password, Config->GetOption("info_sql_password").c_str(), 100); + strncpy(info_database, Config->GetOption("info_sql_database").c_str(), 100); + + game_port = Config->GetOptionInt("game_sql_port"); + strncpy(game_host, Config->GetOption("game_sql_host").c_str(), 100); + strncpy(game_userName, Config->GetOption("game_sql_username").c_str(), 100); + strncpy(game_password, Config->GetOption("game_sql_password").c_str(), 100); + strncpy(game_database, Config->GetOption("game_sql_database").c_str(), 100); + + mKeepaliveDelay = (std::time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive + if (mKeepaliveDelay == 0) + { + Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]")); + } + else if (mKeepaliveDelay < 60) + { + Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay); + mKeepaliveDelay = 60; + } + mLastKeepaliveSent = 0; +} + +PMySQL::~PMySQL() +{ + Console->Print("Closing MySQL connection..."); + mysql_close(info_dbHandle); + mysql_close(game_dbHandle); +} + +void PMySQL::Update() +{ + CheckResCount(); // Check for MYSQL_RES mem leak + + // MySQL keepalive + std::time_t t = std::time(NULL); + if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay)) + { + MYSQL_RES *result; + char query[24]; + snprintf (query, 24, "SELECT NOW()"); + + result = GameResQuery(query); + if(!result) + { + Console->Print("%s Can't send GameDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + ShowGameSQLError(); + return; + } + else + FreeGameSQLResult(result); + + result = InfoResQuery(query); + if(!result) + { + Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + ShowInfoSQLError(); + return; + } + else + FreeInfoSQLResult(result); + + mLastKeepaliveSent = std::time(NULL); + if (gDevDebug) Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]")); + } +} + +void PMySQL::CheckResCount() +{ + static int MaxInfoDBCount = 0; + static int MaxGameDBCount = 0; + + if (InfoDBInuse > MaxInfoDBCount) + { + Console->Print("%s Max In-use InfoDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), InfoDBInuse, InfoDBInuse-MaxInfoDBCount); + MaxInfoDBCount = InfoDBInuse; + } + + if (GameDBInuse > MaxGameDBCount) + { + Console->Print("%s Max In-use GameDB Resources number increasing : %d (+%d)", Console->ColorText(YELLOW, BLACK, "[Notice]"), GameDBInuse, GameDBInuse-MaxGameDBCount); + MaxGameDBCount = GameDBInuse; + } +} + +bool PMySQL::Connect() +{ + Console->LPrint("Establishing link to Infoserver Database..."); + + info_dbHandle = mysql_init(NULL); + + if(!info_dbHandle) + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LClose(); + Console->Print(" Unable to create MySQL-Handle!"); + exit(0); + } + + if(!mysql_real_connect(info_dbHandle, info_host, info_userName, info_password, info_database, info_port, NULL, 0)) + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LClose(); + Console->Print("Unable to connect to Infoserver Database. MySQL returned: %s", mysql_error(info_dbHandle)); + } + else + { + Console->LPrint(GREEN, BLACK, "Success"); + Console->LClose(); + } +// <><><><><><><><> Gameserver DB <><><><><><><><> + Console->LPrint("Establishing link to Gameserver Database..."); + + game_dbHandle = mysql_init(NULL); + + if(!game_dbHandle) + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LClose(); + Console->Print(" Unable to create MySQL-Handle!"); + exit(0); + } + + if(!mysql_real_connect(game_dbHandle, game_host, game_userName, game_password, game_database, game_port, NULL, 0)) + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LClose(); + Console->Print("Unable to connect to Gameserver Database. MySQL returned: %s", mysql_error(game_dbHandle)); + return false; + } + else + { + Console->LPrint(GREEN, BLACK, "Success"); + Console->LClose(); + return true; + } + +} +// ---------------------------------------------------- +MYSQL_RES *PMySQL::InfoResQuery(const char *query) +{ + int sql_result = 0; + MYSQL_RES *result; + + sql_result = mysql_real_query(info_dbHandle, query, strlen(query)); + if(sql_result) + { + return NULL; + } + result = mysql_store_result(info_dbHandle); + if(!result) + { + return NULL; + } + //if(InfoDBInuse == true) + /*if(InfoDBInuse > 0) + { + Console->Print("%s another (%d) info_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), InfoDBInuse); + }*/ + + //InfoDBInuse = true; + InfoDBInuse++; + return result; +} + +int PMySQL::InfoQuery(const char *query) +{ + int sql_result = 0; + sql_result = mysql_real_query(info_dbHandle, query, strlen(query)); + + return sql_result; +} + +void PMySQL::ShowInfoSQLError() +{ + Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(info_dbHandle)); +} +void PMySQL::FreeInfoSQLResult(MYSQL_RES *res) +{ + if(InfoDBInuse > 0) + { + mysql_free_result(res); + InfoDBInuse--; + } + else + Console->Print("PMySQL::FreeInfoSQLResult: Nothing to free..."); +} +// ---------------------------------------------------- +MYSQL_RES *PMySQL::GameResQuery(const char *query) +{ + int sql_result = 0; + MYSQL_RES *result; + + sql_result = mysql_real_query(game_dbHandle, query, strlen(query)); + if(sql_result) + { + return NULL; + } + result = mysql_store_result(game_dbHandle); + if(!result) + { + return NULL; + } + /*if(GameDBInuse > 0) + { + Console->Print("%s another (%d) game_dbHandle result is still in use", Console->ColorText(YELLOW, BLACK, "[Warning]"), GameDBInuse); + }*/ + + //GameDBInuse = true; + GameDBInuse++; + return result; +} + +int PMySQL::GameQuery(const char *query) +{ + int sql_result = 0; + sql_result = mysql_real_query(game_dbHandle, query, strlen(query)); + + return sql_result; +} + +void PMySQL::ShowGameSQLError() +{ + Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(game_dbHandle)); +} + +void PMySQL::FreeGameSQLResult(MYSQL_RES *res) +{ + if(GameDBInuse > 0) + { + mysql_free_result(res); + GameDBInuse--; + } + else + Console->Print("PMySQL::FreeGameSQLResult: Nothing to free..."); +} + +uint32_t PMySQL::EscapeString(const char* nText, char* dText, uint32_t dMaxLength) +{ + uint32_t nLength = strlen(nText); + uint32_t tMax = (dMaxLength - 1)/2; + if(nLength > tMax) + { + nLength = tMax; + } + + return mysql_real_escape_string(game_dbHandle, dText, nText, nLength); +} + +// ---------------------------------------------------- +/* +int PMySQL::GetWorldItemType(unsigned short ID, int Location) +{ + char query[2048]; + MYSQL_RES *result; + MYSQL_ROW row; + + if (Location > 100000) + { + //int nAppLoc = GetAptLocation(Location); + int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID + if (nAppLoc) + snprintf(query, 2048, "SELECT ai_type FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", ID, nAppLoc); + else + return 0; + } + else + snprintf(query, 2048, "SELECT wi_type FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", ID, Location); + + result = GameResQuery(query); + if(!result) + { + Console->Print("%s Cannot get WorldItemType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + ShowGameSQLError(); + return 0; + } + else + { + if(mysql_num_rows(result) > 1) + { + FreeGameSQLResult(result); + return -2; + } + else + { + row = mysql_fetch_row(result); + if(row == NULL) + { + FreeGameSQLResult(result); + return -1; + } + int ret_val = std::atoi(row[0]); + FreeGameSQLResult(result); + return ret_val; + } + } +// else +// { +// FreeGameSQLResult(result); +// return -1; +// } +// + return -1; +} + +int PMySQL::GetWorldItemOption(unsigned short ID, int Location, int option) +{ + char query[2048]; + MYSQL_RES *result; + MYSQL_ROW row; + if(option != 1 && option != 2 && option != 3) + { + return -1; + } + + if (Location > 100000) + { + //int nAppLoc = GetAptLocation(Location); + int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID + if (nAppLoc) + snprintf(query, 2048, "SELECT ai_option%d FROM apt_items WHERE ai_apt_id = %d AND ai_apt_map = %d", option, ID, nAppLoc); + else + return 0; + } + else + snprintf(query, 2048, "SELECT wi_option%d FROM world_items WHERE wi_worlditem_id = %d AND wi_worlditem_map = %d", option, ID, Location); + + result = GameResQuery(query); + if(!result) + { + Console->Print("%s Cannot get WorldItemOption; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + ShowGameSQLError(); + return 0; + } + else + { + if(mysql_num_rows(result) > 1) + { + FreeGameSQLResult(result); + return -2; + } + else + { + row = mysql_fetch_row(result); + if(row == NULL) + { + FreeGameSQLResult(result); + return -1; + } + int ret_val = std::atoi(row[0]); + FreeGameSQLResult(result); + return ret_val; + } + } +// +// else +// { +// FreeGameSQLResult(result); +// return -1; +// } + + return -1; +} + +int PMySQL::GetWorldDoorType(unsigned int ID, int Location) // To be removed +{ + char query[2048]; + MYSQL_RES *result; + MYSQL_ROW row; + +Console->Print(RED, BLACK, "PMySQL::GetWorldDoorType: DATABASE MUST NOT BE USED ANYMORE FOR DOORS INFO !!!"); + if (Location > 100000) + { + //int nAppLoc = GetAptLocation(Location); + int nAppLoc = Location - 100000; // temp as DB doesn't link with App world ID, but with app ID + if (nAppLoc) + snprintf(query, 2048, "SELECT ad_type FROM apt_doors, apartments WHERE apt_doors.ad_apt_map = apartments.apt_type AND apt_doors.ad_apt_id = %i AND apartments.apt_id = %i", ID, nAppLoc); + else + return 0; + } + else + { + snprintf(query, 2048, "SELECT wd_type FROM world_doors WHERE wd_world_id = %d AND wd_world_map = %d", ID, Location); + } + result = GameResQuery(query); + + if(!result) + { + Console->Print("%s Cannot get WorldDoorType; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + ShowGameSQLError(); + return 0; + } else { + if(mysql_num_rows(result) > 1) + { + FreeGameSQLResult(result); + return -2; + } + else + { + row = mysql_fetch_row(result); + if(row == NULL) + { + FreeGameSQLResult(result); + return -1; + } + int ret_val = std::atoi(row[0]); + FreeGameSQLResult(result); + return ret_val; + } + } +// +// else +// { +// FreeGameSQLResult(result); +// return -1; +// } +// + return -1; +}*/ diff --git a/TinNS/Source/GameServer/Sql.hxx b/TinNS/Source/GameServer/Sql.hxx index ed028b3..603d9fc 100644 --- a/TinNS/Source/GameServer/Sql.hxx +++ b/TinNS/Source/GameServer/Sql.hxx @@ -1,64 +1,64 @@ -#pragma once - -#include -#include -#ifdef MYSQL_INC_DIR -#include -#else -#include -#endif - -// TODO: take all non-pure SQL DB access stuff out of this class - -class PMySQL { -private: - int info_port; - char info_host[100]; - char info_userName[100]; - char info_password[100]; - char info_database[100]; - MYSQL *info_dbHandle; - std::time_t mKeepaliveDelay; - std::time_t mLastKeepaliveSent; - - int game_port; - char game_host[100]; - char game_userName[100]; - char game_password[100]; - char game_database[100]; - MYSQL *game_dbHandle; - - int GameDBInuse; - int InfoDBInuse; - -public: - PMySQL(); - ~PMySQL(); - - void Update(); - void CheckResCount(); - - inline MYSQL *GetInfoHandle() { return info_dbHandle; }; - inline MYSQL *GetGameHandle() { return game_dbHandle; }; - - bool Connect(); - - int InfoQuery(const char *query); - MYSQL_RES *InfoResQuery(const char *query); - int GameQuery(const char *query); - MYSQL_RES *GameResQuery(const char *query); - - /*int GetWorldItemType(unsigned short ID, int Location); - int GetWorldItemOption(unsigned short ID, int Location, int option); - int GetWorldDoorType(unsigned int ID, int Location);*/ - - void ShowInfoSQLError(); - void ShowGameSQLError(); - void FreeGameSQLResult(MYSQL_RES *res); - void FreeInfoSQLResult(MYSQL_RES *res); - - inline uint32_t GetLastGameInsertId() { return mysql_insert_id(game_dbHandle); }; - inline uint32_t GetLastInfoInsertId() { return mysql_insert_id(info_dbHandle); }; - - uint32_t EscapeString(const char* nText, char* dText, uint32_t dMaxLength); -}; +#pragma once + +#include +#include +#ifdef MYSQL_INC_DIR +#include +#else +#include +#endif + +// TODO: take all non-pure SQL DB access stuff out of this class + +class PMySQL { +private: + int info_port; + char info_host[100]; + char info_userName[100]; + char info_password[100]; + char info_database[100]; + MYSQL *info_dbHandle; + std::time_t mKeepaliveDelay; + std::time_t mLastKeepaliveSent; + + int game_port; + char game_host[100]; + char game_userName[100]; + char game_password[100]; + char game_database[100]; + MYSQL *game_dbHandle; + + int GameDBInuse; + int InfoDBInuse; + +public: + PMySQL(); + ~PMySQL(); + + void Update(); + void CheckResCount(); + + inline MYSQL *GetInfoHandle() { return info_dbHandle; }; + inline MYSQL *GetGameHandle() { return game_dbHandle; }; + + bool Connect(); + + int InfoQuery(const char *query); + MYSQL_RES *InfoResQuery(const char *query); + int GameQuery(const char *query); + MYSQL_RES *GameResQuery(const char *query); + + /*int GetWorldItemType(unsigned short ID, int Location); + int GetWorldItemOption(unsigned short ID, int Location, int option); + int GetWorldDoorType(unsigned int ID, int Location);*/ + + void ShowInfoSQLError(); + void ShowGameSQLError(); + void FreeGameSQLResult(MYSQL_RES *res); + void FreeInfoSQLResult(MYSQL_RES *res); + + inline uint32_t GetLastGameInsertId() { return mysql_insert_id(game_dbHandle); }; + inline uint32_t GetLastInfoInsertId() { return mysql_insert_id(info_dbHandle); }; + + uint32_t EscapeString(const char* nText, char* dText, uint32_t dMaxLength); +}; diff --git a/TinNS/Source/GameServer/Subway.cxx b/TinNS/Source/GameServer/Subway.cxx index f2ced03..a8669ff 100644 --- a/TinNS/Source/GameServer/Subway.cxx +++ b/TinNS/Source/GameServer/Subway.cxx @@ -1,229 +1,229 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -/* -(Real time) -Full cycle = 328860 ms -Network delay = TBD - -Offset =MOD(M86-122778+(M85*29896);328860) -*/ - -// Determines relative position of cabs, but how ??? -const uint16_t PSubway::mSubwayInitData [] = {0x4396, 0x4387, 0x4370, 0x4352, 0x4334, 0x4316, 0x42f0, 0x42b4, 0x4270, 0x41f0, 0x0000}; -const uint32_t PSubway::mCabLoopTime = 328860; -const uint32_t PSubway::mCab0TimeOffset = 122778; -const int32_t PSubway::mTimingAdjust = 0; -const uint32_t PSubway::mCabIntervalTime = 29896; -const uint32_t PSubway::mOpenDoorOffset [] = { 0, 42500, 83000, 146800, 170700, 226200, 262800, 303200 }; -const uint32_t PSubway::mOpenDoorDuration [] = { 8500, 6900, 12000, 7500, 8800, 9000, 8500, 9300 }; -const char* PSubway::mSubwayStationName[] = { "Pla => Oz", "Vr => Oz", "Pp => Oz", "Oz end", "Oz => Pla", "Pp => Pla", "Vr => Pla", "Pla end" }; -PCharCoordinates PSubway::mCabExitPositions [2][mStationsNumber]; - - -PSubway::PSubway() -{ - for(uint8_t i=0; iPrint(RED, BLACK, "[Error] PSubway::GetTimeOffset : invalid cab VhcId %d", nVhcId); - return 0; - } - - return ((nTime + mCabLoopTime - mCab0TimeOffset + mTimingAdjust + (tIndex * mCabIntervalTime)) % mCabLoopTime); -} - -uint8_t PSubway::GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset) -{ - int8_t i; - - uint32_t tTimeOffset = GetTimeOffset(nVhcId, nTime); - if(TimeOffset) - { - *TimeOffset = tTimeOffset; - } - - for(i = mStationsNumber-1; (i >= 0) && (tTimeOffset < mOpenDoorOffset[i]); --i) ; - - return i; -} - -bool PSubway::IsDoorOpen(uint32_t nVhcId, uint32_t nTime) -{ - uint32_t TimeOffset; - uint8_t tStation; - - if(!GetInfoIndex(nVhcId)) - { - Console->Print(RED, BLACK, "[Error] PSubway::IsDoorOpen : invalid cab VhcId %d", nVhcId); - return false; - } - else - { - tStation = GetStation(nVhcId, nTime, &TimeOffset); - return ((TimeOffset-mOpenDoorOffset[tStation]) <= mOpenDoorDuration[tStation]); - } -} - -std::string* PSubway::GetStationName(uint8_t nStationId) -{ - if(nStationId < mStationsNumber) - { - return new std::string(mSubwayStationName[nStationId]); - } - else - { - Console->Print(RED, BLACK, "[Error] PSubway::GetStationName : invalid subway station %d", nStationId); - return new std::string("Error"); - } -} - -bool PSubway::GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef) -{ - if(nStationId < mStationsNumber) - { - nPosition->SetInterpolate(mCabExitPositions[0][nStationId], mCabExitPositions[1][nStationId], nCoef); - return true; - } - else - { - Console->Print(RED, BLACK, "[Error] PSubway::SetStationExitPosition : invalid subway station %d", nStationId); - return false; - } -} - -bool PSubway::GetInfoIndex(uint32_t nVhcId, uint8_t *Index) -{ - int32_t tIndex = nVhcId - mCabsBaseId; - if ((tIndex >= 0) && (tIndex < mCabsNumber)) - { - if(Index) - { - *Index = (uint8_t)tIndex; - } - return true; - } - else - return false; -} - -bool PSubway::UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened) -{ - uint8_t tIndex; - if(GetInfoIndex(nVhcId, &tIndex)) - { - mSubways[tIndex].mPosition = nPosition; -//if(mSubways[tIndex].mDoorOpened != nDoorOpened) -// Console->Print("[DEBUG] Subway cab %08x : door now %s ", nVhcId, nDoorOpened ? "opened" : "closed" ); - - mSubways[tIndex].mDoorOpened = nDoorOpened; - - return true; - } - else - return false; -} - -uint16_t PSubway::GetPosition(uint32_t nVhcId) -{ - uint8_t tIndex; - if(GetInfoIndex(nVhcId, &tIndex)) - { - return mSubways[tIndex].mPosition; - } - else - return 0; -} - -uint8_t PSubway::GetFreeSeat(uint32_t nVhcId) -{ - uint8_t tIndex; - uint8_t tSeatFound = 0; - if(GetInfoIndex(nVhcId, &tIndex)) - { - for(uint8_t j=0; j<4; j++) - { - if(! mSubways[tIndex].mSeatUsersId[j]) - { - tSeatFound = j+1; - break; - } - } - return tSeatFound; - } - else - return 0; -} - -bool PSubway::SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId) -{ - uint8_t tIndex; - - if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4)) - { - if(! mSubways[tIndex].mSeatUsersId[nSeat-1]) - { - mSubways[tIndex].mSeatUsersId[nSeat-1] = nCharId; -//Console->Print("[DEBUG] Char %d using seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId); - return true; - } - } - - return false; -} - -bool PSubway::UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId) -{ - uint8_t tIndex; - - if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4)) - { - if(mSubways[tIndex].mSeatUsersId[nSeat-1] == nCharId) - { - mSubways[tIndex].mSeatUsersId[nSeat-1] = 0; -//Console->Print("[DEBUG] Char %d leaving seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId); - return true; - } - } - - return false; -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +/* +(Real time) +Full cycle = 328860 ms +Network delay = TBD + +Offset =MOD(M86-122778+(M85*29896);328860) +*/ + +// Determines relative position of cabs, but how ??? +const uint16_t PSubway::mSubwayInitData [] = {0x4396, 0x4387, 0x4370, 0x4352, 0x4334, 0x4316, 0x42f0, 0x42b4, 0x4270, 0x41f0, 0x0000}; +const uint32_t PSubway::mCabLoopTime = 328860; +const uint32_t PSubway::mCab0TimeOffset = 122778; +const int32_t PSubway::mTimingAdjust = 0; +const uint32_t PSubway::mCabIntervalTime = 29896; +const uint32_t PSubway::mOpenDoorOffset [] = { 0, 42500, 83000, 146800, 170700, 226200, 262800, 303200 }; +const uint32_t PSubway::mOpenDoorDuration [] = { 8500, 6900, 12000, 7500, 8800, 9000, 8500, 9300 }; +const char* PSubway::mSubwayStationName[] = { "Pla => Oz", "Vr => Oz", "Pp => Oz", "Oz end", "Oz => Pla", "Pp => Pla", "Vr => Pla", "Pla end" }; +PCharCoordinates PSubway::mCabExitPositions [2][mStationsNumber]; + + +PSubway::PSubway() +{ + for(uint8_t i=0; iPrint(RED, BLACK, "[Error] PSubway::GetTimeOffset : invalid cab VhcId %d", nVhcId); + return 0; + } + + return ((nTime + mCabLoopTime - mCab0TimeOffset + mTimingAdjust + (tIndex * mCabIntervalTime)) % mCabLoopTime); +} + +uint8_t PSubway::GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset) +{ + int8_t i; + + uint32_t tTimeOffset = GetTimeOffset(nVhcId, nTime); + if(TimeOffset) + { + *TimeOffset = tTimeOffset; + } + + for(i = mStationsNumber-1; (i >= 0) && (tTimeOffset < mOpenDoorOffset[i]); --i) ; + + return i; +} + +bool PSubway::IsDoorOpen(uint32_t nVhcId, uint32_t nTime) +{ + uint32_t TimeOffset; + uint8_t tStation; + + if(!GetInfoIndex(nVhcId)) + { + Console->Print(RED, BLACK, "[Error] PSubway::IsDoorOpen : invalid cab VhcId %d", nVhcId); + return false; + } + else + { + tStation = GetStation(nVhcId, nTime, &TimeOffset); + return ((TimeOffset-mOpenDoorOffset[tStation]) <= mOpenDoorDuration[tStation]); + } +} + +std::string* PSubway::GetStationName(uint8_t nStationId) +{ + if(nStationId < mStationsNumber) + { + return new std::string(mSubwayStationName[nStationId]); + } + else + { + Console->Print(RED, BLACK, "[Error] PSubway::GetStationName : invalid subway station %d", nStationId); + return new std::string("Error"); + } +} + +bool PSubway::GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef) +{ + if(nStationId < mStationsNumber) + { + nPosition->SetInterpolate(mCabExitPositions[0][nStationId], mCabExitPositions[1][nStationId], nCoef); + return true; + } + else + { + Console->Print(RED, BLACK, "[Error] PSubway::SetStationExitPosition : invalid subway station %d", nStationId); + return false; + } +} + +bool PSubway::GetInfoIndex(uint32_t nVhcId, uint8_t *Index) +{ + int32_t tIndex = nVhcId - mCabsBaseId; + if ((tIndex >= 0) && (tIndex < mCabsNumber)) + { + if(Index) + { + *Index = (uint8_t)tIndex; + } + return true; + } + else + return false; +} + +bool PSubway::UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened) +{ + uint8_t tIndex; + if(GetInfoIndex(nVhcId, &tIndex)) + { + mSubways[tIndex].mPosition = nPosition; +//if(mSubways[tIndex].mDoorOpened != nDoorOpened) +// Console->Print("[DEBUG] Subway cab %08x : door now %s ", nVhcId, nDoorOpened ? "opened" : "closed" ); + + mSubways[tIndex].mDoorOpened = nDoorOpened; + + return true; + } + else + return false; +} + +uint16_t PSubway::GetPosition(uint32_t nVhcId) +{ + uint8_t tIndex; + if(GetInfoIndex(nVhcId, &tIndex)) + { + return mSubways[tIndex].mPosition; + } + else + return 0; +} + +uint8_t PSubway::GetFreeSeat(uint32_t nVhcId) +{ + uint8_t tIndex; + uint8_t tSeatFound = 0; + if(GetInfoIndex(nVhcId, &tIndex)) + { + for(uint8_t j=0; j<4; j++) + { + if(! mSubways[tIndex].mSeatUsersId[j]) + { + tSeatFound = j+1; + break; + } + } + return tSeatFound; + } + else + return 0; +} + +bool PSubway::SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId) +{ + uint8_t tIndex; + + if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4)) + { + if(! mSubways[tIndex].mSeatUsersId[nSeat-1]) + { + mSubways[tIndex].mSeatUsersId[nSeat-1] = nCharId; +//Console->Print("[DEBUG] Char %d using seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId); + return true; + } + } + + return false; +} + +bool PSubway::UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId) +{ + uint8_t tIndex; + + if(GetInfoIndex(nVhcId, &tIndex) && (nSeat >= 1) && (nSeat <= 4)) + { + if(mSubways[tIndex].mSeatUsersId[nSeat-1] == nCharId) + { + mSubways[tIndex].mSeatUsersId[nSeat-1] = 0; +//Console->Print("[DEBUG] Char %d leaving seat %d of subway cab %08x, ", nCharId, nSeat, nVhcId); + return true; + } + } + + return false; +} diff --git a/TinNS/Source/GameServer/Subway.hxx b/TinNS/Source/GameServer/Subway.hxx index 40197e3..7f5a48c 100644 --- a/TinNS/Source/GameServer/Subway.hxx +++ b/TinNS/Source/GameServer/Subway.hxx @@ -1,56 +1,56 @@ -#pragma once - -#include -#include - -class PSubway { - friend class PMsgBuilder; - - struct PSubwayInfo - { - uint16_t mVhcId; - uint16_t mPosition; - uint8_t mDoorOpened; - uint32_t mSeatUsersId[4]; - }; - - public: - static const uint16_t mCabsNumber = 11; - static const uint32_t mCabsBaseId = 0x03f2; - static const uint32_t mCabsBaseHealth = 100; //should take that from .def instead... - static const uint8_t mStationsNumber = 8; - - private: - static const uint16_t mSubwayInitData []; - static const uint32_t mCabLoopTime; - static const uint32_t mCab0TimeOffset; - static const int32_t mTimingAdjust; - static const uint32_t mCabIntervalTime; - static const uint32_t mOpenDoorOffset []; - static const uint32_t mOpenDoorDuration []; - static const char* mSubwayStationName []; - static PCharCoordinates mCabExitPositions [2][mStationsNumber]; - - PSubwayInfo mSubways[mCabsNumber]; - -public: - bool GetInfoIndex(uint32_t nVhcId, uint8_t *Index = NULL); - - public: - PSubway(); - //~PSubway(); - - inline bool IsValidSubwayCab(uint32_t nVhcId) {return GetInfoIndex(nVhcId); } - bool UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened); - uint16_t GetPosition(uint32_t nVhcId); - - uint32_t GetTimeOffset(uint32_t nVhcId, uint32_t nTime); - uint8_t GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset = NULL); - bool IsDoorOpen(uint32_t nVhcId, uint32_t nTime); - std::string* GetStationName(uint8_t nStationId); - bool GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef = 0.5); - - uint8_t GetFreeSeat(uint32_t nVhcId); - bool SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId); - bool UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId); -}; +#pragma once + +#include +#include + +class PSubway { + friend class PMsgBuilder; + + struct PSubwayInfo + { + uint16_t mVhcId; + uint16_t mPosition; + uint8_t mDoorOpened; + uint32_t mSeatUsersId[4]; + }; + + public: + static const uint16_t mCabsNumber = 11; + static const uint32_t mCabsBaseId = 0x03f2; + static const uint32_t mCabsBaseHealth = 100; //should take that from .def instead... + static const uint8_t mStationsNumber = 8; + + private: + static const uint16_t mSubwayInitData []; + static const uint32_t mCabLoopTime; + static const uint32_t mCab0TimeOffset; + static const int32_t mTimingAdjust; + static const uint32_t mCabIntervalTime; + static const uint32_t mOpenDoorOffset []; + static const uint32_t mOpenDoorDuration []; + static const char* mSubwayStationName []; + static PCharCoordinates mCabExitPositions [2][mStationsNumber]; + + PSubwayInfo mSubways[mCabsNumber]; + +public: + bool GetInfoIndex(uint32_t nVhcId, uint8_t *Index = NULL); + + public: + PSubway(); + //~PSubway(); + + inline bool IsValidSubwayCab(uint32_t nVhcId) {return GetInfoIndex(nVhcId); } + bool UpdateInfo(uint32_t nVhcId, uint16_t nPosition, uint8_t nDoorOpened); + uint16_t GetPosition(uint32_t nVhcId); + + uint32_t GetTimeOffset(uint32_t nVhcId, uint32_t nTime); + uint8_t GetStation(uint32_t nVhcId, uint32_t nTime, uint32_t* TimeOffset = NULL); + bool IsDoorOpen(uint32_t nVhcId, uint32_t nTime); + std::string* GetStationName(uint8_t nStationId); + bool GetStationExitPosition(PCharCoordinates* nPosition, uint8_t nStationId, float nCoef = 0.5); + + uint8_t GetFreeSeat(uint32_t nVhcId); + bool SetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId); + bool UnsetSeatUser(uint32_t nVhcId, uint8_t nSeat, uint32_t nCharId); +}; diff --git a/TinNS/Source/GameServer/Terminal.hxx b/TinNS/Source/GameServer/Terminal.hxx index 6e92092..888f0a0 100644 --- a/TinNS/Source/GameServer/Terminal.hxx +++ b/TinNS/Source/GameServer/Terminal.hxx @@ -1,29 +1,29 @@ -#pragma once - -#include - -class PTerminal { -private: - void SendTryAccessAnswer(PClient* nClient, char *nArea, bool nAllowed); - char mSQLQuery[500]; - - int mResultFields; - void EraseVars(); - - char mConPrefix[50]; - - inline bool ChkOpt(uint8_t nNumOptions, uint8_t nReqOpt) { if(nNumOptions < nReqOpt) return false; else return true; }; - bool DoStockXCheck(PClient* nClient, int nAmountEntered, int nNewAmount); - -public: - PTerminal(); - //~PTerminal(); - // Check accesslevel of Player for various Terminal actions - bool CheckAccess(PClient* nClient, char *nArea, uint16_t nCmdNr, char *nOption1, char *nOption2, char *nOption3); - uint8_t GetNewEmailCount(PClient* nClient, bool nNoticeClient = true); - // Handle ReceiveDB queries - bool HandleQueryDB(PClient* nClient, std::string *nDBCommandName, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions); - bool HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown); - bool HandleTryAccess(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown, bool nCheckOnly = false); - bool HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown); -}; +#pragma once + +#include + +class PTerminal { +private: + void SendTryAccessAnswer(PClient* nClient, char *nArea, bool nAllowed); + char mSQLQuery[500]; + + int mResultFields; + void EraseVars(); + + char mConPrefix[50]; + + inline bool ChkOpt(uint8_t nNumOptions, uint8_t nReqOpt) { if(nNumOptions < nReqOpt) return false; else return true; }; + bool DoStockXCheck(PClient* nClient, int nAmountEntered, int nNewAmount); + +public: + PTerminal(); + //~PTerminal(); + // Check accesslevel of Player for various Terminal actions + bool CheckAccess(PClient* nClient, char *nArea, uint16_t nCmdNr, char *nOption1, char *nOption2, char *nOption3); + uint8_t GetNewEmailCount(PClient* nClient, bool nNoticeClient = true); + // Handle ReceiveDB queries + bool HandleQueryDB(PClient* nClient, std::string *nDBCommandName, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions); + bool HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown); + bool HandleTryAccess(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown, bool nCheckOnly = false); + bool HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown); +}; diff --git a/TinNS/Source/GameServer/TerminalReceiveDatabase.cxx b/TinNS/Source/GameServer/TerminalReceiveDatabase.cxx index 29a7c61..e8d8c7b 100644 --- a/TinNS/Source/GameServer/TerminalReceiveDatabase.cxx +++ b/TinNS/Source/GameServer/TerminalReceiveDatabase.cxx @@ -1,1012 +1,1012 @@ -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -bool PTerminal::HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown) -{ - EraseVars(); - int nAccessLevel = nClient->GetAccountLevel(); - //Console->Print("DBID: %d", nDBID); - - switch (nDBID) - { - case 8: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 6; - if(!strncmp(nOptions[0].c_str(), "date", 4)) - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - else - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 9: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 6; - if(!strncmp(nOptions[0].c_str(), "date", 4)) - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - else - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 10: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 6; - if(!strncmp(nOptions[0].c_str(), "date", 4)) - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - else - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 11: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 6; - //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_content FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_id = %d", atoi(nOptions[0].c_str())); - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_content FROM `neochronicle` WHERE nc_id = %d", atoi(nOptions[0].c_str())); - //snprintf (mSQLQuery, 500, "SELECT na_id, \'\', na_datetime, na_author, na_name, na_content FROM `neocron articles` WHERE na_approval = 1 AND na_id = %d", atoi(nOptions[0].c_str())); - - break; - case 14: - // 0: ID 1: Short 2: Clanname 3: FactionID 4: Faction Symp - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 6; // TODO: replace 0 with average faction sympathy - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM `clans` WHERE cl_name LIKE \"%%%s%%\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 16: - if(!ChkOpt(nNumOptions, 3)) break; - if (!strcmp (nOptions[0].c_str(), "Neocronicle")) - { - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name FROM `neocron articles` WHERE na_approval = 1 LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str()); - } - else - { - mResultFields = 7; - snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name, na_approval, \"0\" FROM `neocron articles` LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str()); - } - - break; - case 18: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 20: - case 21: - // Select either c_"name" or c_"minsympathy". Names taken from option, saves if/else - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT `cl_%s` FROM `clans` WHERE `cl_id` = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str())); - - break; - case 25: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 6; // TODO: replace 0 with average faction sympathy - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM clans WHERE cl_name > \"%s\" AND cl_name <=\"%s\" LIMIT %d, %d", nOptions[0].c_str(), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 26: - // 0: short 1: name 2: money 3: faction 4: fac symp 5: symp_to_join 6: cappid - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_money, cl_faction, \"0\", cl_minsympathy, cl_appid FROM `clans` WHERE `cl_id` = %d", atoi(nOptions[0].c_str())); - - break; - case 27: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_description, count(DISTINCT o_outnum), count(DISTINCT c_id) FROM outposts INNER JOIN clans ON (o_clan = cl_id) INNER JOIN characters ON (c_clan = clans.cl_id) WHERE (cl_id = %d) GROUP BY cl_id", atoi(nOptions[0].c_str())); - - break; - case 28: - // Faction missions? Never seen them even in NC2... - Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 29: - Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Ordercol was missing. Its: [%s]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, nOptions[0].c_str()); - break; - case 34: - // Name, Add. Info, Profession, Description, Overal Ranking, Soullight, Money, Runner Kills, Creature Kills - // Note: Add. Info is autogenerated clientside! - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 8; - snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\", \"1\", \"127\", c_cash, \"0\", \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 38: - // Faction missions? Never seen them even in NC2... - Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 39: - // 0:id 1:name 2:clan 3:fac.symp - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, \"75\" FROM characters WHERE c_name LIKE \"%s\"", nOptions[0].c_str()); - - break; - case 41: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT o_outnum, o_outnum, \"0\", \"0\", \"0\" FROM outposts WHERE o_clan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 46: - // charid, charname, charclanlevel, clanlevelname, charfactionsymp, char online - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, \"0\", c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d) AND (cll_level >= %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 47: - if(!ChkOpt(nNumOptions, 5)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); - - break; - case 48: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 49: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 50: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 2; //Fieldnum - snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d", atoi(nOptions[0].c_str())); - - break; - case 51: - if(!ChkOpt(nNumOptions, 9)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[7].c_str()), atoi(nOptions[8].c_str())); - - break; - case 52: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 54: - // id, name, rank, rankname, f.symp - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 0 FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str())); - - break; - case 60: // Query for OutPost state. Result is - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan FROM outposts LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 61: // It should display the clanname, but it doesnt. seems to be clientside bug - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan, o_clan, o_security FROM outposts WHERE o_outnum = %d", atoi(nOptions[0].c_str())); - - break; - case 75: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 76: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d AND cll_desc = \"%s\")", atoi(nOptions[0].c_str()),nOptions[1].c_str()); - - break; - case 85: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 6; // No idea why this Fac.Symp is that high... 1000000 is 100 ingame. But only for this query - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 1000000, c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_online = %d OR c_online = 1) AND c_clan = %d LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 86: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - if(!strncmp(nOptions[1].c_str(), "date", 4)) - snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - else - snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 87: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_name, mt_date, mt_amount, mt_comment FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_id = %d", atoi(nOptions[0].c_str())); - - break; - case 92: - if(!ChkOpt(nNumOptions, 1)) break; - // Location of player - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT c_location FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 93: - if(!ChkOpt(nNumOptions, 1)) break; - // Name, Add. Info, Profession, Description - // Note: Add. Info is autogenerated clientside! - mResultFields = 3; - snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 96: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT f_showname FROM forums WHERE f_name = \"%s\"", nOptions[0].c_str()); - - break; - case 98: - // ID, Name, Online, 0, Soullight - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_online, \"0\", c_soullight FROM characters WHERE c_online = %d AND c_soullight <= -%d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - break; - case 99: - // Terrorist info - // id, name, faction, clan, clanlevel, location - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_faction, c_clan, cll_level, c_location FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d AND c_soullight <= -%d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 108: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); - - break; - case 109: - if(!ChkOpt(nNumOptions, 1)) break; - // The only case where KK used an DBId twice for completely different things... - if(nNumOptions < 3) - { - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, cll_level, cll_desc FROM characters INNER JOIN clanlevels ON (cll_charid = c_id AND cll_clanid = c_clan) WHERE c_id = %d", atoi(nOptions[0].c_str())); - } - else if(nNumOptions == 3) - { - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT c_id, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - } - - break; - case 116: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT wr_id FROM worlds WHERE wr_group = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 125: - // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =) - //if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT 255"); - - break; - case 126: - // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =) - // This is with Datecheck, somehow.. - //if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT 255"); - - break; - case 127: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT c_name, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str())); - - break; - case 128: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT su_id FROM support WHERE su_supporterid = %d AND su_finished = 0", atoi(nOptions[0].c_str())); - - case 131: - mResultFields = 6; - //snprintf(mSQLQuery, 500, "SELECT br_id, br_type, c_online, c_name, br_location, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_status = %d LIMIT %d, %d", - // atoi(nOptions[0].c_str())+atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - snprintf(mSQLQuery, 500, "SELECT su_id, su_type, 0, c_name, su_worldid, su_datetime FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_inwork = %d AND su_finished = %d LIMIT %d, %d", - atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 132: - // reqid, runnerid, runnername, 0, date/time, type, 0, in work, finished, desc - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 10; - //snprintf(mSQLQuery, 500, "SELECT br_id, br_fromid, c_name, \"0\", br_datetime, br_type, \"0\", br_status, br_status, br_desc FROM `bug report` INNER JOIN characters ON (br_fromid = c_id) WHERE br_id = %d", atoi(nOptions[0].c_str())); - snprintf(mSQLQuery, 500, "SELECT su_id, su_player, c_name, 0, su_datetime, su_type, su_supporterid, su_inwork, su_finished, su_desc FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_id = %d", atoi(nOptions[0].c_str())); - - break; - case 134: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf(mSQLQuery, 500, "SELECT br_id FROM bug_report WHERE br_fromid = %d", atoi(nOptions[0].c_str())); - - break; - case 136: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - break; - case 137: - if(!ChkOpt(nNumOptions, 1)) break; - // runnerid, runnername, location, online - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str()); - break; - case 138: - if(!ChkOpt(nNumOptions, 1)) break; - // runnerid, runnername, location, online - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT br_type, br_location, br_datetime, br_supid, br_status, br_desc FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); - break; - case 143: - if(!ChkOpt(nNumOptions, 1)) break; - // runnerid, runnername, location, online - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT a.a_id, a.a_username, b.c_id, 0, b.c_location, b.c_online FROM `%s`.accounts AS a, `%s`.characters AS b WHERE b.c_name = \"%s\" AND a.a_id = b.a_id", - Config->GetOption("info_sql_database").c_str(), Config->GetOption("game_sql_database").c_str(), nOptions[0].c_str()); - break; - case 144: - mResultFields = 2; // Replace "1" with Online/Offline! - snprintf (mSQLQuery, 500, "SELECT c_location, c_online FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 145: - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT a_email FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str())); - - break; - case 146: - mResultFields = 4; - // Too bad we named the row different... - char tSortRow[10]; - if(!strncmp(nOptions[1].c_str(), "world", 5)) - strcpy(tSortRow, "location"); - else - strcpy(tSortRow, "name"); - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" ORDER BY `c_%s` LIMIT %d, %d", nOptions[0].c_str(), tSortRow, atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 147: - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_online = %d ORDER BY `c_%s` LIMIT %d, %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 148: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, \"0\", \"0\", c_id FROM clans INNER JOIN characters ON (cl_leader = c_id) WHERE (cl_id = %d)", atoi(nOptions[0].c_str())); - - break; - case 150: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 151: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 153: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 154: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 155: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 156: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 157: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 158: - // Mission stuff. Will be added later! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 175: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT br_id, br_type, br_title, br_datetime FROM bug_report LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 176: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 8; - snprintf (mSQLQuery, 500, "SELECT br_type, br_status, br_title, br_desc, 0, br_datetime, br_location, br_fromid FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); - - break; - case 181: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 3; - snprintf (mSQLQuery, 500, "SELECT c_name, apt_location, apt_password FROM apartments INNER JOIN characters ON (c_id = apt_owner) WHERE apt_id = %d", atoi(nOptions[0].c_str())); - - break; - case 183: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name, (SELECT count(*) FROM characters WHERE c_clan = %d), c_name, apt_id, apt_location FROM clans INNER JOIN apartments ON (cl_appid = apt_id) INNER JOIN characters ON (c_clan = cl_id) AND (apt_owner = c_id) WHERE (cl_id = %d) GROUP BY c_id", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str())); - - break; - case 186: - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str()); - - break; - case 220: - mResultFields = 4; //Fieldnum - snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_status, v_condition FROM vehicles WHERE v_owner = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 221: - //VehicleControl order. "VehicleControl", "Type", "Status", "Condition", "Repairprice?" - mResultFields = 4; //Fieldnum - snprintf (mSQLQuery, 500, "SELECT v_type, v_status, v_condition, \"0\" FROM vehicles WHERE v_id = %s", nOptions[0].c_str()); - - break; - case 225: - // Statistics. Maybe later... - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 226: - // Statistics. Maybe later... - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 230: - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, st_curval-st_oldval FROM stockx"); - - break; - case 231: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, (st_curval - st_oldval) FROM stockx WHERE (st_id = %d)", atoi(nOptions[0].c_str())); - - break; - case 232: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT sxd_id, st_factid, st_curval, sxd_amount, (sxd_amount * st_curval) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE (sxd_playerid = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 233: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 7; - snprintf (mSQLQuery, 500, "SELECT st_factid, sxd_amount, (st_curval - st_oldval), st_curval, sxd_paid, (sxd_amount * st_curval), ((sxd_amount * st_curval) - sxd_paid) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) where sxd_id = %d", atoi(nOptions[0].c_str())); - - break; - case 234: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 3; - snprintf (mSQLQuery, 500, "SELECT sxd_id, sxd_amount, sxd_paid FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE sxd_playerid = %d AND st_factid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 250: - // Influence from CharID? Is stockx gm controlled?? - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 251: - // What is this "influence" ? Check this on live servers! - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 260: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 2; //Fieldnum - snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d+%d+%d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 261: - // Maybe even rewrite BB system.. its wrong written anyways.... - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 262: - // This is wrong! 262 is the receiveDB request for FACTION threadlist. It should be limitet to that faction then - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str()); - - //TODO Check this. Same (?) for ID 52,262,267,401 and 411 - break; - case 266: - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 AND fp_clanid = %d LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 267: - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str()); - - break; - case 270: - Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Tablename/Name is: [%s] ThreadID is: [%d]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, atoi(nOptions[0].c_str()), nOptions[1].c_str()); - break; - case 360: - // Gamemaster name (char), Accountname, Location, Online, CharID - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT a.a_id, c.c_id, a.a_username, c.c_name, c.c_online, c.c_location FROM %s.characters AS c, %s.accounts AS a WHERE a.a_priv >= 50 AND c.c_online = %d AND c.a_id = a.a_id ORDER BY c.c_name LIMIT %d, %d", - Config->GetOption("game_sql_database").c_str(), Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 365: - // ID, short, name faction - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 366: - // ID, short, name faction WHERE clanname = %s - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans WHERE cl_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 367: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 8; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_leader, cl_faction, cl_appid, cl_money, (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str())); - - break; - case 368: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 373: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, apt_type, apt_password FROM apartments WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 375: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 376: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 377: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT DISTINCT a_id FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 378: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT a_username, a_email, \"Since begin\", \"Never\", FROM_UNIXTIME(a_bandate) FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str())); - - break; - case 379: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online, c_clan, cll_level FROM characters INNER JOIN clanlevels ON (cll_charid = c_id) WHERE c_id = %d", atoi(nOptions[0].c_str())); - - break; - case 380: // clean - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cl_name, cll_desc FROM clans INNER JOIN clanlevels ON (cll_clanid = cl_id) WHERE cl_id = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 381: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, c_online FROM characters WHERE a_id = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 384: // clean - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, 0, apt_password FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 400: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 401: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 406: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT count(fp_id) FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) WHERE f_name = \"%s\"", nOptions[0].c_str()); - - break; - case 410: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\" AND fp_factionid = %d) LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 411: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d) AND (fp_factionid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - - case 420: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_new, e_replied, e_datetime FROM emails, characters WHERE e_fromid = c_id AND e_toid = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 421: - if(!ChkOpt(nNumOptions, 1)) break; - //MailControl order. "MailControl", "Mail ID", "Subject", "From", boolean Replied, "Date/Time", "FromID", "Content" - mResultFields = 7; - snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_replied, e_datetime, e_fromid, e_body FROM emails, characters WHERE e_fromid = c_id AND e_id = %s", nOptions[0].c_str()); - - break; - case 425: - if(!ChkOpt(nNumOptions, 1)) break; - //Send mail order. "SendMail", "id" - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \'%s\'", nOptions[0].c_str()); - - break; - case 430: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str()); - - break; - case 431: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_id = %s", nOptions[0].c_str()); - - break; - case 435: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT count(*) FROM contacts WHERE c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str()); - - break; - case 436: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_name LIKE \'%%%s%%\' LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str()); - - break; - case 437: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 1; //Fieldnum - snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %s", nOptions[0].c_str()); - - break; - case 445: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_name FROM neochronicle WHERE nc_lang = %d ORDER BY nc_id DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 446: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT nc_id, nc_lang, nc_datetime, nc_name, nc_content FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str())); - - break; - case 453: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT g_id, 0, g_part, g_title, g_language FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 455: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 3; - // Opt 2 is Language - snprintf (mSQLQuery, 500, "SELECT g_id, g_part, g_title FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 456: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT g_id, g_language, g_title, g_content FROM guides WHERE g_id = %d", atoi(nOptions[0].c_str())); - - break; - case 458: // Statisics - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 459: // Statisics - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 510: // ClanWars: Overview - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) or (cw_enemyclan = cl_id) WHERE (cw_enemyclan = %d OR cw_initclan = %d) AND (cl_id != %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - break; - case 511: // ClanWars: Selfdeclared wars - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_enemyclan = cl_id) WHERE cw_initclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - break; - case 512: // ClanWars: Foreigndeclared wars - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 4; - snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) WHERE cw_enemyclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - break; - case 513: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_faction = %d AND cl_id != %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - break; - case 514: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); - break; - case 520: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 10; - snprintf (mSQLQuery, 500, "SELECT cl_faction, cl_shortdesc, cl_name, cl_description, 0, cl_appid, 80, cl_money, (SELECT count(*) FROM outposts WHERE o_clan = %d), (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str())); - - break; - case 521: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE c_clan = %d AND cll_level >= %d AND cll_level < 15 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 522: - if(!ChkOpt(nNumOptions, 5)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); - - break; - case 523: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_leader, cl_description, cl_minsympathy FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); - - break; - case 540: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 541: - if(!ChkOpt(nNumOptions, 3)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT v_id, v_type FROM vehicles WHERE v_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 542: - if(!ChkOpt(nNumOptions, 2)) break; - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_world, v_status, v_condition FROM vehicles WHERE v_owner = %d and v_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - - break; - case 544: - if(!ChkOpt(nNumOptions, 4)) break; - mResultFields = 1; - snprintf (mSQLQuery, 500, "SELECT count(*) FROM clanwars WHERE (cw_initclan = %d AND cw_enemyclan = %d) OR (cw_enemyclan = %d AND cw_initclan = %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); - - break; - case 546: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 2; - snprintf (mSQLQuery, 500, "SELECT cw_starttime, (TO_DAYS(NOW()) - TO_DAYS(cw_starttime)) FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str())); - - break; - case 547: - if(!ChkOpt(nNumOptions, 1)) break; - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT cw_initclan, cw_enemyclan, cw_starttime, cw_status, cw_statement_initiator, cw_statement_enemy FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str())); - - break; - case 557: - Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 558: - Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 562: - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT cb_inscription FROM datacubes WHERE cb_id = %d", atoi(nOptions[0].c_str())); - - break; - case 569: - // Faction representatives. Not stored yet... is it? - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 570: - // Clan representatives. Stored but this query wants votes too... Maybe later - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 571: - // Clan representatives. Stored but this query wants votes too... Maybe later - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 572: - // Runner voting. Not stored yet - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 573: - // Next election date - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 574: - mResultFields = 6; - snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM characters WHERE c_faction = %d", atoi(nOptions[0].c_str())); - - break; - case 575: - // Runner satisfaction with faction - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 576: - // Check if vote from runner is already stored - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 582: - // Clan representative details. Faction rank etc... not stored yet - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 583: - // Clan representative details. Faction rank etc... not stored yet - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 584: - // Clan representative details. Faction rank etc... not stored yet - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 587: - // Clan representative stuff again... - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 603: - mResultFields = 1; - //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 0"); - snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 0 AND su_finished = 0"); - - break; - case 604: - mResultFields = 1; - //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 1"); - snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 1 AND su_finished = 0"); - - break; - case 605: - mResultFields = 1; - //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 2"); - snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_finished = 1"); - - break; - case 606: - mResultFields = 1; - //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report`"); - snprintf (mSQLQuery, 500, "SELECT count(*) FROM support"); - - break; - case 607: // Dont know how to select data from sql where no data to JOIN is there anymore :/ - // This should query ID, RunnerID and Date from bug reports where runnerID is unknown - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 608: - mResultFields = 5; - snprintf (mSQLQuery, 500, "SELECT br_id, br_fromid, br_location, br_status, br_datetime FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); - - break; - case 609: - mResultFields = 1; - //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_supid = %s", nOptions[0].c_str()); - snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str())); - - break; - case 610: - mResultFields = 6; - //snprintf (mSQLQuery, 500, "SELECT br_id, \"0\", c_name, br_location, br_status = 2, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_supid = %s AND br_status > 0 LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str()); - snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - - break; - case 611:// Well, its meant to show date specific stuff. I will rewrite this soon... - snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str())); - break; - case 612:// Well, its meant to show date specific stuff. I will rewrite this soon... - snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); - break; - case 625: // Faction council stuff - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 626: // Faction council stuff - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 627: // Faction council stuff - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 628: // Faction council stuff - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 629: // Faction council stuff - Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - default: - Console->Print("%s [Pterminal::HandleReceiveDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID); - return false; - } - - if(strlen(mSQLQuery) == 0) - return false; -// --------------- - MYSQL_RES *result = NULL; - MYSQL_ROW row; - int tNumRows = 0; - - result = MySQL->GameResQuery(mSQLQuery); - if (!result) - { - Console->Print("Cannot query DB. DBID: %d query was: %s", nDBID, mSQLQuery); - MySQL->ShowGameSQLError(); - return false; - } - - PMessage* tDBResult = new PMessage(); - tNumRows = mysql_num_rows(result); - - // Loop all result rows - for (int i = 0; i < tNumRows ; i++) - { - row = mysql_fetch_row( result ) ; - // Loop all result fields and push answers into Message - for (int t = 0; t < mResultFields; t++) - { - *tDBResult << ( uint16_t )(strlen(row[t]) + 1); - *tDBResult << row[t]; - } - } - - // Build result messages - char tCmd[100]; - memset(tCmd, '\0', 100); - strncpy(tCmd, nCommandName->c_str(), 100); - - PMessage* tmpMsg_allowed = MsgBuilder->BuildTryAccessAnswerMsg( nClient, tCmd, true ); - PMessage* tmpMsg_result = MsgBuilder->BuildReceiveDBAnswerMsg( nClient, tDBResult, nCommandName, tNumRows, mResultFields); - - nClient->SendUDPMessage(tmpMsg_allowed); - nClient->FragmentAndSendUDPMessage(tmpMsg_result, 0x68); - - return true; -} +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +bool PTerminal::HandleReceiveDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown) +{ + EraseVars(); + int nAccessLevel = nClient->GetAccountLevel(); + //Console->Print("DBID: %d", nDBID); + + switch (nDBID) + { + case 8: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 6; + if(!strncmp(nOptions[0].c_str(), "date", 4)) + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + else + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 9: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 6; + if(!strncmp(nOptions[0].c_str(), "date", 4)) + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + else + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 1 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 10: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 6; + if(!strncmp(nOptions[0].c_str(), "date", 4)) + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + else + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_approved FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_approved FROM `neochronicle` WHERE nc_approved = 0 ORDER BY nc_datetime DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 11: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 6; + //snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, c_name, nc_name, nc_content FROM `neochronicle` INNER JOIN characters ON (nc_author = c_id) WHERE nc_id = %d", atoi(nOptions[0].c_str())); + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_icon, nc_datetime, nc_author, nc_name, nc_content FROM `neochronicle` WHERE nc_id = %d", atoi(nOptions[0].c_str())); + //snprintf (mSQLQuery, 500, "SELECT na_id, \'\', na_datetime, na_author, na_name, na_content FROM `neocron articles` WHERE na_approval = 1 AND na_id = %d", atoi(nOptions[0].c_str())); + + break; + case 14: + // 0: ID 1: Short 2: Clanname 3: FactionID 4: Faction Symp + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 6; // TODO: replace 0 with average faction sympathy + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM `clans` WHERE cl_name LIKE \"%%%s%%\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 16: + if(!ChkOpt(nNumOptions, 3)) break; + if (!strcmp (nOptions[0].c_str(), "Neocronicle")) + { + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name FROM `neocron articles` WHERE na_approval = 1 LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str()); + } + else + { + mResultFields = 7; + snprintf (mSQLQuery, 500, "SELECT na_id, \'0\', na_datetime, na_author, na_name, na_approval, \"0\" FROM `neocron articles` LIMIT %s, %s", nOptions[1].c_str(), nOptions[2].c_str()); + } + + break; + case 18: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 20: + case 21: + // Select either c_"name" or c_"minsympathy". Names taken from option, saves if/else + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT `cl_%s` FROM `clans` WHERE `cl_id` = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str())); + + break; + case 25: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 6; // TODO: replace 0 with average faction sympathy + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction, \"0\", \"0\" FROM clans WHERE cl_name > \"%s\" AND cl_name <=\"%s\" LIMIT %d, %d", nOptions[0].c_str(), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 26: + // 0: short 1: name 2: money 3: faction 4: fac symp 5: symp_to_join 6: cappid + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_money, cl_faction, \"0\", cl_minsympathy, cl_appid FROM `clans` WHERE `cl_id` = %d", atoi(nOptions[0].c_str())); + + break; + case 27: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_description, count(DISTINCT o_outnum), count(DISTINCT c_id) FROM outposts INNER JOIN clans ON (o_clan = cl_id) INNER JOIN characters ON (c_clan = clans.cl_id) WHERE (cl_id = %d) GROUP BY cl_id", atoi(nOptions[0].c_str())); + + break; + case 28: + // Faction missions? Never seen them even in NC2... + Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 29: + Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Ordercol was missing. Its: [%s]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, nOptions[0].c_str()); + break; + case 34: + // Name, Add. Info, Profession, Description, Overal Ranking, Soullight, Money, Runner Kills, Creature Kills + // Note: Add. Info is autogenerated clientside! + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 8; + snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\", \"1\", \"127\", c_cash, \"0\", \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 38: + // Faction missions? Never seen them even in NC2... + Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d has not been written yet; Factionmissions..? Never seen them", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 39: + // 0:id 1:name 2:clan 3:fac.symp + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, \"75\" FROM characters WHERE c_name LIKE \"%s\"", nOptions[0].c_str()); + + break; + case 41: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT o_outnum, o_outnum, \"0\", \"0\", \"0\" FROM outposts WHERE o_clan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 46: + // charid, charname, charclanlevel, clanlevelname, charfactionsymp, char online + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, \"0\", c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d) AND (cll_level >= %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 47: + if(!ChkOpt(nNumOptions, 5)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); + + break; + case 48: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 49: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 50: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 2; //Fieldnum + snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d", atoi(nOptions[0].c_str())); + + break; + case 51: + if(!ChkOpt(nNumOptions, 9)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[7].c_str()), atoi(nOptions[8].c_str())); + + break; + case 52: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 54: + // id, name, rank, rankname, f.symp + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 0 FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str())); + + break; + case 60: // Query for OutPost state. Result is + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan FROM outposts LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 61: // It should display the clanname, but it doesnt. seems to be clientside bug + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT o_outnum, o_clan, o_clan, o_security FROM outposts WHERE o_outnum = %d", atoi(nOptions[0].c_str())); + + break; + case 75: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 76: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (cll_clanid = %d AND cll_desc = \"%s\")", atoi(nOptions[0].c_str()),nOptions[1].c_str()); + + break; + case 85: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 6; // No idea why this Fac.Symp is that high... 1000000 is 100 ingame. But only for this query + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, cll_level, cll_desc, 1000000, c_online FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_online = %d OR c_online = 1) AND c_clan = %d LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 86: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + if(!strncmp(nOptions[1].c_str(), "date", 4)) + snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + else + snprintf (mSQLQuery, 500, "SELECT mt_id, mt_amount, mt_date, c_name FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 87: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_name, mt_date, mt_amount, mt_comment FROM moneytransactions INNER JOIN characters ON (mt_player = c_id) WHERE mt_id = %d", atoi(nOptions[0].c_str())); + + break; + case 92: + if(!ChkOpt(nNumOptions, 1)) break; + // Location of player + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT c_location FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 93: + if(!ChkOpt(nNumOptions, 1)) break; + // Name, Add. Info, Profession, Description + // Note: Add. Info is autogenerated clientside! + mResultFields = 3; + snprintf (mSQLQuery, 500, "SELECT c_name, c_profession, \"0\" FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 96: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT f_showname FROM forums WHERE f_name = \"%s\"", nOptions[0].c_str()); + + break; + case 98: + // ID, Name, Online, 0, Soullight + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_online, \"0\", c_soullight FROM characters WHERE c_online = %d AND c_soullight <= -%d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + break; + case 99: + // Terrorist info + // id, name, faction, clan, clanlevel, location + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_faction, c_clan, cll_level, c_location FROM clanlevels INNER JOIN characters ON (cll_charid = c_id) WHERE (c_id = %d AND c_soullight <= -%d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 108: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); + + break; + case 109: + if(!ChkOpt(nNumOptions, 1)) break; + // The only case where KK used an DBId twice for completely different things... + if(nNumOptions < 3) + { + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_clan, cll_level, cll_desc FROM characters INNER JOIN clanlevels ON (cll_charid = c_id AND cll_clanid = c_clan) WHERE c_id = %d", atoi(nOptions[0].c_str())); + } + else if(nNumOptions == 3) + { + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT c_id, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + } + + break; + case 116: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT wr_id FROM worlds WHERE wr_group = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 125: + // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =) + //if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT 255"); + + break; + case 126: + // Return position in Helpqueue. todo yet... for now its 255, we're always busy! =) + // This is with Datecheck, somehow.. + //if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT 255"); + + break; + case 127: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT c_name, apt_location FROM apartments INNER JOIN characters ON (apt_owner = c_id) WHERE (c_id = %d)", atoi(nOptions[0].c_str())); + + break; + case 128: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT su_id FROM support WHERE su_supporterid = %d AND su_finished = 0", atoi(nOptions[0].c_str())); + + case 131: + mResultFields = 6; + //snprintf(mSQLQuery, 500, "SELECT br_id, br_type, c_online, c_name, br_location, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_status = %d LIMIT %d, %d", + // atoi(nOptions[0].c_str())+atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + snprintf(mSQLQuery, 500, "SELECT su_id, su_type, 0, c_name, su_worldid, su_datetime FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_inwork = %d AND su_finished = %d LIMIT %d, %d", + atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 132: + // reqid, runnerid, runnername, 0, date/time, type, 0, in work, finished, desc + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 10; + //snprintf(mSQLQuery, 500, "SELECT br_id, br_fromid, c_name, \"0\", br_datetime, br_type, \"0\", br_status, br_status, br_desc FROM `bug report` INNER JOIN characters ON (br_fromid = c_id) WHERE br_id = %d", atoi(nOptions[0].c_str())); + snprintf(mSQLQuery, 500, "SELECT su_id, su_player, c_name, 0, su_datetime, su_type, su_supporterid, su_inwork, su_finished, su_desc FROM support INNER JOIN characters ON (su_player = c_id) WHERE su_id = %d", atoi(nOptions[0].c_str())); + + break; + case 134: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf(mSQLQuery, 500, "SELECT br_id FROM bug_report WHERE br_fromid = %d", atoi(nOptions[0].c_str())); + + break; + case 136: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + break; + case 137: + if(!ChkOpt(nNumOptions, 1)) break; + // runnerid, runnername, location, online + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str()); + break; + case 138: + if(!ChkOpt(nNumOptions, 1)) break; + // runnerid, runnername, location, online + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT br_type, br_location, br_datetime, br_supid, br_status, br_desc FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); + break; + case 143: + if(!ChkOpt(nNumOptions, 1)) break; + // runnerid, runnername, location, online + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT a.a_id, a.a_username, b.c_id, 0, b.c_location, b.c_online FROM `%s`.accounts AS a, `%s`.characters AS b WHERE b.c_name = \"%s\" AND a.a_id = b.a_id", + Config->GetOption("info_sql_database").c_str(), Config->GetOption("game_sql_database").c_str(), nOptions[0].c_str()); + break; + case 144: + mResultFields = 2; // Replace "1" with Online/Offline! + snprintf (mSQLQuery, 500, "SELECT c_location, c_online FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 145: + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT a_email FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str())); + + break; + case 146: + mResultFields = 4; + // Too bad we named the row different... + char tSortRow[10]; + if(!strncmp(nOptions[1].c_str(), "world", 5)) + strcpy(tSortRow, "location"); + else + strcpy(tSortRow, "name"); + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" ORDER BY `c_%s` LIMIT %d, %d", nOptions[0].c_str(), tSortRow, atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 147: + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_online = %d ORDER BY `c_%s` LIMIT %d, %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 148: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, \"0\", \"0\", c_id FROM clans INNER JOIN characters ON (cl_leader = c_id) WHERE (cl_id = %d)", atoi(nOptions[0].c_str())); + + break; + case 150: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 151: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 153: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 154: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 155: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 156: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 157: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 158: + // Mission stuff. Will be added later! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 175: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT br_id, br_type, br_title, br_datetime FROM bug_report LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 176: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 8; + snprintf (mSQLQuery, 500, "SELECT br_type, br_status, br_title, br_desc, 0, br_datetime, br_location, br_fromid FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); + + break; + case 181: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 3; + snprintf (mSQLQuery, 500, "SELECT c_name, apt_location, apt_password FROM apartments INNER JOIN characters ON (c_id = apt_owner) WHERE apt_id = %d", atoi(nOptions[0].c_str())); + + break; + case 183: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name, (SELECT count(*) FROM characters WHERE c_clan = %d), c_name, apt_id, apt_location FROM clans INNER JOIN apartments ON (cl_appid = apt_id) INNER JOIN characters ON (c_clan = cl_id) AND (apt_owner = c_id) WHERE (cl_id = %d) GROUP BY c_id", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str())); + + break; + case 186: + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \"%s\"", nOptions[0].c_str()); + + break; + case 220: + mResultFields = 4; //Fieldnum + snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_status, v_condition FROM vehicles WHERE v_owner = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 221: + //VehicleControl order. "VehicleControl", "Type", "Status", "Condition", "Repairprice?" + mResultFields = 4; //Fieldnum + snprintf (mSQLQuery, 500, "SELECT v_type, v_status, v_condition, \"0\" FROM vehicles WHERE v_id = %s", nOptions[0].c_str()); + + break; + case 225: + // Statistics. Maybe later... + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 226: + // Statistics. Maybe later... + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 230: + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, st_curval-st_oldval FROM stockx"); + + break; + case 231: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT st_id, st_factid, st_curval, (st_curval - st_oldval) FROM stockx WHERE (st_id = %d)", atoi(nOptions[0].c_str())); + + break; + case 232: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT sxd_id, st_factid, st_curval, sxd_amount, (sxd_amount * st_curval) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE (sxd_playerid = %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 233: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 7; + snprintf (mSQLQuery, 500, "SELECT st_factid, sxd_amount, (st_curval - st_oldval), st_curval, sxd_paid, (sxd_amount * st_curval), ((sxd_amount * st_curval) - sxd_paid) FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) where sxd_id = %d", atoi(nOptions[0].c_str())); + + break; + case 234: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 3; + snprintf (mSQLQuery, 500, "SELECT sxd_id, sxd_amount, sxd_paid FROM stockx_depots INNER JOIN stockx ON (sxd_st_id = st_id) WHERE sxd_playerid = %d AND st_factid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 250: + // Influence from CharID? Is stockx gm controlled?? + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 251: + // What is this "influence" ? Check this on live servers! + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 260: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 2; //Fieldnum + snprintf (mSQLQuery, 500, "SELECT f_showname, f_name FROM forums WHERE f_area = %d+%d+%d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 261: + // Maybe even rewrite BB system.. its wrong written anyways.... + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 262: + // This is wrong! 262 is the receiveDB request for FACTION threadlist. It should be limitet to that faction then + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str()); + + //TODO Check this. Same (?) for ID 52,262,267,401 and 411 + break; + case 266: + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND f_name = \'%s\' AND fp_replyid = 0 AND fp_clanid = %d LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 267: + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM `forum_posts`, forums, characters WHERE fp_forumid = f_id AND c_id = fp_fromid AND (fp_id = %s OR fp_replyid = %s)", nOptions[0].c_str(), nOptions[1].c_str()); + + break; + case 270: + Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d Tablename/Name is: [%s] ThreadID is: [%d]", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID, atoi(nOptions[0].c_str()), nOptions[1].c_str()); + break; + case 360: + // Gamemaster name (char), Accountname, Location, Online, CharID + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT a.a_id, c.c_id, a.a_username, c.c_name, c.c_online, c.c_location FROM %s.characters AS c, %s.accounts AS a WHERE a.a_priv >= 50 AND c.c_online = %d AND c.a_id = a.a_id ORDER BY c.c_name LIMIT %d, %d", + Config->GetOption("game_sql_database").c_str(), Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 365: + // ID, short, name faction + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 366: + // ID, short, name faction WHERE clanname = %s + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_faction FROM clans WHERE cl_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 367: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 8; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_shortdesc, cl_name, cl_leader, cl_faction, cl_appid, cl_money, (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str())); + + break; + case 368: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cll_desc, cll_level FROM clanlevels WHERE cll_clanid = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 373: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, apt_type, apt_password FROM apartments WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 375: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 376: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online FROM characters WHERE c_name LIKE \"%s\" LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 377: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT DISTINCT a_id FROM characters WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 378: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT a_username, a_email, \"Since begin\", \"Never\", FROM_UNIXTIME(a_bandate) FROM `%s`.accounts WHERE a_id = %d", Config->GetOption("info_sql_database").c_str(), atoi(nOptions[0].c_str())); + + break; + case 379: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, c_location, c_online, c_clan, cll_level FROM characters INNER JOIN clanlevels ON (cll_charid = c_id) WHERE c_id = %d", atoi(nOptions[0].c_str())); + + break; + case 380: // clean + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cl_name, cll_desc FROM clans INNER JOIN clanlevels ON (cll_clanid = cl_id) WHERE cl_id = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 381: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, c_online FROM characters WHERE a_id = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 384: // clean + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location, 0, apt_password FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 400: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 401: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 406: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT count(fp_id) FROM forum_posts INNER JOIN forums ON (fp_forumid = f_id) WHERE f_name = \"%s\"", nOptions[0].c_str()); + + break; + case 410: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT fp_id, fp_name, c_name, fp_datetime FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\" AND fp_factionid = %d) LIMIT %d, %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 411: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT c_name, fp_name, fp_datetime, fp_content FROM forum_posts INNER JOIN forums ON (fp_forumid = f_area) INNER JOIN characters ON (fp_fromid = c_id) WHERE (f_name = \"%s\") AND (fp_id = %d OR fp_replyid = %d) AND (fp_factionid = %d)", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + + case 420: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_new, e_replied, e_datetime FROM emails, characters WHERE e_fromid = c_id AND e_toid = %i LIMIT %i, %i", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 421: + if(!ChkOpt(nNumOptions, 1)) break; + //MailControl order. "MailControl", "Mail ID", "Subject", "From", boolean Replied, "Date/Time", "FromID", "Content" + mResultFields = 7; + snprintf (mSQLQuery, 500, "SELECT e_id, e_subject, c_name, e_replied, e_datetime, e_fromid, e_body FROM emails, characters WHERE e_fromid = c_id AND e_id = %s", nOptions[0].c_str()); + + break; + case 425: + if(!ChkOpt(nNumOptions, 1)) break; + //Send mail order. "SendMail", "id" + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT c_id FROM characters WHERE c_name = \'%s\'", nOptions[0].c_str()); + + break; + case 430: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str()); + + break; + case 431: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT a.c_id, a.c_conid, b.c_name, a.c_desc FROM contacts as a, characters as b WHERE a.c_conid = b.c_id AND a.c_id = %s", nOptions[0].c_str()); + + break; + case 435: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT count(*) FROM contacts WHERE c_listid = %s AND c_type = %s", nOptions[0].c_str(), nOptions[1].c_str()); + + break; + case 436: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name FROM characters WHERE c_name LIKE \'%%%s%%\' LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str()); + + break; + case 437: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 1; //Fieldnum + snprintf (mSQLQuery, 500, "SELECT c_name FROM characters WHERE c_id = %s", nOptions[0].c_str()); + + break; + case 445: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_name FROM neochronicle WHERE nc_lang = %d ORDER BY nc_id DESC LIMIT %d, %d", atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 446: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT nc_id, nc_lang, nc_datetime, nc_name, nc_content FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str())); + + break; + case 453: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT g_id, 0, g_part, g_title, g_language FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 455: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 3; + // Opt 2 is Language + snprintf (mSQLQuery, 500, "SELECT g_id, g_part, g_title FROM guides WHERE g_chapter = %d AND g_language = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 456: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT g_id, g_language, g_title, g_content FROM guides WHERE g_id = %d", atoi(nOptions[0].c_str())); + + break; + case 458: // Statisics + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 459: // Statisics + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 510: // ClanWars: Overview + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) or (cw_enemyclan = cl_id) WHERE (cw_enemyclan = %d OR cw_initclan = %d) AND (cl_id != %d) LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + break; + case 511: // ClanWars: Selfdeclared wars + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_enemyclan = cl_id) WHERE cw_initclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + break; + case 512: // ClanWars: Foreigndeclared wars + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 4; + snprintf (mSQLQuery, 500, "SELECT cw_id, cl_name, cw_starttime, cw_status FROM clanwars INNER JOIN clans ON (cw_initclan = cl_id) WHERE cw_enemyclan = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + break; + case 513: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_faction = %d AND cl_id != %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + break; + case 514: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cl_id, cl_name FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); + break; + case 520: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 10; + snprintf (mSQLQuery, 500, "SELECT cl_faction, cl_shortdesc, cl_name, cl_description, 0, cl_appid, 80, cl_money, (SELECT count(*) FROM outposts WHERE o_clan = %d), (SELECT count(*) FROM characters WHERE c_clan = %d) FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[0].c_str())); + + break; + case 521: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE c_clan = %d AND cll_level >= %d AND cll_level < 15 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 522: + if(!ChkOpt(nNumOptions, 5)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT c_id, c_name, 0, cll_desc, 0, c_online FROM characters INNER JOIN clanlevels ON (c_id = cll_charid) WHERE cll_level >= %d AND cll_level <= %d AND c_clan = %d ORDER BY cll_level DESC LIMIT %d, %d", atoi(nOptions[2].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); + + break; + case 523: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT cl_shortdesc, cl_name, cl_leader, cl_description, cl_minsympathy FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); + + break; + case 540: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT apt_id, apt_location FROM apartments WHERE apt_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 541: + if(!ChkOpt(nNumOptions, 3)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT v_id, v_type FROM vehicles WHERE v_owner = %d LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 542: + if(!ChkOpt(nNumOptions, 2)) break; + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT v_id, v_type, v_world, v_status, v_condition FROM vehicles WHERE v_owner = %d and v_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + + break; + case 544: + if(!ChkOpt(nNumOptions, 4)) break; + mResultFields = 1; + snprintf (mSQLQuery, 500, "SELECT count(*) FROM clanwars WHERE (cw_initclan = %d AND cw_enemyclan = %d) OR (cw_enemyclan = %d AND cw_initclan = %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str())); + + break; + case 546: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 2; + snprintf (mSQLQuery, 500, "SELECT cw_starttime, (TO_DAYS(NOW()) - TO_DAYS(cw_starttime)) FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str())); + + break; + case 547: + if(!ChkOpt(nNumOptions, 1)) break; + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT cw_initclan, cw_enemyclan, cw_starttime, cw_status, cw_statement_initiator, cw_statement_enemy FROM clanwars WHERE cw_id = %d", atoi(nOptions[0].c_str())); + + break; + case 557: + Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 558: + Console->Print("%s [Pterminal::HandleReceiveDB] QueryID %d means that you want to edit an DialogScript from the server. This is not supportet yet!", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 562: + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT cb_inscription FROM datacubes WHERE cb_id = %d", atoi(nOptions[0].c_str())); + + break; + case 569: + // Faction representatives. Not stored yet... is it? + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 570: + // Clan representatives. Stored but this query wants votes too... Maybe later + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 571: + // Clan representatives. Stored but this query wants votes too... Maybe later + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 572: + // Runner voting. Not stored yet + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 573: + // Next election date + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 574: + mResultFields = 6; + snprintf (mSQLQuery, 500, "SELECT count(c_id) FROM characters WHERE c_faction = %d", atoi(nOptions[0].c_str())); + + break; + case 575: + // Runner satisfaction with faction + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 576: + // Check if vote from runner is already stored + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 582: + // Clan representative details. Faction rank etc... not stored yet + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 583: + // Clan representative details. Faction rank etc... not stored yet + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 584: + // Clan representative details. Faction rank etc... not stored yet + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 587: + // Clan representative stuff again... + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 603: + mResultFields = 1; + //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 0"); + snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 0 AND su_finished = 0"); + + break; + case 604: + mResultFields = 1; + //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 1"); + snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_inwork = 1 AND su_finished = 0"); + + break; + case 605: + mResultFields = 1; + //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_status = 2"); + snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_finished = 1"); + + break; + case 606: + mResultFields = 1; + //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report`"); + snprintf (mSQLQuery, 500, "SELECT count(*) FROM support"); + + break; + case 607: // Dont know how to select data from sql where no data to JOIN is there anymore :/ + // This should query ID, RunnerID and Date from bug reports where runnerID is unknown + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 608: + mResultFields = 5; + snprintf (mSQLQuery, 500, "SELECT br_id, br_fromid, br_location, br_status, br_datetime FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); + + break; + case 609: + mResultFields = 1; + //snprintf (mSQLQuery, 500, "SELECT count(*) FROM `bug report` WHERE br_supid = %s", nOptions[0].c_str()); + snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str())); + + break; + case 610: + mResultFields = 6; + //snprintf (mSQLQuery, 500, "SELECT br_id, \"0\", c_name, br_location, br_status = 2, br_datetime FROM `bug report`, characters WHERE c_id = br_fromid AND br_supid = %s AND br_status > 0 LIMIT %s, %s", nOptions[0].c_str(), nOptions[1].c_str(), nOptions[2].c_str()); + snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + + break; + case 611:// Well, its meant to show date specific stuff. I will rewrite this soon... + snprintf (mSQLQuery, 500, "SELECT count(*) FROM support WHERE su_supporterid = %d", atoi(nOptions[0].c_str())); + break; + case 612:// Well, its meant to show date specific stuff. I will rewrite this soon... + snprintf (mSQLQuery, 500, "SELECT su_id, su_supporterid, c_name, su_worldid, su_finished, su_datetime FROM support INNER JOIN characters ON (su_supporterid = c_id) WHERE su_supporterid = %d AND su_finished = 1 LIMIT %d, %d", atoi(nOptions[0].c_str()), atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); + break; + case 625: // Faction council stuff + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 626: // Faction council stuff + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 627: // Faction council stuff + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 628: // Faction council stuff + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 629: // Faction council stuff + Console->Print("%s [Pterminal::HandleReceiveDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + default: + Console->Print("%s [Pterminal::HandleReceiveDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID); + return false; + } + + if(strlen(mSQLQuery) == 0) + return false; +// --------------- + MYSQL_RES *result = NULL; + MYSQL_ROW row; + int tNumRows = 0; + + result = MySQL->GameResQuery(mSQLQuery); + if (!result) + { + Console->Print("Cannot query DB. DBID: %d query was: %s", nDBID, mSQLQuery); + MySQL->ShowGameSQLError(); + return false; + } + + PMessage* tDBResult = new PMessage(); + tNumRows = mysql_num_rows(result); + + // Loop all result rows + for (int i = 0; i < tNumRows ; i++) + { + row = mysql_fetch_row( result ) ; + // Loop all result fields and push answers into Message + for (int t = 0; t < mResultFields; t++) + { + *tDBResult << ( uint16_t )(strlen(row[t]) + 1); + *tDBResult << row[t]; + } + } + + // Build result messages + char tCmd[100]; + memset(tCmd, '\0', 100); + strncpy(tCmd, nCommandName->c_str(), 100); + + PMessage* tmpMsg_allowed = MsgBuilder->BuildTryAccessAnswerMsg( nClient, tCmd, true ); + PMessage* tmpMsg_result = MsgBuilder->BuildReceiveDBAnswerMsg( nClient, tDBResult, nCommandName, tNumRows, mResultFields); + + nClient->SendUDPMessage(tmpMsg_allowed); + nClient->FragmentAndSendUDPMessage(tmpMsg_result, 0x68); + + return true; +} diff --git a/TinNS/Source/GameServer/TerminalUpdateDatabase.cxx b/TinNS/Source/GameServer/TerminalUpdateDatabase.cxx index 96a57b1..3490aef 100644 --- a/TinNS/Source/GameServer/TerminalUpdateDatabase.cxx +++ b/TinNS/Source/GameServer/TerminalUpdateDatabase.cxx @@ -1,332 +1,332 @@ -#include -#include -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -bool PTerminal::HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown) -{ - std::ostringstream tLongSQL; // omg my eyes... Stringstream is one of the worst inventions ever! Stick with printf syntax!!111 - char tShortSQL[1024]; // Use this for small updates that will not exceed 1kb - memset(tShortSQL, '\0', 1024); - bool tSuccess = false; - - //Console->Print("UpdateDB ID: %d", nDBID); - switch (nDBID) - { - case 5: - tLongSQL << "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content)"; - tLongSQL << " VALUES (" << atoi(nOptions[0].c_str()) << ", \"" << nOptions[1] << "\", \"" << nOptions[2] << "\", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")"; - - break; - case 6: - // UPDATE when Neocronicle DB is changed! author must be CHAR not INT - break; - case 7: // Delete neocronicle - snprintf(tShortSQL, 1024, "DELETE FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str())); - break; - case 12: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 53: // Runner writing to public board - snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str()); - break; - case 58: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 62: // Set new outpost security - snprintf(tShortSQL, 1024, "UPDATE outposts SET o_security = %d WHERE o_outnum = %d AND o_clan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - break; - - case 66: // Claninfo stuff that is somehow never used... Print error if it is - case 67: - Console->Print("%s [Pterminal::HandleUpdateDB] QueryID %d should never happen. Please contact Linux Addited forums!", Console->ColorText(RED,BLACK,"Notice"), nDBID); - break; - - case 77: // Delete old clanlevel - snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - break; - case 78: // Add new clanlevel - snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_desc, cll_level) VALUES (%d, \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str())); - break; - case 84: // Take/Give money to/from clan - tLongSQL << "INSERT INTO moneytransactions (mt_clanid, mt_player, mt_amount, mt_date, mt_comment) "; - tLongSQL << "VALUES (" << atoi(nOptions[0].c_str()) << ", " << atoi(nOptions[1].c_str()) << ", " << atoi(nOptions[2].c_str()) << ", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")"; - break; - case 94: // Update runner description - snprintf(tShortSQL, 1024, "UPDATE characters SET c_desc = \"%s\" WHERE c_id = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str())); - break; - case 97: - // Just ignore that... KK required some extra updates here - tSuccess = true; - //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 120: // Create support call - snprintf(tShortSQL, 1024, "INSERT INTO support (su_player, su_worldid, su_type, su_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str()); - break; - case 121: - snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - break; - case 122: - snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 0, su_supporterid = 0 WHERE su_id = %d AND su_supporterid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - break; - case 123: - snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_finished = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - break; - case 124: - snprintf(tShortSQL, 1024, "DELETE FROM support WHERE su_id = %d", atoi(nOptions[0].c_str())); - break; - case 133: - tSuccess = true; - //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 139: - snprintf(tShortSQL, 1024, "UPDATE characters SET c_location = %d WHERE c_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); - break; - case 142: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 149: // Changeleader 2nd step. Update clanappartment owner - snprintf(tShortSQL, 1024, "UPDATE apartments SET apt_owner = %d WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - break; - case 160: // Missions, not yet - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 161: // Missions, not yet - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 162: // Missions, not yet - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 163: // Missions, not yet - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 164: // Missions, not yet - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 165: // Missions, not yet - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 170: // Enter new bug - snprintf(tShortSQL, 1024, "INSERT INTO bug_report (br_type, br_status, br_title, br_desc, br_location, br_fromid, br_datetime) VALUES (%d, %d, \"%s\", \"%s\", %d, %d, NOW())", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()), atoi(nOptions[5].c_str())); - break; - case 172: // Delete bug id %d - snprintf(tShortSQL, 1024, "DELETE FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); - break; - case 180: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 182: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 235: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 252: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 263: // Runner writing to Faction Board - snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str()); - break; - case 268: // Runner writing to ClanBoard - snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_clanid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str()); - break; - case 370: // GM ClanRepair - snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_level, cll_desc) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str()); - break; - case 385: // Clandelete 1/7 Clanlevels - snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cl_clanid = %d", atoi(nOptions[0].c_str())); - break; - case 386: // Clandelete 2/7 Outposts - snprintf(tShortSQL, 1024, "UPDATE outposts SET o_clan = 0 WHERE o_clan = %d", atoi(nOptions[0].c_str())); - break; - case 387: // Clandelete 3/7 Free users from clans - snprintf(tShortSQL, 1024, "UPDATE characters SET c_clan = 0 WHERE c_clan = %d", atoi(nOptions[0].c_str())); - break; - case 388: // Clandelete 4/7 The clan itself - snprintf(tShortSQL, 1024, "DELETE FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); - break; - case 389: // Clandelete 5/7 ? - tSuccess = true; - break; - case 390: // Clandelete 6/7 Clanappartment - snprintf(tShortSQL, 1024, "DELETE FROM apartments WHERE apt_id = %d", atoi(nOptions[0].c_str())); - break; - case 391: // Clandelete 7/7 ? - tSuccess = true; - break; - case 402: // GM writing to publicforum - snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str()); - break; - case 404: // GM deleting forum entry step 1 - snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_id = %d", atoi(nOptions[0].c_str())); - break; - case 405: // GM deleting forum entry step 2 - snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_replyid = %d", atoi(nOptions[0].c_str())); - break; - case 412: // GM writing to faction forum - snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str()); - break; - case 422: // Mark email as replied - snprintf(tShortSQL, 1024, "UPDATE emails SET e_replied = 1 WHERE e_id = %d", atoi(nOptions[0].c_str())); - break; - case 423: // Write new email - snprintf(tShortSQL, 1024, "INSERT INTO emails (e_fromid,e_toid,e_datetime,e_subject,e_body) VALUES (%d, %d, \"%s\", \"%s\", \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str()); - break; - case 424: // Delete email - snprintf(tShortSQL, 1024, "DELETE FROM emails WHERE e_id = %d", atoi(nOptions[0].c_str())); - break; - case 426: // Mark email as read - snprintf(tShortSQL, 1024, "UPDATE emails SET e_new = 0 WHERE e_id = %d", atoi(nOptions[0].c_str())); - break; - case 432: // Add new contact - snprintf(tShortSQL, 1024, "INSERT INTO contacts (c_listid,c_conid,c_type,c_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str()); - break; - case 433: // Edit contact - snprintf(tShortSQL, 1024, "UPDATE contacts SET c_type = %d, c_desc = \"%s\" WHERE c_id = %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str())); - break; - case 434: // Delete contact - snprintf(tShortSQL, 1024, "DELETE FROM contacts WHERE c_id = %d", atoi(nOptions[0].c_str())); - break; - case 447: - snprintf(tShortSQL, 1024, "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content, nc_lang) VALUES (%d, \"%s\", \"%s\", \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str(), atoi(nOptions[5].c_str())); - break; - case 450: - snprintf(tShortSQL, 1024, "INSERT INTO guides (g_chapter, g_part, g_title, g_content, g_language) VALUES (%d, %d, \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str())); - break; - case 515: // Create new clanwar - snprintf(tShortSQL, 1024, "INSERT INTO clanwars (cw_initclan, cw_enemyclan, cw_starttime) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str()); - break; - case 516: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 517: - // Special: Check if Clan of our char is = nOption2 - if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) - snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_initclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - // else: SQL Query is empty = failed as result - break; - case 518: - if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) - snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_enemyclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - // else: SQL Query is empty = failed as result - break; - case 519: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 525: // Update clan short - tLongSQL << "UPDATE clans SET cl_shortdesc = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); - - break; - case 526: // Update clan name - tLongSQL << "UPDATE clans SET cl_name = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); - - break; - case 527: // Update clanapp password - //UPDATE apartments SET apt_password = x WHERE apt_owner = x AND apt_id = (SELECT clans.cl_appid WHERE clans.cl_id = x) - tLongSQL << "UPDATE apartments SET apt_password = \"" << nOptions[0] << "\" WHERE apt_owner = " << atoi(nOptions[2].c_str()) << " AND apt_id = (SELECT cl_appid FROM clans WHERE cl_id = " << atoi(nOptions[1].c_str()) << ")"; - break; - case 528: - tLongSQL << "UPDATE clans SET cl_minsympathy = " << atoi(nOptions[0].c_str()) << " WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); - break; - case 529: - tLongSQL << "UPDATE clans SET cl_description = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); - break; - case 543: - // Only delete if: option 2 is >= 7 (days); option0 is 5 or 6; option 4 = our clanid - if(atoi(nOptions[2].c_str()) >= 7) - if(atoi(nOptions[0].c_str()) == 5 || atoi(nOptions[0].c_str()) == 6) - if(nClient->GetChar()->GetClan() == atoi(nOptions[4].c_str())) - snprintf(tShortSQL, 1024, "DELETE FROM clanwars WHERE (cw_status = 5 OR cw_status = 6) AND cw_id = %d AND cw_initclan = %d", atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); - - //Console->Print("%s", tShortSQL); - break; - case 548: - // Check clanmembership - if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) - snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_initiator = \"%s\" WHERE cw_id = %d AND cw_initclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - break; - case 549: - // Check clanmembership - if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) - snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_enemy = \"%s\" WHERE cw_id = %d AND cw_enemyclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); - break; - case 555: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 556: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 561: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 577: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 578: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 579: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 580: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 581: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 585: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 590: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 591: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - case 600: // Just ok, skip it - tSuccess = true; - break; - case 601: // Just ok, skip it - tSuccess = true; - break; - case 630: - Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); - break; - default: - Console->Print("%s [Pterminal::HandleUpdateDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID); - return false; - } - -// ------- - if(tLongSQL.str().length() > 0) - { - if(MySQL->GameQuery(tLongSQL.str().c_str())) - { - Console->Print("Cannot update DB. query was: %s", tLongSQL.str().c_str()); - MySQL->ShowGameSQLError(); - tSuccess = false; - } - else - tSuccess = true; - } - else if(strlen(tShortSQL) > 0) - { - if(MySQL->GameQuery(tShortSQL)) - { - Console->Print("Cannot update DB. query was: %s", tShortSQL); - MySQL->ShowGameSQLError(); - tSuccess = false; - } - else - tSuccess = true; - } - - // Notice client about UpdateDB result - char tCmd[100]; - memset(tCmd, '\0', 100); - strncpy(tCmd, nCommandName->c_str(), 100); - - PMessage* tmpMsg = MsgBuilder->BuildTryAccessAnswerMsg(nClient, tCmd, tSuccess); - nClient->SendUDPMessage(tmpMsg); - return true; -} +#include +#include +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +bool PTerminal::HandleUpdateDB(PClient* nClient, uint16_t mTerminalSessionId, std::string *nCommandName, std::string *nOptions, uint8_t nNumOptions, uint16_t nDBID, uint8_t nUnknown) +{ + std::ostringstream tLongSQL; // omg my eyes... Stringstream is one of the worst inventions ever! Stick with printf syntax!!111 + char tShortSQL[1024]; // Use this for small updates that will not exceed 1kb + memset(tShortSQL, '\0', 1024); + bool tSuccess = false; + + //Console->Print("UpdateDB ID: %d", nDBID); + switch (nDBID) + { + case 5: + tLongSQL << "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content)"; + tLongSQL << " VALUES (" << atoi(nOptions[0].c_str()) << ", \"" << nOptions[1] << "\", \"" << nOptions[2] << "\", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")"; + + break; + case 6: + // UPDATE when Neocronicle DB is changed! author must be CHAR not INT + break; + case 7: // Delete neocronicle + snprintf(tShortSQL, 1024, "DELETE FROM neochronicle WHERE nc_id = %d", atoi(nOptions[0].c_str())); + break; + case 12: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 53: // Runner writing to public board + snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str()); + break; + case 58: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 62: // Set new outpost security + snprintf(tShortSQL, 1024, "UPDATE outposts SET o_security = %d WHERE o_outnum = %d AND o_clan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + break; + + case 66: // Claninfo stuff that is somehow never used... Print error if it is + case 67: + Console->Print("%s [Pterminal::HandleUpdateDB] QueryID %d should never happen. Please contact Linux Addited forums!", Console->ColorText(RED,BLACK,"Notice"), nDBID); + break; + + case 77: // Delete old clanlevel + snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cll_clanid = %d AND cll_level = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + break; + case 78: // Add new clanlevel + snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_desc, cll_level) VALUES (%d, \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str())); + break; + case 84: // Take/Give money to/from clan + tLongSQL << "INSERT INTO moneytransactions (mt_clanid, mt_player, mt_amount, mt_date, mt_comment) "; + tLongSQL << "VALUES (" << atoi(nOptions[0].c_str()) << ", " << atoi(nOptions[1].c_str()) << ", " << atoi(nOptions[2].c_str()) << ", \"" << nOptions[3] << "\", \"" << nOptions[4] << "\")"; + break; + case 94: // Update runner description + snprintf(tShortSQL, 1024, "UPDATE characters SET c_desc = \"%s\" WHERE c_id = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str())); + break; + case 97: + // Just ignore that... KK required some extra updates here + tSuccess = true; + //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 120: // Create support call + snprintf(tShortSQL, 1024, "INSERT INTO support (su_player, su_worldid, su_type, su_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str()); + break; + case 121: + snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + break; + case 122: + snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 0, su_supporterid = 0 WHERE su_id = %d AND su_supporterid = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + break; + case 123: + snprintf(tShortSQL, 1024, "UPDATE support SET su_inwork = 1, su_finished = 1, su_supporterid = %d WHERE su_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + break; + case 124: + snprintf(tShortSQL, 1024, "DELETE FROM support WHERE su_id = %d", atoi(nOptions[0].c_str())); + break; + case 133: + tSuccess = true; + //Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 139: + snprintf(tShortSQL, 1024, "UPDATE characters SET c_location = %d WHERE c_id = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str())); + break; + case 142: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 149: // Changeleader 2nd step. Update clanappartment owner + snprintf(tShortSQL, 1024, "UPDATE apartments SET apt_owner = %d WHERE apt_id = %d AND apt_owner = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + break; + case 160: // Missions, not yet + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 161: // Missions, not yet + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 162: // Missions, not yet + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 163: // Missions, not yet + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 164: // Missions, not yet + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 165: // Missions, not yet + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 170: // Enter new bug + snprintf(tShortSQL, 1024, "INSERT INTO bug_report (br_type, br_status, br_title, br_desc, br_location, br_fromid, br_datetime) VALUES (%d, %d, \"%s\", \"%s\", %d, %d, NOW())", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str()), atoi(nOptions[5].c_str())); + break; + case 172: // Delete bug id %d + snprintf(tShortSQL, 1024, "DELETE FROM bug_report WHERE br_id = %d", atoi(nOptions[0].c_str())); + break; + case 180: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 182: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 235: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 252: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 263: // Runner writing to Faction Board + snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str()); + break; + case 268: // Runner writing to ClanBoard + snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_clanid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str()); + break; + case 370: // GM ClanRepair + snprintf(tShortSQL, 1024, "INSERT INTO clanlevels (cll_clanid, cll_level, cll_desc) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str()); + break; + case 385: // Clandelete 1/7 Clanlevels + snprintf(tShortSQL, 1024, "DELETE FROM clanlevels WHERE cl_clanid = %d", atoi(nOptions[0].c_str())); + break; + case 386: // Clandelete 2/7 Outposts + snprintf(tShortSQL, 1024, "UPDATE outposts SET o_clan = 0 WHERE o_clan = %d", atoi(nOptions[0].c_str())); + break; + case 387: // Clandelete 3/7 Free users from clans + snprintf(tShortSQL, 1024, "UPDATE characters SET c_clan = 0 WHERE c_clan = %d", atoi(nOptions[0].c_str())); + break; + case 388: // Clandelete 4/7 The clan itself + snprintf(tShortSQL, 1024, "DELETE FROM clans WHERE cl_id = %d", atoi(nOptions[0].c_str())); + break; + case 389: // Clandelete 5/7 ? + tSuccess = true; + break; + case 390: // Clandelete 6/7 Clanappartment + snprintf(tShortSQL, 1024, "DELETE FROM apartments WHERE apt_id = %d", atoi(nOptions[0].c_str())); + break; + case 391: // Clandelete 7/7 ? + tSuccess = true; + break; + case 402: // GM writing to publicforum + snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str(), nOptions[4].c_str(), nOptions[5].c_str()); + break; + case 404: // GM deleting forum entry step 1 + snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_id = %d", atoi(nOptions[0].c_str())); + break; + case 405: // GM deleting forum entry step 2 + snprintf(tShortSQL, 1024, "DELETE FROM forum_posts WHERE fp_replyid = %d", atoi(nOptions[0].c_str())); + break; + case 412: // GM writing to faction forum + snprintf(tShortSQL, 1024, "INSERT INTO forum_posts (fp_forumid, fp_factionid, fp_replyid, fp_fromid, fp_datetime, fp_name, fp_content) VALUES ((SELECT f_area FROM forums WHERE f_name = \"%s\"), %d, %d, %d, \"%s\", \"%s\", \"%s\")", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), atoi(nOptions[3].c_str()), nOptions[4].c_str(), nOptions[5].c_str(), nOptions[6].c_str()); + break; + case 422: // Mark email as replied + snprintf(tShortSQL, 1024, "UPDATE emails SET e_replied = 1 WHERE e_id = %d", atoi(nOptions[0].c_str())); + break; + case 423: // Write new email + snprintf(tShortSQL, 1024, "INSERT INTO emails (e_fromid,e_toid,e_datetime,e_subject,e_body) VALUES (%d, %d, \"%s\", \"%s\", \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str()); + break; + case 424: // Delete email + snprintf(tShortSQL, 1024, "DELETE FROM emails WHERE e_id = %d", atoi(nOptions[0].c_str())); + break; + case 426: // Mark email as read + snprintf(tShortSQL, 1024, "UPDATE emails SET e_new = 0 WHERE e_id = %d", atoi(nOptions[0].c_str())); + break; + case 432: // Add new contact + snprintf(tShortSQL, 1024, "INSERT INTO contacts (c_listid,c_conid,c_type,c_desc) VALUES (%d, %d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str()), nOptions[3].c_str()); + break; + case 433: // Edit contact + snprintf(tShortSQL, 1024, "UPDATE contacts SET c_type = %d, c_desc = \"%s\" WHERE c_id = %d", atoi(nOptions[0].c_str()), nOptions[1].c_str(), atoi(nOptions[2].c_str())); + break; + case 434: // Delete contact + snprintf(tShortSQL, 1024, "DELETE FROM contacts WHERE c_id = %d", atoi(nOptions[0].c_str())); + break; + case 447: + snprintf(tShortSQL, 1024, "INSERT INTO neochronicle (nc_icon, nc_author, nc_datetime, nc_name, nc_content, nc_lang) VALUES (%d, \"%s\", \"%s\", \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), nOptions[1].c_str(), nOptions[2].c_str(), nOptions[3].c_str(), nOptions[4].c_str(), atoi(nOptions[5].c_str())); + break; + case 450: + snprintf(tShortSQL, 1024, "INSERT INTO guides (g_chapter, g_part, g_title, g_content, g_language) VALUES (%d, %d, \"%s\", \"%s\", %d)", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str(), nOptions[3].c_str(), atoi(nOptions[4].c_str())); + break; + case 515: // Create new clanwar + snprintf(tShortSQL, 1024, "INSERT INTO clanwars (cw_initclan, cw_enemyclan, cw_starttime) VALUES (%d, %d, \"%s\")", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), nOptions[2].c_str()); + break; + case 516: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 517: + // Special: Check if Clan of our char is = nOption2 + if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) + snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_initclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + // else: SQL Query is empty = failed as result + break; + case 518: + if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) + snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_status = %d WHERE cw_id = %d AND cw_enemyclan = %d", atoi(nOptions[0].c_str()), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + // else: SQL Query is empty = failed as result + break; + case 519: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 525: // Update clan short + tLongSQL << "UPDATE clans SET cl_shortdesc = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); + + break; + case 526: // Update clan name + tLongSQL << "UPDATE clans SET cl_name = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); + + break; + case 527: // Update clanapp password + //UPDATE apartments SET apt_password = x WHERE apt_owner = x AND apt_id = (SELECT clans.cl_appid WHERE clans.cl_id = x) + tLongSQL << "UPDATE apartments SET apt_password = \"" << nOptions[0] << "\" WHERE apt_owner = " << atoi(nOptions[2].c_str()) << " AND apt_id = (SELECT cl_appid FROM clans WHERE cl_id = " << atoi(nOptions[1].c_str()) << ")"; + break; + case 528: + tLongSQL << "UPDATE clans SET cl_minsympathy = " << atoi(nOptions[0].c_str()) << " WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); + break; + case 529: + tLongSQL << "UPDATE clans SET cl_description = \"" << nOptions[0] << "\" WHERE cl_id = " << atoi(nOptions[1].c_str()) << " AND cl_leader = " << atoi(nOptions[2].c_str()); + break; + case 543: + // Only delete if: option 2 is >= 7 (days); option0 is 5 or 6; option 4 = our clanid + if(atoi(nOptions[2].c_str()) >= 7) + if(atoi(nOptions[0].c_str()) == 5 || atoi(nOptions[0].c_str()) == 6) + if(nClient->GetChar()->GetClan() == atoi(nOptions[4].c_str())) + snprintf(tShortSQL, 1024, "DELETE FROM clanwars WHERE (cw_status = 5 OR cw_status = 6) AND cw_id = %d AND cw_initclan = %d", atoi(nOptions[3].c_str()), atoi(nOptions[4].c_str())); + + //Console->Print("%s", tShortSQL); + break; + case 548: + // Check clanmembership + if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) + snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_initiator = \"%s\" WHERE cw_id = %d AND cw_initclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + break; + case 549: + // Check clanmembership + if(nClient->GetChar()->GetClan() == atoi(nOptions[2].c_str())) + snprintf(tShortSQL, 1024, "UPDATE clanwars SET cw_statement_enemy = \"%s\" WHERE cw_id = %d AND cw_enemyclan = %d", nOptions[0].c_str(), atoi(nOptions[1].c_str()), atoi(nOptions[2].c_str())); + break; + case 555: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 556: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 561: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 577: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 578: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 579: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 580: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 581: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 585: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 590: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 591: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + case 600: // Just ok, skip it + tSuccess = true; + break; + case 601: // Just ok, skip it + tSuccess = true; + break; + case 630: + Console->Print("%s [Pterminal::HandleUpdateDB] Nothing to do; Function not written yet for QueryID %d", Console->ColorText(YELLOW,BLACK,"Notice"), nDBID); + break; + default: + Console->Print("%s [Pterminal::HandleUpdateDB] Unknown QueryID %d", Console->ColorText(RED,BLACK,"Warning"), nDBID); + return false; + } + +// ------- + if(tLongSQL.str().length() > 0) + { + if(MySQL->GameQuery(tLongSQL.str().c_str())) + { + Console->Print("Cannot update DB. query was: %s", tLongSQL.str().c_str()); + MySQL->ShowGameSQLError(); + tSuccess = false; + } + else + tSuccess = true; + } + else if(strlen(tShortSQL) > 0) + { + if(MySQL->GameQuery(tShortSQL)) + { + Console->Print("Cannot update DB. query was: %s", tShortSQL); + MySQL->ShowGameSQLError(); + tSuccess = false; + } + else + tSuccess = true; + } + + // Notice client about UpdateDB result + char tCmd[100]; + memset(tCmd, '\0', 100); + strncpy(tCmd, nCommandName->c_str(), 100); + + PMessage* tmpMsg = MsgBuilder->BuildTryAccessAnswerMsg(nClient, tCmd, tSuccess); + nClient->SendUDPMessage(tmpMsg); + return true; +} diff --git a/TinNS/Source/GameServer/Vehicle.cxx b/TinNS/Source/GameServer/Vehicle.cxx index 33276b4..48d30b4 100644 --- a/TinNS/Source/GameServer/Vehicle.cxx +++ b/TinNS/Source/GameServer/Vehicle.cxx @@ -1,497 +1,497 @@ -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -// PVhcCoordinates -void PVhcCoordinates::SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef ) -{ - if (( nCoef < 0 ) || ( nCoef > 1 ) ) - { - Console->Print( RED, BLACK, "[Error] PVhcCoordinates::Interpolate : Invalid nCoef value: %f", nCoef ); - nCoef = 0; - } - float rCoef = 1 - nCoef; - - mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY ); - mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ ); - mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX ); - mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD ); - mLR = ( uint16_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR ); - mRoll = ( uint16_t )( rCoef * Pos1.mRoll + nCoef * Pos2.mRoll ); -} - -void PVhcCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct, uint16_t nUnknown, uint8_t nFF ) -{ - mY = nY; - mZ = nZ; - mX = nX; - mUD = nUD; - mLR = nLR; - mRoll = nRoll; - mAct = nAct; - mUnknown = nUnknown; - mFF = nFF; -} - -// PVehicleInformation -//Tmp -const uint8_t VhcTypes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 50, 60, 62, 64, 65, 70 - }; // (adv.) assault gliders discarded because not ok -#define VHC_DISABLE_NOVULARI -#ifndef VHC_DISABLE_NOVULARI -const uint8_t VhcTypesNum = 19; -#else -const uint8_t VhcTypesNum = 18; -#endif - -bool PVehicleInformation::Load( uint32_t nVehicleId ) -{ - uint8_t i; - uint8_t nVId = nVehicleId % 100; //Tmp - for ( i = 0; ( i < VhcTypesNum ) && ( VhcTypes[i] < nVId ); i++ ) ; //Tmp - if (( i < VhcTypesNum ) && ( VhcTypes[i] == nVId ) ) //Tmp - { - mVehicleId = nVehicleId; - mOwnerCharId = nVehicleId / 100; // tmp - mHealth = 200; // Tmp - mVehicleType = nVId; // tmp - mStatus = 0; - return true; - } - else - return false; -} - -bool PVehicleInformation::Save() -{ - // Shall we Destroy() when mStatus == 2, or keep destroyed vhc in DB ? - return true; -} - -bool PVehicleInformation::Destroy() -{ - if ( mStatus == 2 ) - { - // Delete from DB - mVehicleId = 0; - return true; - } - else - return false; -} - -bool PVehicleInformation::SetStatus( uint8_t nStatus ) -{ - if (( mStatus != 2 ) && ( nStatus <= 2 ) ) - { - mStatus = nStatus; - return true; - } - else - return false; -} - -// PSpawnedVehicule -const uint8_t PSpawnedVehicle::mSeatsFlags[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; - -PSpawnedVehicle::PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos ) -{ - mLocalId = nLocalId; - mInfo = *nVhcInfo; - mLocation = nLocation; - mCoords = *nVhcPos; - for ( int i = 0; i < 8; ++i ) - mSeatUserId[i] = 0; - - mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType ); - if ( ! mVhcDef ) - { - Console->Print( RED, BLACK, "[ERROR] Invalid vhc type %d for vhc id %d (local %d) owner char id %d", mInfo.mVehicleType, mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId ); - Console->Print( RED, BLACK, "[NOTICE] Setting vhc type to %d for vhc id %d (local %d) owner char id %d", VhcTypes[0], mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId ); - mInfo.mVehicleType = VhcTypes[0]; - mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType ); - } - - mNbFreeSeats = GetNumSeats(); - if ( mNbFreeSeats > 8 ) - { - Console->Print( RED, BLACK, "[ERROR] Vhc type %d has more than 8 seats (%d)", mInfo.mVehicleType, mNbFreeSeats ); - mNbFreeSeats = 8; - } - for ( int i = 0; i < mNbFreeSeats; ++i ) - mFreeSeatsFlags |= mSeatsFlags[i]; - - //Temp - for ( int i = 0; i < 4; ++i ) - { - minmax[i][0] = 0xffff; - minmax[i][1] = 0; - } -} - -void PSpawnedVehicle::SetLocation( uint32_t nLocation ) -{ - mLocation = nLocation; -} - -void PSpawnedVehicle::SetPosition( PVhcCoordinates const* nVhcPos ) -{ - mCoords = *nVhcPos; - // Temp - if(gDevDebug) - { - if ( mCoords.mUD < minmax[0][0] ) minmax[0][0] = mCoords.mUD; - if ( mCoords.mUD > minmax[0][1] ) minmax[0][1] = mCoords.mUD; - if ( mCoords.mLR < minmax[1][0] ) minmax[1][0] = mCoords.mLR; - if ( mCoords.mLR > minmax[1][1] ) minmax[1][1] = mCoords.mLR; - if ( mCoords.mRoll < minmax[2][0] ) minmax[2][0] = mCoords.mRoll; - if ( mCoords.mRoll > minmax[2][1] ) minmax[2][1] = mCoords.mRoll; - Console->Print( "%s Min/Max: UD:%d/%d(%d) LR:%d/%d(%d) Roll:%d/%d(%d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), minmax[0][0], minmax[0][1], mCoords.mUD, minmax[1][0], minmax[1][1], mCoords.mLR, minmax[2][0], minmax[2][1], mCoords.mRoll ); - } -} - -int PSpawnedVehicle::GetNumSeats() const -{ - return mVhcDef->GetNumSeats(); -} - -bool PSpawnedVehicle::SetSeatUser( uint8_t nSeatId, uint32_t nCharId ) -{ - if ( nSeatId < mVhcDef->GetNumSeats() ) - { - if ( ! mSeatUserId[nSeatId] ) - { - mSeatUserId[nSeatId] = nCharId; - mFreeSeatsFlags &= ~mSeatsFlags[nSeatId]; - --mNbFreeSeats; - return true; - } - } - return false; -} - -bool PSpawnedVehicle::UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId ) -{ - if ( nSeatId < mVhcDef->GetNumSeats() ) - { - if ( mSeatUserId[nSeatId] == nCharId ) - { - mSeatUserId[nSeatId] = 0; - mFreeSeatsFlags |= mSeatsFlags[nSeatId]; - ++mNbFreeSeats; - return true; - } - } - return false; -} - -bool PSpawnedVehicle::IsCharInside( uint32_t nCharId ) const -{ - for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i ) - { - if ( mSeatUserId[i] == nCharId ) - return true; - } - return false; -} - -uint8_t PSpawnedVehicle::GetFirstFreeSeat() const -{ - for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i ) - { - if ( ! mSeatUserId[i] ) - return i; - } - - return 255; -} -/*uint8_t PSpawnedVehicle::GetFreeSeats() const -{ - uint8_t bitField = 0; - - for(int i = mVhcDef->GetNumSeats() - 1; i >= 0 ; --i) - { - bitField <<= 1; - if ( ! mSeatUserId[i] ) - bitField |= 1; - } - - return bitField; -}*/ - -// PVehicles -PVehicles::PVehicles() -{ - -} - -PVehicles::~PVehicles() -{ - -} - -bool PVehicles::RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle ) -{ - std::pair Result = mSpawnedVehicles.insert( std::make_pair( nSpawnedVehicle->GetVehicleId(), nSpawnedVehicle ) ); - return Result.second; -} - -bool PVehicles::UnregisterSpawnedVehicle( uint32_t nVehicleId ) -{ - PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId ); - if ( it != mSpawnedVehicles.end() ) - { - mSpawnedVehicles.erase( it ); - return true; - } - else - { - return false; - } -} - -//uint32_t PVehicles::CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType) {} -//bool PVehicles::RegisterVehicleOwner(uint32_t nVehicleId, uint32_t nOwnerChar) {} -//bool PVehicles::DestroyVehicle(uint32_t nVehicleId) {} - -bool PVehicles::IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner, uint32_t nOwnerId ) const -{ - // Look in DB - // tmp - uint32_t tVehicleId = nVehicleId; - bool tCheckOwner = nCheckOwner; - uint32_t tOwnerId = nOwnerId; - return true; // tmp -} - -PSpawnedVehicle* PVehicles::GetSpawnedVehicle( uint32_t nVehicleId ) const -{ - PSpawnedVhcMap::const_iterator it = mSpawnedVehicles.find( nVehicleId ); - if ( it != mSpawnedVehicles.end() ) - { - return ( it->second ); - } - else - { - return NULL; - } -} - -bool PVehicles::GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const -{ - PSpawnedVehicle* tVhc = GetSpawnedVehicle( nVehicleId ); - if ( tVhc ) - { - *nInfo = tVhc->GetInformation(); - return true; - } - else - { - return nInfo->Load( nVehicleId ); - } -} - -PVhcInfoList* PVehicles::GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount, uint16_t nStartIndex ) -{ - PVhcInfoList* Entries = new PVhcInfoList(); - PVehicleInformation* InfoEntry; - // Tmp implementation - uint16_t LimitIndex = nStartIndex + nMaxCount; - if ( !nMaxCount || ( VhcTypesNum < LimitIndex ) ) - { - LimitIndex = VhcTypesNum; - } - - for ( uint16_t i = nStartIndex; ( i < LimitIndex ) ; ++i ) - { - InfoEntry = new PVehicleInformation(); - if ( GetVehicleInfo( nCharId * 100 + VhcTypes[i], InfoEntry ) ) - { - Entries->push( InfoEntry ); - } - else - { - delete InfoEntry; - } - } - - return Entries; -} - -PSpawnedVehicle* PVehicles::SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos ) -{ - PSpawnedVehicle* newVhc = NULL; - PWorld* cWorld; - PVehicleInformation nVhcInfo; - - if (( nLocation != PWorlds::mNcSubwayWorldId ) && IsValidVehicle( nVehicleId ) && !IsSpawned( nVehicleId ) ) - { - cWorld = Worlds->LeaseWorld( nLocation ); - - if ( cWorld && GetVehicleInfo( nVehicleId, &nVhcInfo ) ) - { - newVhc = cWorld->GetSpawnedVehicles()->SpawnVehicle( &nVhcInfo, nVhcPos ); - if ( newVhc ) - { - if ( !RegisterSpawnedVehicle( newVhc ) ) - { - Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not register spawned vhc" ); - } - if( gDevDebug ) - Console->Print( "%d Spawned vhc %d (local 0x%04x) type %d (requested: %d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), newVhc->GetVehicleId(), newVhc->GetLocalId(), newVhc->GetInformation().GetVehicleType(), nVhcInfo.GetVehicleType() ); - } - else - Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not create vhc" ); - } - - Worlds->ReleaseWorld( nLocation ); - } - - return newVhc; -} - -bool PVehicles::UnspawnVehicle( uint32_t nVehicleId ) -{ - PWorld* cWorld; - bool Result = false; - - PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId ); - if ( it != mSpawnedVehicles.end() ) - { - cWorld = Worlds->LeaseWorld( it->second->GetLocation() ); - - if ( cWorld ) - { - if ( !it->second->Save() ) - { - Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not save vhc %d", nVehicleId ); - } - - Result = cWorld->GetSpawnedVehicles()->UnspawnVehicle( it->second->GetLocalId() ); - if ( Result ) - { - if ( !UnregisterSpawnedVehicle( nVehicleId ) ) - { - Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not unregister vhc %d", nVehicleId ); - } - } - } - - Worlds->ReleaseWorld( it->second->GetLocation() ); - } - - return Result; -} - -//PSpawnedVehicles -PSpawnedVehicles::PSpawnedVehicles() -{ - mNextFreeHint = 0; - mLocation = 0; -} - -PSpawnedVehicles::~PSpawnedVehicles() -{ - -} - -PSpawnedVehicle* PSpawnedVehicles::SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos ) -{ - PSpawnedVehicle* newVhc = NULL; - uint32_t nSize; - - if ( nVhcInfo->GetStatus() == 0 ) // only if in garage - { - nSize = mSpawnedVehicles.size(); - while (( mNextFreeHint < nSize ) && mSpawnedVehicles[mNextFreeHint] ) - { - ++mNextFreeHint; - } - if ( mNextFreeHint > nSize ) - { - mNextFreeHint = nSize; - } - if ( mNextFreeHint == nSize ) - { - mSpawnedVehicles.push_back( static_cast(NULL) ); - } - - if ( mNextFreeHint < mMaxLocalVhc ) - { - newVhc = new PSpawnedVehicle( mVhcBaseLocalId - mNextFreeHint, nVhcInfo, mLocation, nVhcPos ); - mSpawnedVehicles[mNextFreeHint++] = newVhc; - newVhc->SetStatus( 1 ); - } - } - - return newVhc; -} - -PSpawnedVehicle* PSpawnedVehicles::GetVehicle( uint32_t nLocalId ) -{ - if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) ) - { - return mSpawnedVehicles[mVhcBaseLocalId - nLocalId]; - } - else - { - return NULL; - } -} - -PSpawnedVehicle* PSpawnedVehicles::GetVehicleByGlobalId( uint32_t nVehicleId ) const -{ - for ( PSpawnedVhcVector::const_iterator it = mSpawnedVehicles.begin(); it != mSpawnedVehicles.end(); it++ ) - { - if (( *it )->GetVehicleId() == nVehicleId ) - { - return ( *it ); - } - } - - return NULL; -} - -bool PSpawnedVehicles::UnspawnVehicle( uint32_t nLocalId ) -{ - uint16_t Index; - PSpawnedVehicle* tVhc; - - if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) ) - { - Index = mVhcBaseLocalId - nLocalId; - tVhc = mSpawnedVehicles[Index]; - if ( tVhc ) - { - if ( tVhc->GetInformation().GetStatus() != 2 ) - { - tVhc->SetStatus( 0 ); - } - delete tVhc; - mSpawnedVehicles[Index] = NULL; - if ( mNextFreeHint > Index ) - { - mNextFreeHint = Index; - } - return true; - } - } - - return false; -} - -PSpawnedVhcList* PSpawnedVehicles::GetSpawnedVehicles() const -{ - PSpawnedVhcList* Entries = new PSpawnedVhcList(); - - for ( PSpawnedVhcVector::const_iterator i = mSpawnedVehicles.begin(); i != mSpawnedVehicles.end(); ++i ) - { - if ( *i ) - { - Entries->push( *i ); - } - } - - return Entries; -} +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +// PVhcCoordinates +void PVhcCoordinates::SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef ) +{ + if (( nCoef < 0 ) || ( nCoef > 1 ) ) + { + Console->Print( RED, BLACK, "[Error] PVhcCoordinates::Interpolate : Invalid nCoef value: %f", nCoef ); + nCoef = 0; + } + float rCoef = 1 - nCoef; + + mY = ( uint16_t )( rCoef * Pos1.mY + nCoef * Pos2.mY ); + mZ = ( uint16_t )( rCoef * Pos1.mZ + nCoef * Pos2.mZ ); + mX = ( uint16_t )( rCoef * Pos1.mX + nCoef * Pos2.mX ); + mUD = ( uint8_t )( rCoef * Pos1.mUD + nCoef * Pos2.mUD ); + mLR = ( uint16_t )( rCoef * Pos1.mLR + nCoef * Pos2.mLR ); + mRoll = ( uint16_t )( rCoef * Pos1.mRoll + nCoef * Pos2.mRoll ); +} + +void PVhcCoordinates::SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct, uint16_t nUnknown, uint8_t nFF ) +{ + mY = nY; + mZ = nZ; + mX = nX; + mUD = nUD; + mLR = nLR; + mRoll = nRoll; + mAct = nAct; + mUnknown = nUnknown; + mFF = nFF; +} + +// PVehicleInformation +//Tmp +const uint8_t VhcTypes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 50, 60, 62, 64, 65, 70 + }; // (adv.) assault gliders discarded because not ok +#define VHC_DISABLE_NOVULARI +#ifndef VHC_DISABLE_NOVULARI +const uint8_t VhcTypesNum = 19; +#else +const uint8_t VhcTypesNum = 18; +#endif + +bool PVehicleInformation::Load( uint32_t nVehicleId ) +{ + uint8_t i; + uint8_t nVId = nVehicleId % 100; //Tmp + for ( i = 0; ( i < VhcTypesNum ) && ( VhcTypes[i] < nVId ); i++ ) ; //Tmp + if (( i < VhcTypesNum ) && ( VhcTypes[i] == nVId ) ) //Tmp + { + mVehicleId = nVehicleId; + mOwnerCharId = nVehicleId / 100; // tmp + mHealth = 200; // Tmp + mVehicleType = nVId; // tmp + mStatus = 0; + return true; + } + else + return false; +} + +bool PVehicleInformation::Save() +{ + // Shall we Destroy() when mStatus == 2, or keep destroyed vhc in DB ? + return true; +} + +bool PVehicleInformation::Destroy() +{ + if ( mStatus == 2 ) + { + // Delete from DB + mVehicleId = 0; + return true; + } + else + return false; +} + +bool PVehicleInformation::SetStatus( uint8_t nStatus ) +{ + if (( mStatus != 2 ) && ( nStatus <= 2 ) ) + { + mStatus = nStatus; + return true; + } + else + return false; +} + +// PSpawnedVehicule +const uint8_t PSpawnedVehicle::mSeatsFlags[] = { 1, 2, 4, 8, 16, 32, 64, 128 }; + +PSpawnedVehicle::PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos ) +{ + mLocalId = nLocalId; + mInfo = *nVhcInfo; + mLocation = nLocation; + mCoords = *nVhcPos; + for ( int i = 0; i < 8; ++i ) + mSeatUserId[i] = 0; + + mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType ); + if ( ! mVhcDef ) + { + Console->Print( RED, BLACK, "[ERROR] Invalid vhc type %d for vhc id %d (local %d) owner char id %d", mInfo.mVehicleType, mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId ); + Console->Print( RED, BLACK, "[NOTICE] Setting vhc type to %d for vhc id %d (local %d) owner char id %d", VhcTypes[0], mInfo.mVehicleId, mLocalId, mInfo.mOwnerCharId ); + mInfo.mVehicleType = VhcTypes[0]; + mVhcDef = GameDefs->Vhcs()->GetDef( mInfo.mVehicleType ); + } + + mNbFreeSeats = GetNumSeats(); + if ( mNbFreeSeats > 8 ) + { + Console->Print( RED, BLACK, "[ERROR] Vhc type %d has more than 8 seats (%d)", mInfo.mVehicleType, mNbFreeSeats ); + mNbFreeSeats = 8; + } + for ( int i = 0; i < mNbFreeSeats; ++i ) + mFreeSeatsFlags |= mSeatsFlags[i]; + + //Temp + for ( int i = 0; i < 4; ++i ) + { + minmax[i][0] = 0xffff; + minmax[i][1] = 0; + } +} + +void PSpawnedVehicle::SetLocation( uint32_t nLocation ) +{ + mLocation = nLocation; +} + +void PSpawnedVehicle::SetPosition( PVhcCoordinates const* nVhcPos ) +{ + mCoords = *nVhcPos; + // Temp + if(gDevDebug) + { + if ( mCoords.mUD < minmax[0][0] ) minmax[0][0] = mCoords.mUD; + if ( mCoords.mUD > minmax[0][1] ) minmax[0][1] = mCoords.mUD; + if ( mCoords.mLR < minmax[1][0] ) minmax[1][0] = mCoords.mLR; + if ( mCoords.mLR > minmax[1][1] ) minmax[1][1] = mCoords.mLR; + if ( mCoords.mRoll < minmax[2][0] ) minmax[2][0] = mCoords.mRoll; + if ( mCoords.mRoll > minmax[2][1] ) minmax[2][1] = mCoords.mRoll; + Console->Print( "%s Min/Max: UD:%d/%d(%d) LR:%d/%d(%d) Roll:%d/%d(%d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), minmax[0][0], minmax[0][1], mCoords.mUD, minmax[1][0], minmax[1][1], mCoords.mLR, minmax[2][0], minmax[2][1], mCoords.mRoll ); + } +} + +int PSpawnedVehicle::GetNumSeats() const +{ + return mVhcDef->GetNumSeats(); +} + +bool PSpawnedVehicle::SetSeatUser( uint8_t nSeatId, uint32_t nCharId ) +{ + if ( nSeatId < mVhcDef->GetNumSeats() ) + { + if ( ! mSeatUserId[nSeatId] ) + { + mSeatUserId[nSeatId] = nCharId; + mFreeSeatsFlags &= ~mSeatsFlags[nSeatId]; + --mNbFreeSeats; + return true; + } + } + return false; +} + +bool PSpawnedVehicle::UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId ) +{ + if ( nSeatId < mVhcDef->GetNumSeats() ) + { + if ( mSeatUserId[nSeatId] == nCharId ) + { + mSeatUserId[nSeatId] = 0; + mFreeSeatsFlags |= mSeatsFlags[nSeatId]; + ++mNbFreeSeats; + return true; + } + } + return false; +} + +bool PSpawnedVehicle::IsCharInside( uint32_t nCharId ) const +{ + for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i ) + { + if ( mSeatUserId[i] == nCharId ) + return true; + } + return false; +} + +uint8_t PSpawnedVehicle::GetFirstFreeSeat() const +{ + for ( int i = 0; i < mVhcDef->GetNumSeats(); ++i ) + { + if ( ! mSeatUserId[i] ) + return i; + } + + return 255; +} +/*uint8_t PSpawnedVehicle::GetFreeSeats() const +{ + uint8_t bitField = 0; + + for(int i = mVhcDef->GetNumSeats() - 1; i >= 0 ; --i) + { + bitField <<= 1; + if ( ! mSeatUserId[i] ) + bitField |= 1; + } + + return bitField; +}*/ + +// PVehicles +PVehicles::PVehicles() +{ + +} + +PVehicles::~PVehicles() +{ + +} + +bool PVehicles::RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle ) +{ + std::pair Result = mSpawnedVehicles.insert( std::make_pair( nSpawnedVehicle->GetVehicleId(), nSpawnedVehicle ) ); + return Result.second; +} + +bool PVehicles::UnregisterSpawnedVehicle( uint32_t nVehicleId ) +{ + PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId ); + if ( it != mSpawnedVehicles.end() ) + { + mSpawnedVehicles.erase( it ); + return true; + } + else + { + return false; + } +} + +//uint32_t PVehicles::CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType) {} +//bool PVehicles::RegisterVehicleOwner(uint32_t nVehicleId, uint32_t nOwnerChar) {} +//bool PVehicles::DestroyVehicle(uint32_t nVehicleId) {} + +bool PVehicles::IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner, uint32_t nOwnerId ) const +{ + // Look in DB + // tmp + uint32_t tVehicleId = nVehicleId; + bool tCheckOwner = nCheckOwner; + uint32_t tOwnerId = nOwnerId; + return true; // tmp +} + +PSpawnedVehicle* PVehicles::GetSpawnedVehicle( uint32_t nVehicleId ) const +{ + PSpawnedVhcMap::const_iterator it = mSpawnedVehicles.find( nVehicleId ); + if ( it != mSpawnedVehicles.end() ) + { + return ( it->second ); + } + else + { + return NULL; + } +} + +bool PVehicles::GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const +{ + PSpawnedVehicle* tVhc = GetSpawnedVehicle( nVehicleId ); + if ( tVhc ) + { + *nInfo = tVhc->GetInformation(); + return true; + } + else + { + return nInfo->Load( nVehicleId ); + } +} + +PVhcInfoList* PVehicles::GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount, uint16_t nStartIndex ) +{ + PVhcInfoList* Entries = new PVhcInfoList(); + PVehicleInformation* InfoEntry; + // Tmp implementation + uint16_t LimitIndex = nStartIndex + nMaxCount; + if ( !nMaxCount || ( VhcTypesNum < LimitIndex ) ) + { + LimitIndex = VhcTypesNum; + } + + for ( uint16_t i = nStartIndex; ( i < LimitIndex ) ; ++i ) + { + InfoEntry = new PVehicleInformation(); + if ( GetVehicleInfo( nCharId * 100 + VhcTypes[i], InfoEntry ) ) + { + Entries->push( InfoEntry ); + } + else + { + delete InfoEntry; + } + } + + return Entries; +} + +PSpawnedVehicle* PVehicles::SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos ) +{ + PSpawnedVehicle* newVhc = NULL; + PWorld* cWorld; + PVehicleInformation nVhcInfo; + + if (( nLocation != PWorlds::mNcSubwayWorldId ) && IsValidVehicle( nVehicleId ) && !IsSpawned( nVehicleId ) ) + { + cWorld = Worlds->LeaseWorld( nLocation ); + + if ( cWorld && GetVehicleInfo( nVehicleId, &nVhcInfo ) ) + { + newVhc = cWorld->GetSpawnedVehicles()->SpawnVehicle( &nVhcInfo, nVhcPos ); + if ( newVhc ) + { + if ( !RegisterSpawnedVehicle( newVhc ) ) + { + Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not register spawned vhc" ); + } + if( gDevDebug ) + Console->Print( "%d Spawned vhc %d (local 0x%04x) type %d (requested: %d)", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), newVhc->GetVehicleId(), newVhc->GetLocalId(), newVhc->GetInformation().GetVehicleType(), nVhcInfo.GetVehicleType() ); + } + else + Console->Print( RED, BLACK, "[Error] PVehicles::SpawnVehicle : Could not create vhc" ); + } + + Worlds->ReleaseWorld( nLocation ); + } + + return newVhc; +} + +bool PVehicles::UnspawnVehicle( uint32_t nVehicleId ) +{ + PWorld* cWorld; + bool Result = false; + + PSpawnedVhcMap::iterator it = mSpawnedVehicles.find( nVehicleId ); + if ( it != mSpawnedVehicles.end() ) + { + cWorld = Worlds->LeaseWorld( it->second->GetLocation() ); + + if ( cWorld ) + { + if ( !it->second->Save() ) + { + Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not save vhc %d", nVehicleId ); + } + + Result = cWorld->GetSpawnedVehicles()->UnspawnVehicle( it->second->GetLocalId() ); + if ( Result ) + { + if ( !UnregisterSpawnedVehicle( nVehicleId ) ) + { + Console->Print( RED, BLACK, "[Error] PVehicles::UnspawnVehicle : Could not unregister vhc %d", nVehicleId ); + } + } + } + + Worlds->ReleaseWorld( it->second->GetLocation() ); + } + + return Result; +} + +//PSpawnedVehicles +PSpawnedVehicles::PSpawnedVehicles() +{ + mNextFreeHint = 0; + mLocation = 0; +} + +PSpawnedVehicles::~PSpawnedVehicles() +{ + +} + +PSpawnedVehicle* PSpawnedVehicles::SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos ) +{ + PSpawnedVehicle* newVhc = NULL; + uint32_t nSize; + + if ( nVhcInfo->GetStatus() == 0 ) // only if in garage + { + nSize = mSpawnedVehicles.size(); + while (( mNextFreeHint < nSize ) && mSpawnedVehicles[mNextFreeHint] ) + { + ++mNextFreeHint; + } + if ( mNextFreeHint > nSize ) + { + mNextFreeHint = nSize; + } + if ( mNextFreeHint == nSize ) + { + mSpawnedVehicles.push_back( static_cast(NULL) ); + } + + if ( mNextFreeHint < mMaxLocalVhc ) + { + newVhc = new PSpawnedVehicle( mVhcBaseLocalId - mNextFreeHint, nVhcInfo, mLocation, nVhcPos ); + mSpawnedVehicles[mNextFreeHint++] = newVhc; + newVhc->SetStatus( 1 ); + } + } + + return newVhc; +} + +PSpawnedVehicle* PSpawnedVehicles::GetVehicle( uint32_t nLocalId ) +{ + if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) ) + { + return mSpawnedVehicles[mVhcBaseLocalId - nLocalId]; + } + else + { + return NULL; + } +} + +PSpawnedVehicle* PSpawnedVehicles::GetVehicleByGlobalId( uint32_t nVehicleId ) const +{ + for ( PSpawnedVhcVector::const_iterator it = mSpawnedVehicles.begin(); it != mSpawnedVehicles.end(); it++ ) + { + if (( *it )->GetVehicleId() == nVehicleId ) + { + return ( *it ); + } + } + + return NULL; +} + +bool PSpawnedVehicles::UnspawnVehicle( uint32_t nLocalId ) +{ + uint16_t Index; + PSpawnedVehicle* tVhc; + + if (( nLocalId <= mVhcBaseLocalId ) && ( nLocalId > ( mVhcBaseLocalId - mSpawnedVehicles.size() ) ) ) + { + Index = mVhcBaseLocalId - nLocalId; + tVhc = mSpawnedVehicles[Index]; + if ( tVhc ) + { + if ( tVhc->GetInformation().GetStatus() != 2 ) + { + tVhc->SetStatus( 0 ); + } + delete tVhc; + mSpawnedVehicles[Index] = NULL; + if ( mNextFreeHint > Index ) + { + mNextFreeHint = Index; + } + return true; + } + } + + return false; +} + +PSpawnedVhcList* PSpawnedVehicles::GetSpawnedVehicles() const +{ + PSpawnedVhcList* Entries = new PSpawnedVhcList(); + + for ( PSpawnedVhcVector::const_iterator i = mSpawnedVehicles.begin(); i != mSpawnedVehicles.end(); ++i ) + { + if ( *i ) + { + Entries->push( *i ); + } + } + + return Entries; +} diff --git a/TinNS/Source/GameServer/Vehicle.hxx b/TinNS/Source/GameServer/Vehicle.hxx index d7c407b..a1e901f 100644 --- a/TinNS/Source/GameServer/Vehicle.hxx +++ b/TinNS/Source/GameServer/Vehicle.hxx @@ -1,188 +1,188 @@ -#pragma once - -#include -#include -#include -#include - -class PDefVhc; - -class PVhcCoordinates { - friend class PSpawnedVehicle; - - private: - uint16_t mY; // Y-Position in world - uint16_t mZ; // Z-Position in world - uint16_t mX; // X-Position in world - uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) // Pitch - uint16_t mLR; // Yaw - uint16_t mRoll; - uint16_t mUnknown; // Usually 0x0001 - uint8_t mFF; // Usually 0xff ... - uint8_t mAct; // Last user action state - // mAct: bit field - //0x00 = not moving - //0x01 = Left - //0x02 = Right - //0x04 = Forward - //0x08 = Back - //0x20 = Pushing down - //0x40 = Pulling up - - public: - inline PVhcCoordinates() { mX = mY = mZ = mAct = 0; mUD = 128; mLR = 34683; mRoll = 32403;} - - void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct = 0, uint16_t nUnknown = 1, uint8_t nFF = 0xff ); - void SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef ); - inline uint16_t GetX() const { return mX; } - inline uint16_t GetY() const { return mY; } - inline uint16_t GetZ() const { return mZ; } - inline uint8_t GetUD() const { return mUD; } - inline uint16_t GetLR() const { return mLR; } - inline uint16_t GetRoll() const { return mRoll; } - inline uint8_t GetAct() const { return mAct; } - inline uint8_t GetUnknown() const { return mUnknown; } - inline uint8_t GetFF() const { return mFF; } -}; - -class PVehicleInformation -{ - friend class PSpawnedVehicle; - friend class PVehicles; - - private: - uint32_t mVehicleId; - uint32_t mOwnerCharId; - uint32_t mHealth; // or float ??? - uint8_t mVehicleType; - uint8_t mStatus; //vhcStatus 0:parking, 1:in_service, 2:destroyed - - public: - inline PVehicleInformation( uint32_t nVehicleId = 0, uint32_t nOwnerCharId = 0, uint32_t nHealth = 0, uint8_t nVehicleType = 0, uint8_t nStatus = 0 ) : - mVehicleId( nVehicleId ), - mOwnerCharId( nOwnerCharId ), - mHealth( nHealth ), - mVehicleType( nVehicleType ), - mStatus( nStatus ) - { } - - inline uint32_t GetVehicleId() const { return mVehicleId; } - inline uint32_t GetOwnerCharId() const { return mOwnerCharId; } - inline uint32_t GetHealth() const { return mHealth; } // or float ??? - inline uint8_t GetVehicleType() const { return mVehicleType; } - inline uint8_t GetStatus() const { return mStatus; } - bool SetStatus( uint8_t nStatus ); - - bool Load( uint32_t nVehicleId ); - bool Save(); - bool Destroy(); -}; - -class PSpawnedVehicle -{ - private: - static const uint8_t mSeatsFlags[]; - - private: - uint32_t mLocalId; - PVehicleInformation mInfo; - uint32_t mLocation; - PVhcCoordinates mCoords; - const PDefVhc* mVhcDef; - - uint32_t mSeatUserId[8]; - uint8_t mFreeSeatsFlags; - uint8_t mNbFreeSeats; - - uint16_t minmax[4][2]; //Temp - - public: - PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos ); - - inline uint32_t GetVehicleId() const { return mInfo.mVehicleId; } - inline uint32_t GetLocalId() const { return mLocalId; } - inline const PVhcCoordinates& GetPosition() const { return mCoords; } - inline const PVehicleInformation& GetInformation() const { return mInfo; } - inline bool SetStatus( uint8_t nStatus ) { return mInfo.SetStatus( nStatus ); } - - void SetLocation( uint32_t nLocation ); - inline uint32_t GetLocation() const { return mLocation; } - void SetPosition( PVhcCoordinates const* nVhcPos ); - - inline bool Save() { return mInfo.Save(); } - - int GetNumSeats() const; - inline uint32_t GetSeatUser( uint8_t nSeatId ) const { return (( nSeatId < 8 ) ? mSeatUserId[nSeatId] : 0 ); } - bool SetSeatUser( uint8_t nSeatId, uint32_t nCharId ); - bool UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId ); - bool IsCharInside( uint32_t nCharId ) const; - inline uint8_t GetFreeSeatsFlags() const { return mFreeSeatsFlags; } - inline uint8_t GetNbFreeSeats() const { return mNbFreeSeats; } - uint8_t GetFirstFreeSeat() const; - - //SetHealth(const uint32_t nHealth); - //uint32_t DoDamage(const uint32_t nHealthDec); - //uint32_t DoRepair(const uint32_t nHealthInc); -}; - -typedef std::map PSpawnedVhcMap; -typedef std::queue PVhcInfoList; -class PVehicles -{ - private: - PSpawnedVhcMap mSpawnedVehicles; - - bool RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle ); - bool UnregisterSpawnedVehicle( uint32_t nVehicleId ); - - public: - PVehicles(); - ~PVehicles(); - - //uint32_t CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType); - //bool RegisterVehicleOwner(uint32_t nVehiculeId, uint32_t nOwnerChar); - //bool DestroyVehicle(uint32_t nVehiculeId); - bool IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner = false, uint32_t nOwnerId = 0 ) const; - inline bool IsSpawned( uint32_t nVehicleId ) const { return ( mSpawnedVehicles.find( nVehicleId ) != mSpawnedVehicles.end() ); } - PSpawnedVehicle* GetSpawnedVehicle( uint32_t nVehicleId ) const; - bool GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const; - PSpawnedVehicle* SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos ); // Refuses for subway zone atm - bool UnspawnVehicle( uint32_t nVehicleId ); - - PVhcInfoList* GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount = 0, uint16_t nStartIndex = 0 ); - -}; - -typedef std::vector PSpawnedVhcVector; -typedef std::queue PSpawnedVhcList; - -class PSpawnedVehicles -{ - friend class PWorld; - - public: - static const uint32_t mVhcBaseLocalId = 0x03fd; //Vhc local Id are allocated downward from this value. Could br 0x3ff, but 0x3fe is used as "target" when shooting nowhere - static const uint16_t mMaxLocalVhc = 127; - - inline static bool IsPotentialSpawnedVehicle( uint32_t nLocalId ) - { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mMaxLocalVhc ) ); } - - private: - PSpawnedVhcVector mSpawnedVehicles; - uint16_t mNextFreeHint; - uint32_t mLocation; - - inline void SetLocation( uint32_t nLocation ) { mLocation = nLocation; } - - public: - PSpawnedVehicles(); - ~PSpawnedVehicles(); - - inline bool IsSpawned( uint32_t nLocalId ) const { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mSpawnedVehicles.size() ) && mSpawnedVehicles[mVhcBaseLocalId-nLocalId] ); } - PSpawnedVehicle* SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos ); - PSpawnedVehicle* GetVehicle( uint32_t nLocalId ); - PSpawnedVehicle* GetVehicleByGlobalId( uint32_t nVehicleId ) const; - bool UnspawnVehicle( uint32_t nVehicleId ); - - PSpawnedVhcList* GetSpawnedVehicles() const; -}; +#pragma once + +#include +#include +#include +#include + +class PDefVhc; + +class PVhcCoordinates { + friend class PSpawnedVehicle; + + private: + uint16_t mY; // Y-Position in world + uint16_t mZ; // Z-Position in world + uint16_t mX; // X-Position in world + uint8_t mUD; // Up - Mid - Down (d6 - 80 - 2a) // Pitch + uint16_t mLR; // Yaw + uint16_t mRoll; + uint16_t mUnknown; // Usually 0x0001 + uint8_t mFF; // Usually 0xff ... + uint8_t mAct; // Last user action state + // mAct: bit field + //0x00 = not moving + //0x01 = Left + //0x02 = Right + //0x04 = Forward + //0x08 = Back + //0x20 = Pushing down + //0x40 = Pulling up + + public: + inline PVhcCoordinates() { mX = mY = mZ = mAct = 0; mUD = 128; mLR = 34683; mRoll = 32403;} + + void SetPosition( uint16_t nY, uint16_t nZ, uint16_t nX, uint8_t nUD, uint16_t nLR, uint16_t nRoll, uint8_t nAct = 0, uint16_t nUnknown = 1, uint8_t nFF = 0xff ); + void SetInterpolate( const PVhcCoordinates& Pos1, const PVhcCoordinates& Pos2, float nCoef ); + inline uint16_t GetX() const { return mX; } + inline uint16_t GetY() const { return mY; } + inline uint16_t GetZ() const { return mZ; } + inline uint8_t GetUD() const { return mUD; } + inline uint16_t GetLR() const { return mLR; } + inline uint16_t GetRoll() const { return mRoll; } + inline uint8_t GetAct() const { return mAct; } + inline uint8_t GetUnknown() const { return mUnknown; } + inline uint8_t GetFF() const { return mFF; } +}; + +class PVehicleInformation +{ + friend class PSpawnedVehicle; + friend class PVehicles; + + private: + uint32_t mVehicleId; + uint32_t mOwnerCharId; + uint32_t mHealth; // or float ??? + uint8_t mVehicleType; + uint8_t mStatus; //vhcStatus 0:parking, 1:in_service, 2:destroyed + + public: + inline PVehicleInformation( uint32_t nVehicleId = 0, uint32_t nOwnerCharId = 0, uint32_t nHealth = 0, uint8_t nVehicleType = 0, uint8_t nStatus = 0 ) : + mVehicleId( nVehicleId ), + mOwnerCharId( nOwnerCharId ), + mHealth( nHealth ), + mVehicleType( nVehicleType ), + mStatus( nStatus ) + { } + + inline uint32_t GetVehicleId() const { return mVehicleId; } + inline uint32_t GetOwnerCharId() const { return mOwnerCharId; } + inline uint32_t GetHealth() const { return mHealth; } // or float ??? + inline uint8_t GetVehicleType() const { return mVehicleType; } + inline uint8_t GetStatus() const { return mStatus; } + bool SetStatus( uint8_t nStatus ); + + bool Load( uint32_t nVehicleId ); + bool Save(); + bool Destroy(); +}; + +class PSpawnedVehicle +{ + private: + static const uint8_t mSeatsFlags[]; + + private: + uint32_t mLocalId; + PVehicleInformation mInfo; + uint32_t mLocation; + PVhcCoordinates mCoords; + const PDefVhc* mVhcDef; + + uint32_t mSeatUserId[8]; + uint8_t mFreeSeatsFlags; + uint8_t mNbFreeSeats; + + uint16_t minmax[4][2]; //Temp + + public: + PSpawnedVehicle( uint32_t nLocalId, PVehicleInformation const* nVhcInfo, uint32_t nLocation, PVhcCoordinates const* nVhcPos ); + + inline uint32_t GetVehicleId() const { return mInfo.mVehicleId; } + inline uint32_t GetLocalId() const { return mLocalId; } + inline const PVhcCoordinates& GetPosition() const { return mCoords; } + inline const PVehicleInformation& GetInformation() const { return mInfo; } + inline bool SetStatus( uint8_t nStatus ) { return mInfo.SetStatus( nStatus ); } + + void SetLocation( uint32_t nLocation ); + inline uint32_t GetLocation() const { return mLocation; } + void SetPosition( PVhcCoordinates const* nVhcPos ); + + inline bool Save() { return mInfo.Save(); } + + int GetNumSeats() const; + inline uint32_t GetSeatUser( uint8_t nSeatId ) const { return (( nSeatId < 8 ) ? mSeatUserId[nSeatId] : 0 ); } + bool SetSeatUser( uint8_t nSeatId, uint32_t nCharId ); + bool UnsetSeatUser( uint8_t nSeatId, uint32_t nCharId ); + bool IsCharInside( uint32_t nCharId ) const; + inline uint8_t GetFreeSeatsFlags() const { return mFreeSeatsFlags; } + inline uint8_t GetNbFreeSeats() const { return mNbFreeSeats; } + uint8_t GetFirstFreeSeat() const; + + //SetHealth(const uint32_t nHealth); + //uint32_t DoDamage(const uint32_t nHealthDec); + //uint32_t DoRepair(const uint32_t nHealthInc); +}; + +typedef std::map PSpawnedVhcMap; +typedef std::queue PVhcInfoList; +class PVehicles +{ + private: + PSpawnedVhcMap mSpawnedVehicles; + + bool RegisterSpawnedVehicle( PSpawnedVehicle* nSpawnedVehicle ); + bool UnregisterSpawnedVehicle( uint32_t nVehicleId ); + + public: + PVehicles(); + ~PVehicles(); + + //uint32_t CreateVehicle(uint32_t nOwnerChar, uint8_t mVehicleType); + //bool RegisterVehicleOwner(uint32_t nVehiculeId, uint32_t nOwnerChar); + //bool DestroyVehicle(uint32_t nVehiculeId); + bool IsValidVehicle( uint32_t nVehicleId, bool nCheckOwner = false, uint32_t nOwnerId = 0 ) const; + inline bool IsSpawned( uint32_t nVehicleId ) const { return ( mSpawnedVehicles.find( nVehicleId ) != mSpawnedVehicles.end() ); } + PSpawnedVehicle* GetSpawnedVehicle( uint32_t nVehicleId ) const; + bool GetVehicleInfo( uint32_t nVehicleId, PVehicleInformation* nInfo ) const; + PSpawnedVehicle* SpawnVehicle( uint32_t nVehicleId, uint32_t nLocation, PVhcCoordinates const* nVhcPos ); // Refuses for subway zone atm + bool UnspawnVehicle( uint32_t nVehicleId ); + + PVhcInfoList* GetCharVehicles( uint32_t nCharId, uint16_t nMaxCount = 0, uint16_t nStartIndex = 0 ); + +}; + +typedef std::vector PSpawnedVhcVector; +typedef std::queue PSpawnedVhcList; + +class PSpawnedVehicles +{ + friend class PWorld; + + public: + static const uint32_t mVhcBaseLocalId = 0x03fd; //Vhc local Id are allocated downward from this value. Could br 0x3ff, but 0x3fe is used as "target" when shooting nowhere + static const uint16_t mMaxLocalVhc = 127; + + inline static bool IsPotentialSpawnedVehicle( uint32_t nLocalId ) + { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mMaxLocalVhc ) ); } + + private: + PSpawnedVhcVector mSpawnedVehicles; + uint16_t mNextFreeHint; + uint32_t mLocation; + + inline void SetLocation( uint32_t nLocation ) { mLocation = nLocation; } + + public: + PSpawnedVehicles(); + ~PSpawnedVehicles(); + + inline bool IsSpawned( uint32_t nLocalId ) const { return (( nLocalId <= mVhcBaseLocalId ) && (( mVhcBaseLocalId - nLocalId ) < mSpawnedVehicles.size() ) && mSpawnedVehicles[mVhcBaseLocalId-nLocalId] ); } + PSpawnedVehicle* SpawnVehicle( PVehicleInformation const* nVhcInfo, PVhcCoordinates const* nVhcPos ); + PSpawnedVehicle* GetVehicle( uint32_t nLocalId ); + PSpawnedVehicle* GetVehicleByGlobalId( uint32_t nVehicleId ) const; + bool UnspawnVehicle( uint32_t nVehicleId ); + + PSpawnedVhcList* GetSpawnedVehicles() const; +}; diff --git a/TinNS/Source/GameServer/WorldActors.hxx b/TinNS/Source/GameServer/WorldActors.hxx index 423327b..22c9f11 100644 --- a/TinNS/Source/GameServer/WorldActors.hxx +++ b/TinNS/Source/GameServer/WorldActors.hxx @@ -1,156 +1,156 @@ -#pragma once - -#include - -class PClient; - -/* -Current known WorldActors: - -- Furniture -1 Door -2 Wooden Door -3 Tech Door -5 Lift -6 Shutter -9 Airlock -10 Chair -11 Wooden Chair -12 Bench -13 Table -14 Recreation Unit - -- Interactions -21 Gen rep -22 Go Guardian -99 Outfitter -23/29 Venture Warp -90 City Com -98 Home term -104 Home term -160-195 Hack term -900 Carport Term - -- Cabinets -150 Cabinet -101 Secure Cabinet -105 Safe -106 High Security Safe - -- Hack Boxes -700 Light Weapon Box -703 Medium -720 Ammo Box -740 Armour Box -750 Equipment Box -780 Psi Box - -- Containers -134 Old Bag -120 Trashcan -125 Old Bag -126 Mutant Cooking Pot -127 Rotten Box -128 Rusty Box -133 Steel Box -130 Bunch of Bones -136 Dead Technician (Loot) -137 Corpse (Loot) - -- Others -131 Pile of Stones -8 Rock -510 Tree Trunk -790 Burning Barrel -800 Explosive Barrel - -- Costs -15 Pay 20nc -16 Pay 50nc -17 Pay 100nc -18 Pay 150nc -19 Pay 200nc -20 Pay 500nc - -*/ - -// Start from this offset (00 00 80 00) -#define DYNACTORIDSTART 8388608 - -class PWorldActors { - private: - // SQL Layout - enum - { - wa_id, - wa_actor_id, - wa_actor_map, - wa_actor_model, - wa_actor_type, - wa_posX, - wa_posY, - wa_posZ, - wa_rotX, - wa_rotY, - wa_rotZ, - wa_option1, - wa_option2, - wa_option3 - }; - - void SpawnWA(uint32_t nWorld, uint16_t nActorID, uint16_t nFunctionID, uint32_t nWOID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ); - void VanishWA(uint32_t nWorld, uint32_t nWAid); - - // Get next availeable WorldactorID. First, try to find ID in known .dat files, then - // Get the currently highest ID from SQL and add +1 - // select distinct wi_worlditem_id from world_items order by wi_worlditem_id desc limit 1; - uint32_t GetNextFreeWAID(); - - public: - PWorldActors(); - ~PWorldActors(); - - // Sends initial zone setup to client (after zoning-in) - void InitWorld(PClient* nClient); - - // Add new worldactor to database and spawn it. Returns created WorldID - // Position is taken from nClient, same as the worldID and calls the mainfunction - // The function values are optional (used for interactive objects, gogo or genrep) - uint32_t AddWorldActor(PClient* nClient, uint16_t nActorID, uint16_t nFuncID, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0); - - // Add new worldactor to database and spawn it. Returns created WorldID - // The function values are optional (used for interactive objects, gogo or genrep) - uint32_t AddWorldActor(uint32_t nWorldID, uint16_t nActorID, uint16_t nFuncID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0); - - // Remove worldactor in given world from SQL and game - void DelWorldActor(PClient* nClient, uint32_t nWAid); - - // Get functionvalues for worldactor - void GetWAoption(uint32_t nWAid, uint16_t nWorld, uint16_t &nValue1, uint16_t &nValue2, uint16_t &nValue3); - - // Get SQL ID from world and worldID - int GetWASQLID(uint32_t nWAid, uint32_t nWorld); - - // Check if actorID is dynamic - bool IsDynamicActor(uint32_t nWAid); - - // Not needed. Better re-spawn the actor - //bool EditWorldActor(uint32_t nWorldID, int nOption1 = -1, int nOption2 = -1, int nOption3 = -1); - - int GetWorldActorFunctionID(uint32_t nWAid); - - void GetFrontPos(uint32_t nWAID, uint16_t* mX, uint16_t* mY, uint16_t* mZ); // For chairs - int GetLinkedObjectID(uint32_t nWAID); // OptionValue 1 is used for linked object! - - // Check if given functionID does exist - bool IsValidWAFunction(int nFunctionID); - - // Checks if this functionID required an linked object or not - bool RequiresLinkedObject(int nFunctionID); - - // Checks if the given worldobjectID is valid for this type of functionID - bool IsValidLinkedObject(PClient *nClient, uint16_t nOption1, int nFunctionID); - - // Checks for double actor-IDs and deletes them from DB - void DoActorCheck(); -}; +#pragma once + +#include + +class PClient; + +/* +Current known WorldActors: + +- Furniture +1 Door +2 Wooden Door +3 Tech Door +5 Lift +6 Shutter +9 Airlock +10 Chair +11 Wooden Chair +12 Bench +13 Table +14 Recreation Unit + +- Interactions +21 Gen rep +22 Go Guardian +99 Outfitter +23/29 Venture Warp +90 City Com +98 Home term +104 Home term +160-195 Hack term +900 Carport Term + +- Cabinets +150 Cabinet +101 Secure Cabinet +105 Safe +106 High Security Safe + +- Hack Boxes +700 Light Weapon Box +703 Medium +720 Ammo Box +740 Armour Box +750 Equipment Box +780 Psi Box + +- Containers +134 Old Bag +120 Trashcan +125 Old Bag +126 Mutant Cooking Pot +127 Rotten Box +128 Rusty Box +133 Steel Box +130 Bunch of Bones +136 Dead Technician (Loot) +137 Corpse (Loot) + +- Others +131 Pile of Stones +8 Rock +510 Tree Trunk +790 Burning Barrel +800 Explosive Barrel + +- Costs +15 Pay 20nc +16 Pay 50nc +17 Pay 100nc +18 Pay 150nc +19 Pay 200nc +20 Pay 500nc + +*/ + +// Start from this offset (00 00 80 00) +#define DYNACTORIDSTART 8388608 + +class PWorldActors { + private: + // SQL Layout + enum + { + wa_id, + wa_actor_id, + wa_actor_map, + wa_actor_model, + wa_actor_type, + wa_posX, + wa_posY, + wa_posZ, + wa_rotX, + wa_rotY, + wa_rotZ, + wa_option1, + wa_option2, + wa_option3 + }; + + void SpawnWA(uint32_t nWorld, uint16_t nActorID, uint16_t nFunctionID, uint32_t nWOID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ); + void VanishWA(uint32_t nWorld, uint32_t nWAid); + + // Get next availeable WorldactorID. First, try to find ID in known .dat files, then + // Get the currently highest ID from SQL and add +1 + // select distinct wi_worlditem_id from world_items order by wi_worlditem_id desc limit 1; + uint32_t GetNextFreeWAID(); + + public: + PWorldActors(); + ~PWorldActors(); + + // Sends initial zone setup to client (after zoning-in) + void InitWorld(PClient* nClient); + + // Add new worldactor to database and spawn it. Returns created WorldID + // Position is taken from nClient, same as the worldID and calls the mainfunction + // The function values are optional (used for interactive objects, gogo or genrep) + uint32_t AddWorldActor(PClient* nClient, uint16_t nActorID, uint16_t nFuncID, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0); + + // Add new worldactor to database and spawn it. Returns created WorldID + // The function values are optional (used for interactive objects, gogo or genrep) + uint32_t AddWorldActor(uint32_t nWorldID, uint16_t nActorID, uint16_t nFuncID, uint16_t nPosX, uint16_t nPosY, uint16_t nPosZ, uint8_t nRotX, uint8_t nRotY, uint8_t nRotZ, uint16_t nOpt1 = 0, uint16_t nOpt2 = 0, uint16_t nOpt3 = 0); + + // Remove worldactor in given world from SQL and game + void DelWorldActor(PClient* nClient, uint32_t nWAid); + + // Get functionvalues for worldactor + void GetWAoption(uint32_t nWAid, uint16_t nWorld, uint16_t &nValue1, uint16_t &nValue2, uint16_t &nValue3); + + // Get SQL ID from world and worldID + int GetWASQLID(uint32_t nWAid, uint32_t nWorld); + + // Check if actorID is dynamic + bool IsDynamicActor(uint32_t nWAid); + + // Not needed. Better re-spawn the actor + //bool EditWorldActor(uint32_t nWorldID, int nOption1 = -1, int nOption2 = -1, int nOption3 = -1); + + int GetWorldActorFunctionID(uint32_t nWAid); + + void GetFrontPos(uint32_t nWAID, uint16_t* mX, uint16_t* mY, uint16_t* mZ); // For chairs + int GetLinkedObjectID(uint32_t nWAID); // OptionValue 1 is used for linked object! + + // Check if given functionID does exist + bool IsValidWAFunction(int nFunctionID); + + // Checks if this functionID required an linked object or not + bool RequiresLinkedObject(int nFunctionID); + + // Checks if the given worldobjectID is valid for this type of functionID + bool IsValidLinkedObject(PClient *nClient, uint16_t nOption1, int nFunctionID); + + // Checks for double actor-IDs and deletes them from DB + void DoActorCheck(); +}; diff --git a/TinNS/Source/GameServer/WorldDataTemplate.cxx b/TinNS/Source/GameServer/WorldDataTemplate.cxx index 003863d..4778ed3 100644 --- a/TinNS/Source/GameServer/WorldDataTemplate.cxx +++ b/TinNS/Source/GameServer/WorldDataTemplate.cxx @@ -1,251 +1,251 @@ -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -PWorldDataTemplate::PWorldDataTemplate() -{ - mUseCount = 0; - for ( int i = 0; i < WORLDDATATEMPLATE_MAXPOSITEMS; ++i ) - { - mPositionItems[i] = NULL; - } -} - -PWorldDataTemplate::~PWorldDataTemplate() -{ - DatFileDataCleanup(); -} - -void PWorldDataTemplate::DatFileDataCleanup() -{ - for ( PFurnitureItemsMap::iterator i = mFurnitureItems.begin(); i != mFurnitureItems.end(); i++ ) - delete i->second; - for ( PDoorsMap::iterator i = mDoors.begin(); i != mDoors.end(); i++ ) - delete i->second; - for ( PNPCsMap::iterator i = mNPCs.begin(); i != mNPCs.end(); i++ ) - delete i->second; -} - -bool PWorldDataTemplate::LoadDatFile( const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly ) -{ - PWorldDatParser WDatLoader; - int LoadResult; - - DatFileDataCleanup(); - if ( gDevDebug ) Console->Print( "%s Loading %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nFilename.c_str() ); - LoadResult = WDatLoader.LoadDatFile( nFilename, this, true, nTestAccesOnly ) ; // We want to discard passive objects for now - switch ( LoadResult ) - { - case 0: - { - mName = nFilename; - mBspName = WorldTemplateName; - if ( !nTestAccesOnly ) - { - SetLinkedObjects(); // temp until better solution found from .dat & .bsp files - } - return true; - } - - case -1: - { - if ( !nTestAccesOnly ) - Console->Print( "%s Can't read file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFilename.c_str() ); - break; - } - - case - 2: - { - Console->Print( "%s Bad data", Console->ColorText( RED, BLACK, "[ERROR]" ) ); - break; - } - - case - 3: - { - Console->Print( "%s Unexpected end of file", Console->ColorText( RED, BLACK, "[ERROR]" ) ); - break; - } - - default: - Console->Print( "%s Unknown error %d", Console->ColorText( RED, BLACK, "[ERROR]" ), LoadResult ); - } - return false; -} - -uint32_t PWorldDataTemplate::AddFurnitureItem( PFurnitureItemTemplate* nItem ) -{ - if ( nItem ) - { - if ( mFurnitureItems.insert( std::make_pair( nItem->GetID(), nItem ) ).second ) - { - if ( gDevDebug ) Console->Print( "%s Furniture item %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nItem->GetID() ); - - if ( nItem->GetFunctionType() == 21 ) - { - int v = nItem->GetFunctionValue(); - if (( v >= 0 ) && ( v < WORLDDATATEMPLATE_MAXPOSITEMS ) ) - { - if ( mPositionItems[v] ) - { - if (( v == WORLDDATATEMPLATE_MAXPOSITEMS - 2 ) && !mPositionItems[v+1] ) // We allow that only for Pos 9 in order not to mess with other pos - { - Console->Print( "%s Same position %d for two position items ID %d and %d. Last one will be put on next position.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() ); - ++v; - } - else - { - Console->Print( "%s Same position %d for two position items ID %d and %d. Only last one kept.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() ); - } - } - - mPositionItems[v] = nItem; - /* - Console->Print("Position entity %d (id 0x%x) added to world template", v, nItem->GetID()); - float fpX, fpY, fpZ; - uint16_t pX, pY, pZ; - nItem->GetPos(&fpX, &fpY, &fpZ); - pX = (uint16_t) (fpX + 32000); - pY = (uint16_t) (fpY + 32000); - pZ = (uint16_t) (fpZ + 32000); - Console->Print("Position Y=%f (0x%04x) Z=%f (0x%04x) X=%f (0x%04x)", fpY, pY, fpZ, pZ, fpX, pX); - */ - } - else - { - Console->Print( "%s Invalid position %d for position item ID %d. Position ignored.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, nItem->GetID() ); - } - } - return nItem->GetID(); - } - else - { - Console->Print( "%s Duplicate furniture item ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nItem->GetID() ); - } - } - return 0; -} - -const PFurnitureItemTemplate* PWorldDataTemplate::GetFurnitureItem( uint32_t ItemID ) -{ - PFurnitureItemsMap::const_iterator it = mFurnitureItems.find( ItemID ); - if ( it == mFurnitureItems.end() ) - return NULL; - else - return it->second; -} - -bool PWorldDataTemplate::getPositionItemPosition( uint8_t PosID, float* pX, float* pY, float* pZ ) -{ - if (( PosID < WORLDDATATEMPLATE_MAXPOSITEMS ) && mPositionItems[PosID] ) - { - mPositionItems[PosID]->GetPos( pX, pY, pZ ) ; - return true; - } - return false; -} - -uint32_t PWorldDataTemplate::AddDoor( PDoorTemplate* nDoor ) -{ - if ( nDoor ) - { - if ( mDoors.insert( std::make_pair( nDoor->GetID(), nDoor ) ).second ) - { - if ( gDevDebug ) Console->Print( "%s Door %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nDoor->GetID() ); - return nDoor->GetID(); - } - else - { - Console->Print( "%s Duplicate Door ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nDoor->GetID() ); - } - } - return 0; -} - -const PDoorTemplate* PWorldDataTemplate::GetDoor( uint32_t DoorID ) -{ - PDoorsMap::const_iterator it = mDoors.find( DoorID ); - if ( it == mDoors.end() ) - return NULL; - else - return it->second; -} - - -uint32_t PWorldDataTemplate::AddNPC( PNPCTemplate* nNPC ) -{ - if ( nNPC ) - { - if ( mNPCs.insert( std::make_pair( nNPC->GetNpcID(), nNPC ) ).second ) - { - if ( gDevDebug ) Console->Print( "%s NPC %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nNPC->GetNpcID() ); - return nNPC->GetNpcID(); - } - else - { - Console->Print( "%s Duplicate NPC ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nNPC->GetNpcID() ); - } - } - return 0; -} - -const PNPCTemplate* PWorldDataTemplate::GetNPC( uint32_t NPCID ) -{ - PNPCsMap::const_iterator it = mNPCs.find( NPCID ); - if ( it == mNPCs.end() ) - return NULL; - else - return it->second; -} - -void PWorldDataTemplate::SetLinkedObjects() -{ - float xI, yI, zI; - float xD, yD, zD; - float D2, minD2; - uint32_t minObjID; - uint16_t fnctType; - uint16_t tGROrder = 0; - - for ( PFurnitureItemsMap::iterator it = mFurnitureItems.begin(); it != mFurnitureItems.end(); it++ ) - { - fnctType = it->second->GetFunctionType(); - if (( fnctType == 11 ) || ( fnctType == 12 ) || ( fnctType == 13 ) || ( fnctType == 23 ) ) // if function is apt entry button, door access if, hack button or money button - { - it->second->GetPos( &xI, &yI, &zI ); -//Console->Print("Button pos: %0.0f %0.0f %0.0f", xI, yI, zI); - minD2 = 1e9; - minObjID = 0; - for ( PDoorsMap::iterator dit = mDoors.begin(); dit != mDoors.end(); dit++ ) - { -//Console->Print("%s Found door %d (%s) : %s triggered, %s", Console->ColorText(GREEN, BLACK, "[Debug]"), dit->first, dit->second->GetName().c_str(), (dit->second->IsTriggeredDoor()?"":"not"), (dit->second->IsDoubleDoor()?"double":"single") ); - if ( dit->second->IsTriggeredDoor() ) - { - dit->second->GetPos( &xD, &yD, &zD ); -//Console->Print("Door pos: %0.0f %0.0f %0.0f", xD, yD, zD); - D2 = ( xI - xD ) * ( xI - xD ) + ( yI - yD ) * ( yI - yD ) + ( zI - zD ) * ( zI - zD ); -//Console->Print("Dist D2:%0.0f minD2:%0.0f", D2, minD2); - if ( D2 < minD2 ) - { - minD2 = D2; - minObjID = 1 + dit->first; - } - } - } - if ( minObjID-- ) - { - it->second->SetLinkedObjectID( minObjID ); - if ( gDevDebug ) Console->Print( "%s Found triggered door %d (%s) for button %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), minObjID, GetDoor( minObjID )->GetName().c_str(), it->first, it->second->GetName().c_str() ); - - } - else - { - Console->Print( "%s No triggered door found for button %d (%s) in World data template %s", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), it->first, it->second->GetName().c_str(), this->GetName().c_str() ); - } - } - else if ( fnctType == 6 ) // if function is genrep - { - it->second->SetLinkedObjectID( ++tGROrder ); - } - } - -} +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +PWorldDataTemplate::PWorldDataTemplate() +{ + mUseCount = 0; + for ( int i = 0; i < WORLDDATATEMPLATE_MAXPOSITEMS; ++i ) + { + mPositionItems[i] = NULL; + } +} + +PWorldDataTemplate::~PWorldDataTemplate() +{ + DatFileDataCleanup(); +} + +void PWorldDataTemplate::DatFileDataCleanup() +{ + for ( PFurnitureItemsMap::iterator i = mFurnitureItems.begin(); i != mFurnitureItems.end(); i++ ) + delete i->second; + for ( PDoorsMap::iterator i = mDoors.begin(); i != mDoors.end(); i++ ) + delete i->second; + for ( PNPCsMap::iterator i = mNPCs.begin(); i != mNPCs.end(); i++ ) + delete i->second; +} + +bool PWorldDataTemplate::LoadDatFile( const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly ) +{ + PWorldDatParser WDatLoader; + int LoadResult; + + DatFileDataCleanup(); + if ( gDevDebug ) Console->Print( "%s Loading %s", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nFilename.c_str() ); + LoadResult = WDatLoader.LoadDatFile( nFilename, this, true, nTestAccesOnly ) ; // We want to discard passive objects for now + switch ( LoadResult ) + { + case 0: + { + mName = nFilename; + mBspName = WorldTemplateName; + if ( !nTestAccesOnly ) + { + SetLinkedObjects(); // temp until better solution found from .dat & .bsp files + } + return true; + } + + case -1: + { + if ( !nTestAccesOnly ) + Console->Print( "%s Can't read file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFilename.c_str() ); + break; + } + + case - 2: + { + Console->Print( "%s Bad data", Console->ColorText( RED, BLACK, "[ERROR]" ) ); + break; + } + + case - 3: + { + Console->Print( "%s Unexpected end of file", Console->ColorText( RED, BLACK, "[ERROR]" ) ); + break; + } + + default: + Console->Print( "%s Unknown error %d", Console->ColorText( RED, BLACK, "[ERROR]" ), LoadResult ); + } + return false; +} + +uint32_t PWorldDataTemplate::AddFurnitureItem( PFurnitureItemTemplate* nItem ) +{ + if ( nItem ) + { + if ( mFurnitureItems.insert( std::make_pair( nItem->GetID(), nItem ) ).second ) + { + if ( gDevDebug ) Console->Print( "%s Furniture item %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nItem->GetID() ); + + if ( nItem->GetFunctionType() == 21 ) + { + int v = nItem->GetFunctionValue(); + if (( v >= 0 ) && ( v < WORLDDATATEMPLATE_MAXPOSITEMS ) ) + { + if ( mPositionItems[v] ) + { + if (( v == WORLDDATATEMPLATE_MAXPOSITEMS - 2 ) && !mPositionItems[v+1] ) // We allow that only for Pos 9 in order not to mess with other pos + { + Console->Print( "%s Same position %d for two position items ID %d and %d. Last one will be put on next position.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() ); + ++v; + } + else + { + Console->Print( "%s Same position %d for two position items ID %d and %d. Only last one kept.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, mPositionItems[v]->GetID(), nItem->GetID() ); + } + } + + mPositionItems[v] = nItem; + /* + Console->Print("Position entity %d (id 0x%x) added to world template", v, nItem->GetID()); + float fpX, fpY, fpZ; + uint16_t pX, pY, pZ; + nItem->GetPos(&fpX, &fpY, &fpZ); + pX = (uint16_t) (fpX + 32000); + pY = (uint16_t) (fpY + 32000); + pZ = (uint16_t) (fpZ + 32000); + Console->Print("Position Y=%f (0x%04x) Z=%f (0x%04x) X=%f (0x%04x)", fpY, pY, fpZ, pZ, fpX, pX); + */ + } + else + { + Console->Print( "%s Invalid position %d for position item ID %d. Position ignored.", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), v, nItem->GetID() ); + } + } + return nItem->GetID(); + } + else + { + Console->Print( "%s Duplicate furniture item ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nItem->GetID() ); + } + } + return 0; +} + +const PFurnitureItemTemplate* PWorldDataTemplate::GetFurnitureItem( uint32_t ItemID ) +{ + PFurnitureItemsMap::const_iterator it = mFurnitureItems.find( ItemID ); + if ( it == mFurnitureItems.end() ) + return NULL; + else + return it->second; +} + +bool PWorldDataTemplate::getPositionItemPosition( uint8_t PosID, float* pX, float* pY, float* pZ ) +{ + if (( PosID < WORLDDATATEMPLATE_MAXPOSITEMS ) && mPositionItems[PosID] ) + { + mPositionItems[PosID]->GetPos( pX, pY, pZ ) ; + return true; + } + return false; +} + +uint32_t PWorldDataTemplate::AddDoor( PDoorTemplate* nDoor ) +{ + if ( nDoor ) + { + if ( mDoors.insert( std::make_pair( nDoor->GetID(), nDoor ) ).second ) + { + if ( gDevDebug ) Console->Print( "%s Door %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nDoor->GetID() ); + return nDoor->GetID(); + } + else + { + Console->Print( "%s Duplicate Door ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nDoor->GetID() ); + } + } + return 0; +} + +const PDoorTemplate* PWorldDataTemplate::GetDoor( uint32_t DoorID ) +{ + PDoorsMap::const_iterator it = mDoors.find( DoorID ); + if ( it == mDoors.end() ) + return NULL; + else + return it->second; +} + + +uint32_t PWorldDataTemplate::AddNPC( PNPCTemplate* nNPC ) +{ + if ( nNPC ) + { + if ( mNPCs.insert( std::make_pair( nNPC->GetNpcID(), nNPC ) ).second ) + { + if ( gDevDebug ) Console->Print( "%s NPC %d added to world template", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), nNPC->GetNpcID() ); + return nNPC->GetNpcID(); + } + else + { + Console->Print( "%s Duplicate NPC ID %d !!! Not added to world template", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), nNPC->GetNpcID() ); + } + } + return 0; +} + +const PNPCTemplate* PWorldDataTemplate::GetNPC( uint32_t NPCID ) +{ + PNPCsMap::const_iterator it = mNPCs.find( NPCID ); + if ( it == mNPCs.end() ) + return NULL; + else + return it->second; +} + +void PWorldDataTemplate::SetLinkedObjects() +{ + float xI, yI, zI; + float xD, yD, zD; + float D2, minD2; + uint32_t minObjID; + uint16_t fnctType; + uint16_t tGROrder = 0; + + for ( PFurnitureItemsMap::iterator it = mFurnitureItems.begin(); it != mFurnitureItems.end(); it++ ) + { + fnctType = it->second->GetFunctionType(); + if (( fnctType == 11 ) || ( fnctType == 12 ) || ( fnctType == 13 ) || ( fnctType == 23 ) ) // if function is apt entry button, door access if, hack button or money button + { + it->second->GetPos( &xI, &yI, &zI ); +//Console->Print("Button pos: %0.0f %0.0f %0.0f", xI, yI, zI); + minD2 = 1e9; + minObjID = 0; + for ( PDoorsMap::iterator dit = mDoors.begin(); dit != mDoors.end(); dit++ ) + { +//Console->Print("%s Found door %d (%s) : %s triggered, %s", Console->ColorText(GREEN, BLACK, "[Debug]"), dit->first, dit->second->GetName().c_str(), (dit->second->IsTriggeredDoor()?"":"not"), (dit->second->IsDoubleDoor()?"double":"single") ); + if ( dit->second->IsTriggeredDoor() ) + { + dit->second->GetPos( &xD, &yD, &zD ); +//Console->Print("Door pos: %0.0f %0.0f %0.0f", xD, yD, zD); + D2 = ( xI - xD ) * ( xI - xD ) + ( yI - yD ) * ( yI - yD ) + ( zI - zD ) * ( zI - zD ); +//Console->Print("Dist D2:%0.0f minD2:%0.0f", D2, minD2); + if ( D2 < minD2 ) + { + minD2 = D2; + minObjID = 1 + dit->first; + } + } + } + if ( minObjID-- ) + { + it->second->SetLinkedObjectID( minObjID ); + if ( gDevDebug ) Console->Print( "%s Found triggered door %d (%s) for button %d (%s)", Console->ColorText( GREEN, BLACK, "[Debug]" ), minObjID, GetDoor( minObjID )->GetName().c_str(), it->first, it->second->GetName().c_str() ); + + } + else + { + Console->Print( "%s No triggered door found for button %d (%s) in World data template %s", Console->ColorText( YELLOW, BLACK, "[NOTICE]" ), it->first, it->second->GetName().c_str(), this->GetName().c_str() ); + } + } + else if ( fnctType == 6 ) // if function is genrep + { + it->second->SetLinkedObjectID( ++tGROrder ); + } + } + +} diff --git a/TinNS/Source/GameServer/WorldDataTemplate.hxx b/TinNS/Source/GameServer/WorldDataTemplate.hxx index d93f4ba..c052b68 100644 --- a/TinNS/Source/GameServer/WorldDataTemplate.hxx +++ b/TinNS/Source/GameServer/WorldDataTemplate.hxx @@ -1,74 +1,74 @@ -#pragma once - -#include -#include - -#define WORLDDATATEMPLATE_MAXPOSITEMS 11 - -class PFurnitureItemTemplate; -typedef std::map PFurnitureItemsMap; - -class PDoorTemplate; -typedef std::map PDoorsMap; - -class PNPCTemplate; -typedef std::map PNPCsMap; - -class PWorldDataTemplate -{ -private: - std::string mName; // (datfile) relative path+filename without leading ./ or ./worlds/ nor .dat extension - std::string mBspName; // (bsp file) relative path+filename without leading ./ or ./worlds/ nor .bsp extension - PFurnitureItemsMap mFurnitureItems; - PDoorsMap mDoors; - PNPCsMap mNPCs; - PFurnitureItemTemplate* mPositionItems[WORLDDATATEMPLATE_MAXPOSITEMS]; - - int mUseCount; - - void DatFileDataCleanup(); - void SetLinkedObjects(); // This method implements some workarouds for some world objects on which we lack info. - -public: - PWorldDataTemplate(); - ~PWorldDataTemplate(); - - bool LoadDatFile(const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly = false); - inline const std::string& GetName() - { - return mName; - } - inline const std::string& GetBspName() - { - return mBspName; - } - - inline void IncreaseUseCount() - { - ++mUseCount; - } - inline int DecreaseUseCount() - { - return (mUseCount ? --mUseCount : 0); - } - inline int GetUseCount() - { - return mUseCount; - } - - uint32_t AddFurnitureItem(PFurnitureItemTemplate* nItem); - const PFurnitureItemTemplate* GetFurnitureItem(uint32_t ItemID); - bool getPositionItemPosition(uint8_t PosID, float* pX, float* pY, float* pZ); - - uint32_t AddDoor(PDoorTemplate* nDoor); - const PDoorTemplate* GetDoor(uint32_t DoorID); - - uint32_t AddNPC(PNPCTemplate* nNPC); - - // External functions for NPCManager - const PNPCTemplate* GetNPC(uint32_t NPCID); - inline const PNPCsMap *GetNPCMap() const - { - return &mNPCs; - }; // called by class PNPCWorld to get all NPCs for this world -}; +#pragma once + +#include +#include + +#define WORLDDATATEMPLATE_MAXPOSITEMS 11 + +class PFurnitureItemTemplate; +typedef std::map PFurnitureItemsMap; + +class PDoorTemplate; +typedef std::map PDoorsMap; + +class PNPCTemplate; +typedef std::map PNPCsMap; + +class PWorldDataTemplate +{ +private: + std::string mName; // (datfile) relative path+filename without leading ./ or ./worlds/ nor .dat extension + std::string mBspName; // (bsp file) relative path+filename without leading ./ or ./worlds/ nor .bsp extension + PFurnitureItemsMap mFurnitureItems; + PDoorsMap mDoors; + PNPCsMap mNPCs; + PFurnitureItemTemplate* mPositionItems[WORLDDATATEMPLATE_MAXPOSITEMS]; + + int mUseCount; + + void DatFileDataCleanup(); + void SetLinkedObjects(); // This method implements some workarouds for some world objects on which we lack info. + +public: + PWorldDataTemplate(); + ~PWorldDataTemplate(); + + bool LoadDatFile(const std::string& WorldTemplateName, const std::string& nFilename, const bool nTestAccesOnly = false); + inline const std::string& GetName() + { + return mName; + } + inline const std::string& GetBspName() + { + return mBspName; + } + + inline void IncreaseUseCount() + { + ++mUseCount; + } + inline int DecreaseUseCount() + { + return (mUseCount ? --mUseCount : 0); + } + inline int GetUseCount() + { + return mUseCount; + } + + uint32_t AddFurnitureItem(PFurnitureItemTemplate* nItem); + const PFurnitureItemTemplate* GetFurnitureItem(uint32_t ItemID); + bool getPositionItemPosition(uint8_t PosID, float* pX, float* pY, float* pZ); + + uint32_t AddDoor(PDoorTemplate* nDoor); + const PDoorTemplate* GetDoor(uint32_t DoorID); + + uint32_t AddNPC(PNPCTemplate* nNPC); + + // External functions for NPCManager + const PNPCTemplate* GetNPC(uint32_t NPCID); + inline const PNPCsMap *GetNPCMap() const + { + return &mNPCs; + }; // called by class PNPCWorld to get all NPCs for this world +}; diff --git a/TinNS/Source/GameServer/Worlds.cxx b/TinNS/Source/GameServer/Worlds.cxx index 5efc667..57bf7a0 100644 --- a/TinNS/Source/GameServer/Worlds.cxx +++ b/TinNS/Source/GameServer/Worlds.cxx @@ -1,796 +1,796 @@ -#include -#include "GameServer/Includes.hxx" -#include "GameServer/Definitions/Includes.hxx" -#include "Common/Includes.hxx" - -/**** PWorld ****/ -uint16_t const PWorld::mZoneOutLimitOffset = 0x100; -uint16_t const PWorld::mBottomZoneOutLimit = 0x4800 - PWorld::mZoneOutLimitOffset; -uint16_t const PWorld::mBottomZoneInLimit = 0x4a00; -uint16_t const PWorld::mTopZoneOutLimit = 0xb200 + PWorld::mZoneOutLimitOffset; -uint16_t const PWorld::mTopZoneInLimit = 0xb000; -const std::string EmptyString; - -PWorld::PWorld() -{ - mID = 0; - mUseCount = 0; - mWorldDataTemplate = NULL; -} - -PWorld::~PWorld() -{ -} - -bool PWorld::Load( uint32_t nWorldID ) -{ - std::string WorldTemplateName; - std::string tFileName; - bool tCheckOK; - - if ( nWorldID > PWorlds::mAptBaseWorldId ) - { - //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId); - int AptTmplID = Appartements->GetAptType( nWorldID ); - if ( !AptTmplID ) - { - Console->Print( "%s PWorld::Load - invalid apt %d", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID - PWorlds::mAptBaseWorldId ); - return false; - } - const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID ); - if ( !nAppDef ) - { - Console->Print( "%s PWorld::Load - invalid apt type %d", Console->ColorText( RED, BLACK, "[WARNING]" ), AptTmplID ); - return false; - } - WorldTemplateName = nAppDef->GetWorldName(); - - tFileName = std::string( "worlds/" ) + WorldTemplateName + ".dat"; - tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ); - if ( !tCheckOK ) - { - tFileName = WorldTemplateName + ".dat"; - tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ); - } - if ( !tCheckOK ) - { - Console->Print( "%s PWorld::Load - unable to lease apt world %s (%s)", Console->ColorText( RED, BLACK, "[WARNING]" ), WorldTemplateName.c_str(), tFileName.c_str() ); - return false; - } - } - else - { - const PDefWorldFile* nWorldFileDef; - - if (( nWorldID > 90000 ) && ( nWorldID < 90017 ) ) // hardcoded holomatch hack - { - nWorldFileDef = NULL; - char worldName[19]; - int MatchID = nWorldID - 90000; - if ( MatchID > 8 ) // to care for Neofrag 1 & 2 - MatchID -= 8; - if ( MatchID > 6 ) - MatchID = 6; // holomatch 7 and 8 are same as 6 - snprintf( worldName, 19, "holomatch/neofrag%d", MatchID ); - WorldTemplateName = worldName; - } - else - { - nWorldFileDef = GameDefs->WorldFiles()->GetDef( nWorldID ); - if ( !nWorldFileDef ) - return false; - WorldTemplateName = nWorldFileDef->GetName(); - } - - const PDefWorld* tWorldDef = GameDefs->Worlds()->GetDef( nWorldID ); - if ( tWorldDef ) // should always be true here - { - if ( !( tWorldDef->GetDatFile().empty() ) ) - tFileName = tWorldDef->GetDatFile(); - else if ( nWorldFileDef ) - tFileName = nWorldFileDef->GetBasicFileName() + ".dat"; - else - { - tFileName = "worlds/"; - tFileName += WorldTemplateName; - tFileName += ".dat"; - } - } - else - return false; // should'nt happen here - - if ( !Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ) ) - return false; - } - - mWorldDataTemplate = Worlds->GetWorldDataTemplate( tFileName ); - if ( !mWorldDataTemplate ) - { - Console->Print( "%s PWorld::Load : Unexpected world %d not found error", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID ); - return false; - } - - mID = nWorldID; - mSpawnedVehicles.SetLocation( nWorldID ); - // furniture & other world stuff loading here - Console->Print( "%s Loaded world %d", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nWorldID ); - return true; -} - -std::string PWorld::GetName() -{ - return ( mWorldDataTemplate ? mWorldDataTemplate->GetName() : EmptyString ); -} - -std::string PWorld::GetBspName() -{ - return ( mWorldDataTemplate ? mWorldDataTemplate->GetBspName() : EmptyString ); -} - -bool PWorld::IsAppartment() -{ - return mIsAppartment; -} - -const PFurnitureItemTemplate *PWorld::GetFurnitureItemTemplate( uint32_t nItemID ) -{ - return ( mWorldDataTemplate ? mWorldDataTemplate->GetFurnitureItem( nItemID ) : NULL ) ; -} - -const PDefWorldModel *PWorld::GetFurnitureItemModel(uint32_t nItemID) -{ - if ( mWorldDataTemplate ) - { - const PFurnitureItemTemplate* tFurniture = mWorldDataTemplate->GetFurnitureItem( nItemID ); - if ( tFurniture ) - return tFurniture->GetDefWorldModel(); - } - return nullptr; -} - -const PDoorTemplate *PWorld::GetDoor(uint32_t nDoorID) -{ - return (mWorldDataTemplate ? mWorldDataTemplate->GetDoor(nDoorID) : nullptr); -} - -bool PWorld::getPositionItemPosition(uint8_t PosID, float *pX, float *pY, float *pZ) -{ - return (mWorldDataTemplate ? mWorldDataTemplate->getPositionItemPosition(PosID, pX, pY, pZ) : false); -} - -bool PWorld::CharUseChair( int CharLocalID, uint32_t nItemID ) -{ - PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID ); - if ( it == mChairsInUseMap.end() ) // chair is free - { - if ( gDevDebug ) - Console->Print( "%s Localchar %d now using free chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID ); - mChairsInUseMap.insert( std::make_pair( nItemID, CharLocalID ) ); - return true; - } - else // chair is already in use - { - if ( gDevDebug ) - { - if ( it->second == CharLocalID ) - { - Console->Print( "%s Localchar %d already using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID ); - } - else - { - Console->Print( "%s Localchar %d can't sit on chair %d used by localchar %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID, it->second ); - } - } - return ( it->second == CharLocalID ); - } -} - -void PWorld::CharLeaveChair( int CharLocalID, uint32_t nItemID ) -{ - PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID ); - if (( it != mChairsInUseMap.end() ) && ( it->second == CharLocalID ) ) // chair is in use by this char - { - if ( gDevDebug ) - Console->Print( "%s Localchar %d leaving chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID ); - mChairsInUseMap.erase( it ); - } -} - -PClient* PWorld::GetClientByCharLocalId( uint32_t rawObjectId ) const -{ - // Temp implementation - return ClientManager->GetClientByCharLocalId( rawObjectId, mID ); -} - -PSpawnedVehicles *PWorld::GetSpawnedVehicles() -{ - return &mSpawnedVehicles; -} - -bool PWorld::CheckVhcNeedZoning( PVhcCoordinates const* nPos ) const -{ - if ( ( nPos->GetX() <= mBottomZoneOutLimit ) || ( nPos->GetX() >= mTopZoneOutLimit ) || ( nPos->GetY() <= mBottomZoneOutLimit ) || ( nPos->GetY() >= mTopZoneOutLimit ) ) - return true; - else - return false; -} - -uint32_t PWorld::GetVhcZoningDestination( PSpawnedVehicle const* nVhc, PVhcCoordinates* nPos ) const -{ - uint32_t destWorldId = 0; - int16_t vChange = 0; - int16_t hChange = 0; - PVhcCoordinates const vhcPos = nVhc->GetPosition(); - uint16_t posX = vhcPos.GetX(); - uint16_t posY = vhcPos.GetY(); - - if ( posX <= mBottomZoneOutLimit ) - { - vChange = 1; - } - else if ( posX >= mTopZoneOutLimit ) - { - vChange = -1; - } - - if ( posY <= mBottomZoneOutLimit ) - { - hChange = -1; - } - else if ( posY >= mTopZoneOutLimit ) - { - hChange = 1; - } - - if ( vChange || hChange ) - { - //Console->Print( YELLOW, BLACK, "[DEBUG] Limit Reached V:%d H:%d mapId:%d", vChange,hChange,mID ); - uint8_t currH = 0; - uint8_t currV = 0; - int16_t newH, newV; - - if ( Worlds->GetWorldmapFromWorldId( mID, currH, currV ) ) - { - //Console->Print( YELLOW, BLACK, "[DEBUG] current map pos V:%d H:%d", currV,currH ); - newH = currH + hChange; - if ( newH < 0 ) - newH = 0; - else if ( newH >= PWorlds::mOutdoorWorldmapHSize ) - newH = PWorlds::mOutdoorWorldmapHSize; - - newV = currV + vChange; - if ( newV < 0 ) - newV = 0; - else if ( newV >= PWorlds::mOutdoorWorldmapHSize ) - newV = PWorlds::mOutdoorWorldmapHSize; - - //Console->Print( YELLOW, BLACK, "[DEBUG] new map pos V:%d H:%d", newV,newH ); - if (( newH != currH ) || ( newV != currV ) ) - { - destWorldId = Worlds->GetWorldIdFromWorldmap( newH, newV ); - - if ( destWorldId && nPos ) - { - if ( vChange == 1 ) - posX = mTopZoneInLimit; - else if ( vChange == -1 ) - posX = mBottomZoneInLimit; - - if ( hChange == -1 ) - posY = mTopZoneInLimit; - else if ( hChange == 1 ) - posY = mBottomZoneInLimit; - - nPos->SetPosition( posY, vhcPos.GetZ(), posX, vhcPos.GetUD(), vhcPos.GetLR(), vhcPos.GetRoll(), vhcPos.GetAct(), vhcPos.GetUnknown(), vhcPos.GetFF() ); - } - } - } - } - - return destWorldId; -} - -const PNPCsMap *PWorld::GetNPCMap() const -{ - return (mWorldDataTemplate ? mWorldDataTemplate->GetNPCMap() : nullptr); -} - -const PNPCTemplate *PWorld::GetNPCTemplate(uint32_t nNPCID) const -{ - return (mWorldDataTemplate ? mWorldDataTemplate->GetNPC(nNPCID) : nullptr); -} - -/**** PWorlds ****/ -uint32_t const PWorlds::mNcSubwayWorldId = 1000; -uint32_t const PWorlds::mAptBaseWorldId = 100000; -uint32_t const PWorlds::mOutdoorBaseWorldId = 2001; -uint32_t const PWorlds::mOutdoorWorldIdVIncrement = 20; -uint8_t const PWorlds::mOutdoorWorldmapHSize = 16; -uint8_t const PWorlds::mOutdoorWorldmapVSize = 11; -uint32_t const PWorlds::mOutdoorMaxWorldId = PWorlds::mOutdoorBaseWorldId + PWorlds::mOutdoorWorldIdVIncrement * ( PWorlds::mOutdoorWorldmapVSize - 1 ) + PWorlds::mOutdoorWorldmapHSize - 1; - -PWorlds::PWorlds() -{ - mPreloadWorldsTemplates = false; // to be put as config option - mPreloadStaticWorlds = false; // to be put as config option -} - -PWorlds::~PWorlds() -{ - for ( PWorldsMap::iterator i = mStaticWorldsMap.begin(); i != mStaticWorldsMap.end(); i++ ) - if ( i->second ) - { - delete i->second; - } - for ( PWorldsMap::iterator i = mOnDemandWorldsMap.begin(); i != mOnDemandWorldsMap.end(); i++ ) - if ( i->second ) - { - delete i->second; - } - for ( PWorldDataTemplatesMap::iterator i = mWorldDataTemplatesMap.begin(); i != mWorldDataTemplatesMap.end(); i++ ) - if ( i->second ) - { - delete i->second; - } -} - -bool PWorlds::LeaseWorldDataTemplate( const std::string& nBspName, const std::string& nFileName, const bool nPreloadPhase ) -{ - PWorldDataTemplate* tWorldDataTemplate; - - PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName ); - if ( it == mWorldDataTemplatesMap.end() ) // template unkown yet - { - if ( nPreloadPhase ) // if in preload phase, we try to load it or make it known - { - tWorldDataTemplate = new PWorldDataTemplate; - if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName, !mPreloadWorldsTemplates ) ) - { - if ( mPreloadWorldsTemplates ) - { - mWorldDataTemplatesMap.insert( std::make_pair( nFileName, tWorldDataTemplate ) ); - tWorldDataTemplate->IncreaseUseCount(); - } - else - { - mWorldDataTemplatesMap.insert( std::make_pair( nFileName, ( PWorldDataTemplate* )NULL ) ); // NULL means file access OK but not preloaded yet - delete tWorldDataTemplate; - } - //return true; - } - else - { - delete tWorldDataTemplate; - return false; - } - } - else - { - return false; - } - } - else // template already known - { - if ( !it->second && !nPreloadPhase ) // template known but not already loaded and not in preload ? - { - tWorldDataTemplate = new PWorldDataTemplate; - if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName ) ) - { - it->second = tWorldDataTemplate; - } - else - { - Console->Print( "%s Invalid world data template file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFileName.c_str() ); - mWorldDataTemplatesMap.erase( it ); - delete tWorldDataTemplate; - return false; - } - } - - if ( !nPreloadPhase ) - it->second->IncreaseUseCount(); - - //return true; - } - - return true; -} - -void PWorlds::ReleaseWorldDataTemplate( const std::string& nFileName ) -{ - PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName ); - if (( it != mWorldDataTemplatesMap.end() ) && it->second ) - { - it->second->DecreaseUseCount(); - } - else - Console->Print( "%s PWorlds::ReleaseWorldDataTemplate : try to relese not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() ); -} - -void PWorlds::UnloadWorldDataTemplate( const std::string& nFileName ) -{ - PWorldDataTemplate* tWorldDataTemplate; - - PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName ); - if (( it != mWorldDataTemplatesMap.end() ) && it->second ) - { - tWorldDataTemplate = it->second; - if ( mPreloadWorldsTemplates || ( tWorldDataTemplate->GetUseCount() > 0 ) ) - Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to unload template %s when use count not null ou preload set", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() ); - else - { - it->second = ( PWorldDataTemplate* )NULL; - delete tWorldDataTemplate; - } - } - else - Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to release not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() ); -} - -PWorldDataTemplate* PWorlds::GetWorldDataTemplate( const std::string& nFileName ) -{ - PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( nFileName ); - if ( it != mWorldDataTemplatesMap.end() ) - return it->second; - else - return NULL; -} - -bool PWorlds::LoadWorlds() // once Load is done, only WorldDataTemplate registred in mWorldDataTemplatesMap -{ - // will be considered as valid - std::string tFileName; - std::string tBspName; - const PDefWorld* tDefWorld; - bool tCheckOK; - int ValidCount = 0, InvalidCount = 0, DblInvCount = 0; - int DatTmplCount, BadDatTmplCount; - std::set - InvalideFiles; - - // Appartment templates checking or preloading - std::map::const_iterator itAptStart = GameDefs->Appartements()->ConstIteratorBegin(); - std::map::const_iterator itAptEnd = GameDefs->Appartements()->ConstIteratorEnd(); - for ( std::map::const_iterator i = itAptStart; i != itAptEnd; i++ ) - { - tCheckOK = false; - tBspName = i->second->GetWorldName(); - tFileName = std::string( "worlds/" ) + tBspName + ".dat"; - if ( !InvalideFiles.count( tFileName ) ) - { - tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true ); - if ( !tCheckOK ) - { - InvalideFiles.insert( tFileName ); - if ( gDevDebug ) - Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() ); - } - } - if ( !tCheckOK ) // in case full path was given without omiting worlds/ or in another dir/archive ... - { - tFileName = tBspName + ".dat"; - if ( !InvalideFiles.count( tFileName ) ) - { - tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true ); - if ( !tCheckOK ) - { - InvalideFiles.insert( tFileName ); - ++DblInvCount; - } - } - } - - if ( tCheckOK ) - { - ++ValidCount; - if ( gDevDebug ) - Console->Print( GREEN, BLACK, "Template file %s for appartment %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); - } - else - { - ++InvalidCount; - if ( gDevDebug ) - Console->Print( RED, BLACK, "Template file %s for appartment %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); - } - } - - DatTmplCount = mWorldDataTemplatesMap.size(); - BadDatTmplCount = InvalideFiles.size(); - Console->Print( "%s %d valid appartement templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, DatTmplCount ); - if ( InvalidCount ) - Console->Print( "%s %d invalid appartement templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, BadDatTmplCount - DblInvCount ); - - // Static worlds & static worlds templates checking or preloading - ValidCount = InvalidCount = 0; - const PDefWorldFile* tDefWorldFile; - std::map::const_iterator itFilStart = GameDefs->WorldFiles()->ConstIteratorBegin(); - std::map::const_iterator itFilEnd = GameDefs->WorldFiles()->ConstIteratorEnd(); - for ( std::map::const_iterator i = itFilStart; i != itFilEnd; i++ ) - { - tDefWorldFile = i->second; - - tDefWorld = GameDefs->Worlds()->GetDef( tDefWorldFile->GetIndex() ); - if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too - { - tBspName = tDefWorldFile->GetName(); - if ( !( tDefWorld->GetDatFile().empty() ) ) - tFileName = tDefWorld->GetDatFile(); - else - tFileName = i->second->GetBasicFileName() + ".dat"; - - tCheckOK = false; - if ( !InvalideFiles.count( tFileName ) ) - { - tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true ); - if ( !tCheckOK ) - { - InvalideFiles.insert( tFileName ); - if ( gDevDebug ) - Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() ); - } - } - - if ( tCheckOK ) - { - ++ValidCount; - if ( mPreloadStaticWorlds ) - { - LeaseWorld( tDefWorldFile->GetIndex(), true ); // This will make the world ready and kept in mem (use count always >0 ) - } - else - { - mStaticWorldsMap.insert( std::make_pair( tDefWorldFile->GetIndex(), ( PWorld* )NULL ) ); - } - if ( gDevDebug ) - Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); - } - else - { - ++InvalidCount; - if ( gDevDebug ) - Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); - } - } - } - - // Hardcoded neofrag worlds ... oO ... and neofrag4.dat can't be found :-/ - for ( int i = 1; i <= 16; i++ ) - { - char worldName[19]; - int MatchID = i; - if ( MatchID > 8 ) // to care for Neofrag 1 & 2 - MatchID -= 8; - if ( MatchID > 6 ) - MatchID = 6; // holomatch 7 and 8 are same as 6 - snprintf( worldName, 19, "holomatch/neofrag%d", MatchID ); - - tDefWorld = GameDefs->Worlds()->GetDef( 90000 + i ); - if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too - { - if ( !( tDefWorld->GetDatFile().empty() ) ) - tFileName = tDefWorld->GetDatFile(); - else - { - tFileName = "worlds/"; - tFileName += worldName; - tFileName += ".dat"; - } - - tCheckOK = false; - if ( !InvalideFiles.count( tFileName ) ) - { - tCheckOK = LeaseWorldDataTemplate( worldName, tFileName, true ); - if ( !tCheckOK ) - { - InvalideFiles.insert( tFileName ); - if ( gDevDebug ) - Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() ); - } - } - - if ( tCheckOK ) - { - ++ValidCount; - if ( mPreloadStaticWorlds ) - { - LeaseWorld( 90000 + i, true ); // This will make the world ready and kept in mem (use count always >0 ) - } - else - { - mStaticWorldsMap.insert( std::make_pair( 90000 + i, ( PWorld* )NULL ) ); - } - if ( gDevDebug ) - Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), 90000 + i, worldName ); - } - else - { - ++InvalidCount; - if ( gDevDebug ) - Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), 90000 + i, worldName ); - } - } - } - - Console->Print( "%s %d valid world templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, mWorldDataTemplatesMap.size() - DatTmplCount ); - if ( InvalidCount ) - Console->Print( "%s %d invalid world templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, InvalideFiles.size() - BadDatTmplCount - DblInvCount ); - Console->Print( "%s %d static worlds prepared", Console->ColorText( GREEN, BLACK, "[Success]" ), mStaticWorldsMap.size() ); - - // release memory if World templates preload activated, this cache that won't be used anymore - // if (mPreloadWorldsTemplates) Filesystem->ClearCache(); - - return true; -} - -bool PWorlds::IsValidWorld( uint32_t nWorldID ) const -{ - if ( nWorldID > PWorlds::mAptBaseWorldId ) - { - if ( mOnDemandWorldsMap.count( nWorldID ) ) // Check if already loaded - return true; - else //should better do a check using a PAppartements class object to get the world template - { - //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId); - int AptTmplID = Appartements->GetAptType( nWorldID ); - if ( !AptTmplID ) - return false; - - const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID ); - if ( !nAppDef ) - return false; - - std::string tFileName = "worlds/" + nAppDef->GetWorldName() + ".dat"; - PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( tFileName ); - return ( it != mWorldDataTemplatesMap.end() ); - } - } - else - { - if ( gDevDebug ) - Console->Print( "%s Checking validity for world %d : %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID, mStaticWorldsMap.count( nWorldID ) ? "OK" : "BAD" ); - return ( mStaticWorldsMap.count( nWorldID ) ); - } -} - -PWorld* PWorlds::LeaseWorld( uint32_t nWorldID, const bool nPreloadPhase ) -{ - PWorldsMap::iterator it; - - if ( nWorldID > PWorlds::mAptBaseWorldId ) - { - it = mOnDemandWorldsMap.find( nWorldID ); // Check if already loaded - if (( it != mOnDemandWorldsMap.end() ) && it->second ) // Dynamic world shall not have a NULL it->second - { - // if loaded - it->second->IncreaseUseCount(); - if ( gDevDebug ) - Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); - return it->second; - } - else // not loaded yet or invalid - { - PWorld* nWorld = new PWorld; - if ( ! nWorld->Load( nWorldID ) ) // Error when loading (shouldn't happen) - { - delete nWorld; - Console->Print( "% Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); - return NULL; - } - else - { - mOnDemandWorldsMap.insert( std::make_pair( nWorldID, nWorld ) ); - nWorld->IncreaseUseCount(); - if ( gDevDebug ) - Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); - return nWorld; - } - } - } - else - { - it = mStaticWorldsMap.find( nWorldID ); // Check if already loaded - if (( it == mStaticWorldsMap.end() ) && nPreloadPhase ) - { - mStaticWorldsMap.insert( std::make_pair( nWorldID, ( PWorld* )NULL ) ); - it = mStaticWorldsMap.find( nWorldID ); - } - if ( it != mStaticWorldsMap.end() ) - { - // if valid - if ( ! it->second ) // if not loaded yet - { - it->second = new PWorld; - if ( ! it->second->Load( nWorldID ) ) // Error when loading (shouldn't happen) - { - delete it->second; - Console->Print( "%s Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); - mStaticWorldsMap.erase( it ); // remove from valid worlds map - return NULL; - } - } - it->second->IncreaseUseCount(); - if ( gDevDebug ) - Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); - return it->second; - } - else // invalid worldID - { - return NULL; - } - } -} - -PWorld* PWorlds::GetWorld( uint32_t nWorldID ) -{ - PWorldsMap* tMap; - PWorldsMap::iterator it; - - tMap = (( nWorldID > PWorlds::mAptBaseWorldId ) ? &mOnDemandWorldsMap : &mStaticWorldsMap ); - - it = tMap->find( nWorldID ); - if (( it != tMap->end() ) && it->second ) - { - return it->second; - } - else - { - Console->Print( "%s PWorlds::GetWorld : Trying to get world %d without lease !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); - return NULL; - } -} - -void PWorlds::ReleaseWorld( uint32_t nWorldID ) // no dynamic unload is performed atm + don't forget spawned vhc ! -{ - PWorld* tWorld = GetWorld( nWorldID ); - if ( tWorld ) - { - if ( tWorld->GetUseCount() ) // this check is for dev time only - { - tWorld->DecreaseUseCount(); - if ( gDevDebug ) - Console->Print( "%s Released world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); - } - else - { - Console->Print( "%s PWorlds::ReleaseWorld : Trying to release world %d with use count 0 !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); - } - } - else - { - Console->Print( "%s PWorlds::ReleaseWorld : Generated the invalid get world %d", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); - } -} - -bool PWorlds::IsAppartment( uint32_t nWorldID ) -{ - return (( nWorldID > PWorlds::mAptBaseWorldId ) && IsValidWorld( nWorldID ) ); -} - -void PWorlds::Update() -{} - -void PWorlds::Shutdown() -{} - -uint32_t PWorlds::GetWorldIdFromWorldmap( uint8_t mapH, uint8_t mapV ) const -{ - uint32_t loc = 0; - if (( mapH < mOutdoorWorldmapHSize ) && ( mapV < mOutdoorWorldmapVSize ) ) - { - loc = mOutdoorBaseWorldId + mOutdoorWorldIdVIncrement * mapV + mapH; - if ( ! IsValidWorld( loc ) ) - loc = 0; - } - return loc; -} - -bool PWorlds::GetWorldmapFromWorldId( uint32_t nWorldId, uint8_t& mapH, uint8_t& mapV ) const -{ - if (( nWorldId >= mOutdoorBaseWorldId ) && ( nWorldId <= mOutdoorMaxWorldId ) ) - { - mapV = ( nWorldId - mOutdoorBaseWorldId ) / mOutdoorWorldIdVIncrement; - mapH = ( nWorldId - mOutdoorBaseWorldId ) % mOutdoorWorldIdVIncrement; - return true; - } - return false; -} +#include +#include "GameServer/Includes.hxx" +#include "GameServer/Definitions/Includes.hxx" +#include "Common/Includes.hxx" + +/**** PWorld ****/ +uint16_t const PWorld::mZoneOutLimitOffset = 0x100; +uint16_t const PWorld::mBottomZoneOutLimit = 0x4800 - PWorld::mZoneOutLimitOffset; +uint16_t const PWorld::mBottomZoneInLimit = 0x4a00; +uint16_t const PWorld::mTopZoneOutLimit = 0xb200 + PWorld::mZoneOutLimitOffset; +uint16_t const PWorld::mTopZoneInLimit = 0xb000; +const std::string EmptyString; + +PWorld::PWorld() +{ + mID = 0; + mUseCount = 0; + mWorldDataTemplate = NULL; +} + +PWorld::~PWorld() +{ +} + +bool PWorld::Load( uint32_t nWorldID ) +{ + std::string WorldTemplateName; + std::string tFileName; + bool tCheckOK; + + if ( nWorldID > PWorlds::mAptBaseWorldId ) + { + //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId); + int AptTmplID = Appartements->GetAptType( nWorldID ); + if ( !AptTmplID ) + { + Console->Print( "%s PWorld::Load - invalid apt %d", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID - PWorlds::mAptBaseWorldId ); + return false; + } + const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID ); + if ( !nAppDef ) + { + Console->Print( "%s PWorld::Load - invalid apt type %d", Console->ColorText( RED, BLACK, "[WARNING]" ), AptTmplID ); + return false; + } + WorldTemplateName = nAppDef->GetWorldName(); + + tFileName = std::string( "worlds/" ) + WorldTemplateName + ".dat"; + tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ); + if ( !tCheckOK ) + { + tFileName = WorldTemplateName + ".dat"; + tCheckOK = Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ); + } + if ( !tCheckOK ) + { + Console->Print( "%s PWorld::Load - unable to lease apt world %s (%s)", Console->ColorText( RED, BLACK, "[WARNING]" ), WorldTemplateName.c_str(), tFileName.c_str() ); + return false; + } + } + else + { + const PDefWorldFile* nWorldFileDef; + + if (( nWorldID > 90000 ) && ( nWorldID < 90017 ) ) // hardcoded holomatch hack + { + nWorldFileDef = NULL; + char worldName[19]; + int MatchID = nWorldID - 90000; + if ( MatchID > 8 ) // to care for Neofrag 1 & 2 + MatchID -= 8; + if ( MatchID > 6 ) + MatchID = 6; // holomatch 7 and 8 are same as 6 + snprintf( worldName, 19, "holomatch/neofrag%d", MatchID ); + WorldTemplateName = worldName; + } + else + { + nWorldFileDef = GameDefs->WorldFiles()->GetDef( nWorldID ); + if ( !nWorldFileDef ) + return false; + WorldTemplateName = nWorldFileDef->GetName(); + } + + const PDefWorld* tWorldDef = GameDefs->Worlds()->GetDef( nWorldID ); + if ( tWorldDef ) // should always be true here + { + if ( !( tWorldDef->GetDatFile().empty() ) ) + tFileName = tWorldDef->GetDatFile(); + else if ( nWorldFileDef ) + tFileName = nWorldFileDef->GetBasicFileName() + ".dat"; + else + { + tFileName = "worlds/"; + tFileName += WorldTemplateName; + tFileName += ".dat"; + } + } + else + return false; // should'nt happen here + + if ( !Worlds->LeaseWorldDataTemplate( WorldTemplateName, tFileName ) ) + return false; + } + + mWorldDataTemplate = Worlds->GetWorldDataTemplate( tFileName ); + if ( !mWorldDataTemplate ) + { + Console->Print( "%s PWorld::Load : Unexpected world %d not found error", Console->ColorText( RED, BLACK, "[WARNING]" ), nWorldID ); + return false; + } + + mID = nWorldID; + mSpawnedVehicles.SetLocation( nWorldID ); + // furniture & other world stuff loading here + Console->Print( "%s Loaded world %d", Console->ColorText( GREEN, BLACK, "[DEBUG]" ), nWorldID ); + return true; +} + +std::string PWorld::GetName() +{ + return ( mWorldDataTemplate ? mWorldDataTemplate->GetName() : EmptyString ); +} + +std::string PWorld::GetBspName() +{ + return ( mWorldDataTemplate ? mWorldDataTemplate->GetBspName() : EmptyString ); +} + +bool PWorld::IsAppartment() +{ + return mIsAppartment; +} + +const PFurnitureItemTemplate *PWorld::GetFurnitureItemTemplate( uint32_t nItemID ) +{ + return ( mWorldDataTemplate ? mWorldDataTemplate->GetFurnitureItem( nItemID ) : NULL ) ; +} + +const PDefWorldModel *PWorld::GetFurnitureItemModel(uint32_t nItemID) +{ + if ( mWorldDataTemplate ) + { + const PFurnitureItemTemplate* tFurniture = mWorldDataTemplate->GetFurnitureItem( nItemID ); + if ( tFurniture ) + return tFurniture->GetDefWorldModel(); + } + return nullptr; +} + +const PDoorTemplate *PWorld::GetDoor(uint32_t nDoorID) +{ + return (mWorldDataTemplate ? mWorldDataTemplate->GetDoor(nDoorID) : nullptr); +} + +bool PWorld::getPositionItemPosition(uint8_t PosID, float *pX, float *pY, float *pZ) +{ + return (mWorldDataTemplate ? mWorldDataTemplate->getPositionItemPosition(PosID, pX, pY, pZ) : false); +} + +bool PWorld::CharUseChair( int CharLocalID, uint32_t nItemID ) +{ + PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID ); + if ( it == mChairsInUseMap.end() ) // chair is free + { + if ( gDevDebug ) + Console->Print( "%s Localchar %d now using free chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID ); + mChairsInUseMap.insert( std::make_pair( nItemID, CharLocalID ) ); + return true; + } + else // chair is already in use + { + if ( gDevDebug ) + { + if ( it->second == CharLocalID ) + { + Console->Print( "%s Localchar %d already using chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID ); + } + else + { + Console->Print( "%s Localchar %d can't sit on chair %d used by localchar %d", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID, it->second ); + } + } + return ( it->second == CharLocalID ); + } +} + +void PWorld::CharLeaveChair( int CharLocalID, uint32_t nItemID ) +{ + PChairsInUseMap::iterator it = mChairsInUseMap.find( nItemID ); + if (( it != mChairsInUseMap.end() ) && ( it->second == CharLocalID ) ) // chair is in use by this char + { + if ( gDevDebug ) + Console->Print( "%s Localchar %d leaving chair %d.", Console->ColorText( CYAN, BLACK, "[DEBUG]" ), CharLocalID, nItemID ); + mChairsInUseMap.erase( it ); + } +} + +PClient* PWorld::GetClientByCharLocalId( uint32_t rawObjectId ) const +{ + // Temp implementation + return ClientManager->GetClientByCharLocalId( rawObjectId, mID ); +} + +PSpawnedVehicles *PWorld::GetSpawnedVehicles() +{ + return &mSpawnedVehicles; +} + +bool PWorld::CheckVhcNeedZoning( PVhcCoordinates const* nPos ) const +{ + if ( ( nPos->GetX() <= mBottomZoneOutLimit ) || ( nPos->GetX() >= mTopZoneOutLimit ) || ( nPos->GetY() <= mBottomZoneOutLimit ) || ( nPos->GetY() >= mTopZoneOutLimit ) ) + return true; + else + return false; +} + +uint32_t PWorld::GetVhcZoningDestination( PSpawnedVehicle const* nVhc, PVhcCoordinates* nPos ) const +{ + uint32_t destWorldId = 0; + int16_t vChange = 0; + int16_t hChange = 0; + PVhcCoordinates const vhcPos = nVhc->GetPosition(); + uint16_t posX = vhcPos.GetX(); + uint16_t posY = vhcPos.GetY(); + + if ( posX <= mBottomZoneOutLimit ) + { + vChange = 1; + } + else if ( posX >= mTopZoneOutLimit ) + { + vChange = -1; + } + + if ( posY <= mBottomZoneOutLimit ) + { + hChange = -1; + } + else if ( posY >= mTopZoneOutLimit ) + { + hChange = 1; + } + + if ( vChange || hChange ) + { + //Console->Print( YELLOW, BLACK, "[DEBUG] Limit Reached V:%d H:%d mapId:%d", vChange,hChange,mID ); + uint8_t currH = 0; + uint8_t currV = 0; + int16_t newH, newV; + + if ( Worlds->GetWorldmapFromWorldId( mID, currH, currV ) ) + { + //Console->Print( YELLOW, BLACK, "[DEBUG] current map pos V:%d H:%d", currV,currH ); + newH = currH + hChange; + if ( newH < 0 ) + newH = 0; + else if ( newH >= PWorlds::mOutdoorWorldmapHSize ) + newH = PWorlds::mOutdoorWorldmapHSize; + + newV = currV + vChange; + if ( newV < 0 ) + newV = 0; + else if ( newV >= PWorlds::mOutdoorWorldmapHSize ) + newV = PWorlds::mOutdoorWorldmapHSize; + + //Console->Print( YELLOW, BLACK, "[DEBUG] new map pos V:%d H:%d", newV,newH ); + if (( newH != currH ) || ( newV != currV ) ) + { + destWorldId = Worlds->GetWorldIdFromWorldmap( newH, newV ); + + if ( destWorldId && nPos ) + { + if ( vChange == 1 ) + posX = mTopZoneInLimit; + else if ( vChange == -1 ) + posX = mBottomZoneInLimit; + + if ( hChange == -1 ) + posY = mTopZoneInLimit; + else if ( hChange == 1 ) + posY = mBottomZoneInLimit; + + nPos->SetPosition( posY, vhcPos.GetZ(), posX, vhcPos.GetUD(), vhcPos.GetLR(), vhcPos.GetRoll(), vhcPos.GetAct(), vhcPos.GetUnknown(), vhcPos.GetFF() ); + } + } + } + } + + return destWorldId; +} + +const PNPCsMap *PWorld::GetNPCMap() const +{ + return (mWorldDataTemplate ? mWorldDataTemplate->GetNPCMap() : nullptr); +} + +const PNPCTemplate *PWorld::GetNPCTemplate(uint32_t nNPCID) const +{ + return (mWorldDataTemplate ? mWorldDataTemplate->GetNPC(nNPCID) : nullptr); +} + +/**** PWorlds ****/ +uint32_t const PWorlds::mNcSubwayWorldId = 1000; +uint32_t const PWorlds::mAptBaseWorldId = 100000; +uint32_t const PWorlds::mOutdoorBaseWorldId = 2001; +uint32_t const PWorlds::mOutdoorWorldIdVIncrement = 20; +uint8_t const PWorlds::mOutdoorWorldmapHSize = 16; +uint8_t const PWorlds::mOutdoorWorldmapVSize = 11; +uint32_t const PWorlds::mOutdoorMaxWorldId = PWorlds::mOutdoorBaseWorldId + PWorlds::mOutdoorWorldIdVIncrement * ( PWorlds::mOutdoorWorldmapVSize - 1 ) + PWorlds::mOutdoorWorldmapHSize - 1; + +PWorlds::PWorlds() +{ + mPreloadWorldsTemplates = false; // to be put as config option + mPreloadStaticWorlds = false; // to be put as config option +} + +PWorlds::~PWorlds() +{ + for ( PWorldsMap::iterator i = mStaticWorldsMap.begin(); i != mStaticWorldsMap.end(); i++ ) + if ( i->second ) + { + delete i->second; + } + for ( PWorldsMap::iterator i = mOnDemandWorldsMap.begin(); i != mOnDemandWorldsMap.end(); i++ ) + if ( i->second ) + { + delete i->second; + } + for ( PWorldDataTemplatesMap::iterator i = mWorldDataTemplatesMap.begin(); i != mWorldDataTemplatesMap.end(); i++ ) + if ( i->second ) + { + delete i->second; + } +} + +bool PWorlds::LeaseWorldDataTemplate( const std::string& nBspName, const std::string& nFileName, const bool nPreloadPhase ) +{ + PWorldDataTemplate* tWorldDataTemplate; + + PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName ); + if ( it == mWorldDataTemplatesMap.end() ) // template unkown yet + { + if ( nPreloadPhase ) // if in preload phase, we try to load it or make it known + { + tWorldDataTemplate = new PWorldDataTemplate; + if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName, !mPreloadWorldsTemplates ) ) + { + if ( mPreloadWorldsTemplates ) + { + mWorldDataTemplatesMap.insert( std::make_pair( nFileName, tWorldDataTemplate ) ); + tWorldDataTemplate->IncreaseUseCount(); + } + else + { + mWorldDataTemplatesMap.insert( std::make_pair( nFileName, ( PWorldDataTemplate* )NULL ) ); // NULL means file access OK but not preloaded yet + delete tWorldDataTemplate; + } + //return true; + } + else + { + delete tWorldDataTemplate; + return false; + } + } + else + { + return false; + } + } + else // template already known + { + if ( !it->second && !nPreloadPhase ) // template known but not already loaded and not in preload ? + { + tWorldDataTemplate = new PWorldDataTemplate; + if ( tWorldDataTemplate->LoadDatFile( nBspName, nFileName ) ) + { + it->second = tWorldDataTemplate; + } + else + { + Console->Print( "%s Invalid world data template file %s", Console->ColorText( RED, BLACK, "[ERROR]" ), nFileName.c_str() ); + mWorldDataTemplatesMap.erase( it ); + delete tWorldDataTemplate; + return false; + } + } + + if ( !nPreloadPhase ) + it->second->IncreaseUseCount(); + + //return true; + } + + return true; +} + +void PWorlds::ReleaseWorldDataTemplate( const std::string& nFileName ) +{ + PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName ); + if (( it != mWorldDataTemplatesMap.end() ) && it->second ) + { + it->second->DecreaseUseCount(); + } + else + Console->Print( "%s PWorlds::ReleaseWorldDataTemplate : try to relese not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() ); +} + +void PWorlds::UnloadWorldDataTemplate( const std::string& nFileName ) +{ + PWorldDataTemplate* tWorldDataTemplate; + + PWorldDataTemplatesMap::iterator it = mWorldDataTemplatesMap.find( nFileName ); + if (( it != mWorldDataTemplatesMap.end() ) && it->second ) + { + tWorldDataTemplate = it->second; + if ( mPreloadWorldsTemplates || ( tWorldDataTemplate->GetUseCount() > 0 ) ) + Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to unload template %s when use count not null ou preload set", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() ); + else + { + it->second = ( PWorldDataTemplate* )NULL; + delete tWorldDataTemplate; + } + } + else + Console->Print( "%s PWorlds::UnloadWorldDataTemplate : attempt to release not loaded template %s", Console->ColorText( RED, BLACK, "[Warning]" ), nFileName.c_str() ); +} + +PWorldDataTemplate* PWorlds::GetWorldDataTemplate( const std::string& nFileName ) +{ + PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( nFileName ); + if ( it != mWorldDataTemplatesMap.end() ) + return it->second; + else + return NULL; +} + +bool PWorlds::LoadWorlds() // once Load is done, only WorldDataTemplate registred in mWorldDataTemplatesMap +{ + // will be considered as valid + std::string tFileName; + std::string tBspName; + const PDefWorld* tDefWorld; + bool tCheckOK; + int ValidCount = 0, InvalidCount = 0, DblInvCount = 0; + int DatTmplCount, BadDatTmplCount; + std::set + InvalideFiles; + + // Appartment templates checking or preloading + std::map::const_iterator itAptStart = GameDefs->Appartements()->ConstIteratorBegin(); + std::map::const_iterator itAptEnd = GameDefs->Appartements()->ConstIteratorEnd(); + for ( std::map::const_iterator i = itAptStart; i != itAptEnd; i++ ) + { + tCheckOK = false; + tBspName = i->second->GetWorldName(); + tFileName = std::string( "worlds/" ) + tBspName + ".dat"; + if ( !InvalideFiles.count( tFileName ) ) + { + tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true ); + if ( !tCheckOK ) + { + InvalideFiles.insert( tFileName ); + if ( gDevDebug ) + Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() ); + } + } + if ( !tCheckOK ) // in case full path was given without omiting worlds/ or in another dir/archive ... + { + tFileName = tBspName + ".dat"; + if ( !InvalideFiles.count( tFileName ) ) + { + tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true ); + if ( !tCheckOK ) + { + InvalideFiles.insert( tFileName ); + ++DblInvCount; + } + } + } + + if ( tCheckOK ) + { + ++ValidCount; + if ( gDevDebug ) + Console->Print( GREEN, BLACK, "Template file %s for appartment %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); + } + else + { + ++InvalidCount; + if ( gDevDebug ) + Console->Print( RED, BLACK, "Template file %s for appartment %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); + } + } + + DatTmplCount = mWorldDataTemplatesMap.size(); + BadDatTmplCount = InvalideFiles.size(); + Console->Print( "%s %d valid appartement templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, DatTmplCount ); + if ( InvalidCount ) + Console->Print( "%s %d invalid appartement templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, BadDatTmplCount - DblInvCount ); + + // Static worlds & static worlds templates checking or preloading + ValidCount = InvalidCount = 0; + const PDefWorldFile* tDefWorldFile; + std::map::const_iterator itFilStart = GameDefs->WorldFiles()->ConstIteratorBegin(); + std::map::const_iterator itFilEnd = GameDefs->WorldFiles()->ConstIteratorEnd(); + for ( std::map::const_iterator i = itFilStart; i != itFilEnd; i++ ) + { + tDefWorldFile = i->second; + + tDefWorld = GameDefs->Worlds()->GetDef( tDefWorldFile->GetIndex() ); + if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too + { + tBspName = tDefWorldFile->GetName(); + if ( !( tDefWorld->GetDatFile().empty() ) ) + tFileName = tDefWorld->GetDatFile(); + else + tFileName = i->second->GetBasicFileName() + ".dat"; + + tCheckOK = false; + if ( !InvalideFiles.count( tFileName ) ) + { + tCheckOK = LeaseWorldDataTemplate( tBspName, tFileName, true ); + if ( !tCheckOK ) + { + InvalideFiles.insert( tFileName ); + if ( gDevDebug ) + Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() ); + } + } + + if ( tCheckOK ) + { + ++ValidCount; + if ( mPreloadStaticWorlds ) + { + LeaseWorld( tDefWorldFile->GetIndex(), true ); // This will make the world ready and kept in mem (use count always >0 ) + } + else + { + mStaticWorldsMap.insert( std::make_pair( tDefWorldFile->GetIndex(), ( PWorld* )NULL ) ); + } + if ( gDevDebug ) + Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); + } + else + { + ++InvalidCount; + if ( gDevDebug ) + Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), i->second->GetIndex(), i->second->GetName().c_str() ); + } + } + } + + // Hardcoded neofrag worlds ... oO ... and neofrag4.dat can't be found :-/ + for ( int i = 1; i <= 16; i++ ) + { + char worldName[19]; + int MatchID = i; + if ( MatchID > 8 ) // to care for Neofrag 1 & 2 + MatchID -= 8; + if ( MatchID > 6 ) + MatchID = 6; // holomatch 7 and 8 are same as 6 + snprintf( worldName, 19, "holomatch/neofrag%d", MatchID ); + + tDefWorld = GameDefs->Worlds()->GetDef( 90000 + i ); + if ( tDefWorld ) // we only care for worlds that are present in worldinfo.def too + { + if ( !( tDefWorld->GetDatFile().empty() ) ) + tFileName = tDefWorld->GetDatFile(); + else + { + tFileName = "worlds/"; + tFileName += worldName; + tFileName += ".dat"; + } + + tCheckOK = false; + if ( !InvalideFiles.count( tFileName ) ) + { + tCheckOK = LeaseWorldDataTemplate( worldName, tFileName, true ); + if ( !tCheckOK ) + { + InvalideFiles.insert( tFileName ); + if ( gDevDebug ) + Console->Print( RED, BLACK, "Template file %s invalid", tFileName.c_str() ); + } + } + + if ( tCheckOK ) + { + ++ValidCount; + if ( mPreloadStaticWorlds ) + { + LeaseWorld( 90000 + i, true ); // This will make the world ready and kept in mem (use count always >0 ) + } + else + { + mStaticWorldsMap.insert( std::make_pair( 90000 + i, ( PWorld* )NULL ) ); + } + if ( gDevDebug ) + Console->Print( GREEN, BLACK, "Template file %s for world %d (%s) loaded", tFileName.c_str(), 90000 + i, worldName ); + } + else + { + ++InvalidCount; + if ( gDevDebug ) + Console->Print( RED, BLACK, "Template file %s for world %d (%s) not available or invalid", tFileName.c_str(), 90000 + i, worldName ); + } + } + } + + Console->Print( "%s %d valid world templates checked (%d dat files)", Console->ColorText( GREEN, BLACK, "[Success]" ), ValidCount, mWorldDataTemplatesMap.size() - DatTmplCount ); + if ( InvalidCount ) + Console->Print( "%s %d invalid world templates rejected (%d dat files)", Console->ColorText( YELLOW, BLACK, "[Notice]" ), InvalidCount, InvalideFiles.size() - BadDatTmplCount - DblInvCount ); + Console->Print( "%s %d static worlds prepared", Console->ColorText( GREEN, BLACK, "[Success]" ), mStaticWorldsMap.size() ); + + // release memory if World templates preload activated, this cache that won't be used anymore + // if (mPreloadWorldsTemplates) Filesystem->ClearCache(); + + return true; +} + +bool PWorlds::IsValidWorld( uint32_t nWorldID ) const +{ + if ( nWorldID > PWorlds::mAptBaseWorldId ) + { + if ( mOnDemandWorldsMap.count( nWorldID ) ) // Check if already loaded + return true; + else //should better do a check using a PAppartements class object to get the world template + { + //int AptTmplID = Appartements->GetAptType(nWorldID - PWorlds::mAptBaseWorldId); + int AptTmplID = Appartements->GetAptType( nWorldID ); + if ( !AptTmplID ) + return false; + + const PDefAppartement* nAppDef = GameDefs->Appartements()->GetDef( AptTmplID ); + if ( !nAppDef ) + return false; + + std::string tFileName = "worlds/" + nAppDef->GetWorldName() + ".dat"; + PWorldDataTemplatesMap::const_iterator it = mWorldDataTemplatesMap.find( tFileName ); + return ( it != mWorldDataTemplatesMap.end() ); + } + } + else + { + if ( gDevDebug ) + Console->Print( "%s Checking validity for world %d : %s", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID, mStaticWorldsMap.count( nWorldID ) ? "OK" : "BAD" ); + return ( mStaticWorldsMap.count( nWorldID ) ); + } +} + +PWorld* PWorlds::LeaseWorld( uint32_t nWorldID, const bool nPreloadPhase ) +{ + PWorldsMap::iterator it; + + if ( nWorldID > PWorlds::mAptBaseWorldId ) + { + it = mOnDemandWorldsMap.find( nWorldID ); // Check if already loaded + if (( it != mOnDemandWorldsMap.end() ) && it->second ) // Dynamic world shall not have a NULL it->second + { + // if loaded + it->second->IncreaseUseCount(); + if ( gDevDebug ) + Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); + return it->second; + } + else // not loaded yet or invalid + { + PWorld* nWorld = new PWorld; + if ( ! nWorld->Load( nWorldID ) ) // Error when loading (shouldn't happen) + { + delete nWorld; + Console->Print( "% Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); + return NULL; + } + else + { + mOnDemandWorldsMap.insert( std::make_pair( nWorldID, nWorld ) ); + nWorld->IncreaseUseCount(); + if ( gDevDebug ) + Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); + return nWorld; + } + } + } + else + { + it = mStaticWorldsMap.find( nWorldID ); // Check if already loaded + if (( it == mStaticWorldsMap.end() ) && nPreloadPhase ) + { + mStaticWorldsMap.insert( std::make_pair( nWorldID, ( PWorld* )NULL ) ); + it = mStaticWorldsMap.find( nWorldID ); + } + if ( it != mStaticWorldsMap.end() ) + { + // if valid + if ( ! it->second ) // if not loaded yet + { + it->second = new PWorld; + if ( ! it->second->Load( nWorldID ) ) // Error when loading (shouldn't happen) + { + delete it->second; + Console->Print( "%s Could not load world %d - World now set as invalid", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); + mStaticWorldsMap.erase( it ); // remove from valid worlds map + return NULL; + } + } + it->second->IncreaseUseCount(); + if ( gDevDebug ) + Console->Print( "%s Leased world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); + return it->second; + } + else // invalid worldID + { + return NULL; + } + } +} + +PWorld* PWorlds::GetWorld( uint32_t nWorldID ) +{ + PWorldsMap* tMap; + PWorldsMap::iterator it; + + tMap = (( nWorldID > PWorlds::mAptBaseWorldId ) ? &mOnDemandWorldsMap : &mStaticWorldsMap ); + + it = tMap->find( nWorldID ); + if (( it != tMap->end() ) && it->second ) + { + return it->second; + } + else + { + Console->Print( "%s PWorlds::GetWorld : Trying to get world %d without lease !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); + return NULL; + } +} + +void PWorlds::ReleaseWorld( uint32_t nWorldID ) // no dynamic unload is performed atm + don't forget spawned vhc ! +{ + PWorld* tWorld = GetWorld( nWorldID ); + if ( tWorld ) + { + if ( tWorld->GetUseCount() ) // this check is for dev time only + { + tWorld->DecreaseUseCount(); + if ( gDevDebug ) + Console->Print( "%s Released world %d", Console->ColorText( GREEN, BLACK, "[Debug]" ), nWorldID ); + } + else + { + Console->Print( "%s PWorlds::ReleaseWorld : Trying to release world %d with use count 0 !", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); + } + } + else + { + Console->Print( "%s PWorlds::ReleaseWorld : Generated the invalid get world %d", Console->ColorText( RED, BLACK, "[Warning]" ), nWorldID ); + } +} + +bool PWorlds::IsAppartment( uint32_t nWorldID ) +{ + return (( nWorldID > PWorlds::mAptBaseWorldId ) && IsValidWorld( nWorldID ) ); +} + +void PWorlds::Update() +{} + +void PWorlds::Shutdown() +{} + +uint32_t PWorlds::GetWorldIdFromWorldmap( uint8_t mapH, uint8_t mapV ) const +{ + uint32_t loc = 0; + if (( mapH < mOutdoorWorldmapHSize ) && ( mapV < mOutdoorWorldmapVSize ) ) + { + loc = mOutdoorBaseWorldId + mOutdoorWorldIdVIncrement * mapV + mapH; + if ( ! IsValidWorld( loc ) ) + loc = 0; + } + return loc; +} + +bool PWorlds::GetWorldmapFromWorldId( uint32_t nWorldId, uint8_t& mapH, uint8_t& mapV ) const +{ + if (( nWorldId >= mOutdoorBaseWorldId ) && ( nWorldId <= mOutdoorMaxWorldId ) ) + { + mapV = ( nWorldId - mOutdoorBaseWorldId ) / mOutdoorWorldIdVIncrement; + mapH = ( nWorldId - mOutdoorBaseWorldId ) % mOutdoorWorldIdVIncrement; + return true; + } + return false; +} diff --git a/TinNS/Source/GameServer/Zoning.cxx b/TinNS/Source/GameServer/Zoning.cxx index 8f35f74..14923d9 100644 --- a/TinNS/Source/GameServer/Zoning.cxx +++ b/TinNS/Source/GameServer/Zoning.cxx @@ -1,36 +1,36 @@ -#include "GameServer/Includes.hxx" -#include "Common/Includes.hxx" - -// TODO: Put get the fallback world from config -// Check for file existence before sending info to client to avoid client crash and bad location in char info - -void SendZone(PClient *Client, uint32_t loc) -{ - //TODO : FIX case for worldroute and 5 missing id 505 - std::string worldName; - ConnectionTCP *Socket = Client->getTCPConn(); - //PChar *Char = Chars->GetChar(Client->GetCharID()); - - Socket->SetTimeOutValue(0xffff); - - PWorld* CurrentWorld = Worlds->GetWorld(loc); - if (CurrentWorld) - { - worldName = CurrentWorld->GetBspName(); - if (worldName.empty()) - { - worldName = "plaza/plaza_p1"; // Should be a config entry - Console->Print("Client %d: Empty name for world %d. Redirecting to %s", Console->ColorText(RED, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str()); - loc = 1; - } - } - else - { - worldName = "plaza/plaza_p1"; // Should be a config entry - Console->Print("Client %d: Invalid or not loaded world %d. Redirecting to %s", Console->ColorText(YELLOW, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str()); - loc = 1; - } - - PMessage* cMsg = MsgBuilder->BuildSendZoneTCPMsg(loc, &worldName); - Client->SendTCPMessage(cMsg); -} +#include "GameServer/Includes.hxx" +#include "Common/Includes.hxx" + +// TODO: Put get the fallback world from config +// Check for file existence before sending info to client to avoid client crash and bad location in char info + +void SendZone(PClient *Client, uint32_t loc) +{ + //TODO : FIX case for worldroute and 5 missing id 505 + std::string worldName; + ConnectionTCP *Socket = Client->getTCPConn(); + //PChar *Char = Chars->GetChar(Client->GetCharID()); + + Socket->SetTimeOutValue(0xffff); + + PWorld* CurrentWorld = Worlds->GetWorld(loc); + if (CurrentWorld) + { + worldName = CurrentWorld->GetBspName(); + if (worldName.empty()) + { + worldName = "plaza/plaza_p1"; // Should be a config entry + Console->Print("Client %d: Empty name for world %d. Redirecting to %s", Console->ColorText(RED, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str()); + loc = 1; + } + } + else + { + worldName = "plaza/plaza_p1"; // Should be a config entry + Console->Print("Client %d: Invalid or not loaded world %d. Redirecting to %s", Console->ColorText(YELLOW, BLACK, "Warning"), Client->GetID(), loc, worldName.c_str()); + loc = 1; + } + + PMessage* cMsg = MsgBuilder->BuildSendZoneTCPMsg(loc, &worldName); + Client->SendTCPMessage(cMsg); +} diff --git a/TinNS/Source/GameServer/Zoning.hxx b/TinNS/Source/GameServer/Zoning.hxx index 6f6950c..c006087 100644 --- a/TinNS/Source/GameServer/Zoning.hxx +++ b/TinNS/Source/GameServer/Zoning.hxx @@ -1,8 +1,8 @@ -#pragma once - -#include - -class PClient; - -//void SendZone(PClient *Client, PGameState *State,int loc); -void SendZone(PClient *Client, uint32_t loc); +#pragma once + +#include + +class PClient; + +//void SendZone(PClient *Client, PGameState *State,int loc); +void SendZone(PClient *Client, uint32_t loc); diff --git a/TinNS/Source/InfoServer/Accounts.cxx b/TinNS/Source/InfoServer/Accounts.cxx index 9872c0c..ee05c3d 100644 --- a/TinNS/Source/InfoServer/Accounts.cxx +++ b/TinNS/Source/InfoServer/Accounts.cxx @@ -1,407 +1,407 @@ -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -/* -NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE: -a_priv: -0 = unregistered user -1 = Registered user -30 = volunteer -50 = GM -100 = Admin - -a_status: -0 = Offline -1 = Online -2 = Banned -*/ - -/** Static members **/ -RegEx* PAccount::mUsernameRegexFilter = nullptr; -RegEx* PAccount::mPasswordRegexFilter = nullptr; - -bool PAccount::SetUsernameRegexFilter(const char* RegexStr) -{ - if(mUsernameRegexFilter) - { - delete mUsernameRegexFilter; - mUsernameRegexFilter = NULL; - } - - if(RegexStr) - { - try { - mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); - } - catch (...) { - return false; - } - } - return true; -} - -bool PAccount::SetPasswordRegexFilter(const char* RegexStr) -{ - if(mPasswordRegexFilter) - { - delete mPasswordRegexFilter; - mPasswordRegexFilter = NULL; - } - - if(RegexStr) - { - try { - mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); - } - catch (...) { - return false; - } - } - return true; -} - -bool PAccount::IsUsernameWellFormed(const char *Username) -{ - if(mUsernameRegexFilter) - { - return mUsernameRegexFilter->Search(Username); - } - else - return true; -} - -bool PAccount::IsPasswordWellFormed(const char *Password) -{ - if(mPasswordRegexFilter) - { - return mPasswordRegexFilter->Search(Password); - } - else - return true; -} - -/** Instance members **/ -PAccount::PAccount() -{ - mID = 0; - mLevel = PAL_BANNED; - mStatus = PAS_OFFLINE; - mBannedUntil = 0; -} - -PAccount::PAccount(const uint32_t AccountId) -{ - char query[256]; - mID = 0; - snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId); - LoadFromQuery(query); -} - -PAccount::PAccount(const char *Username) -{ - char query[256]; - mID = 0; - if(IsUsernameWellFormed(Username)) { - char escUsername[256]; - MySQL->EscapeString(Username, escUsername, 256); - snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername); - LoadFromQuery(query); - } -} - -bool PAccount::LoadFromQuery(char* query) -{ - MYSQL_ROW row = 0; - MYSQL_RES *result = 0; - - bool FinalResult = false; - - //result = MySQL->InfoResQuery(query); - result = MySQL->ResQuery(query); - if(result == NULL) - { - Console->Print(RED, BLACK, "Failed to load AccountData from SQL"); - //MySQL->ShowInfoSQLError(); - MySQL->ShowSQLError(); - return false; - } - - if((row = mysql_fetch_row(result))) - { - mID = atoi(row[a_id]); - mName = row[a_username]; - mPassword = row[a_password]; - - mBannedUntil = atoi(row[a_bandate]); - if(mBannedUntil > std::time(NULL)) - { - mStatus = PAS_BANNED; - mLevel = PAL_BANNED; - } - else - { - mStatus = PAS_OFFLINE; - mLevel = atoi(row[a_priv]); - } - - FinalResult = true; - } - else - { -Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load..."); - } - - //MySQL->FreeInfoSQLResult(result); - MySQL->FreeSQLResult(result); - return FinalResult; -} - -uint32_t PAccount::GetID() const -{ - return mID; -} - -bool PAccount::SetName(const std::string &Username) -{ - if(IsUsernameWellFormed(Username.c_str())) - { - mName = Username; - return true; - } - else - { - return false; - } -} - -const std::string &PAccount::GetName() const -{ - return mName; -} - -bool PAccount::SetPassword(const std::string &Password) -{ - if(IsPasswordWellFormed(Password.c_str())) - { - mPassword = Password; - return true; - } - else - { - return false; - } -} - -bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key) -{ - char Pass[128]; - - if(DecodePassword(PasswordData, PassLen, Key, Pass)) - { - return SetPassword((std::string)Pass); - } - else - { - Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); - return false; - } -} - -const std::string &PAccount::GetPassword() const -{ - return mPassword; -} - -bool PAccount::SetLevel(int newLevel) -{ - if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN)) - { - mLevel = newLevel; - return true; - } - else - { - return false; - } -} - -int32_t PAccount::GetLevel() const -{ - return mLevel; -} - -std::string PAccount::GetLevelString() const -{ - switch(mLevel) - { - case PAL_BANNED : return "banned"; - case PAL_UNREGPLAYER : return "unregplayer"; - case PAL_REGPLAYER : return "regplayer"; - case PAL_VOLUNTEER : return "volunteer"; - case PAL_GM : return "gm"; - case PAL_ADMIN : return "admin"; - } - - return "custom"; -} - -bool PAccount::SetStatus(PAccountStatus Status) -{ - mStatus = Status; - return true; -} - -PAccountStatus PAccount::GetStatus() const -{ - return mStatus; -} - -bool PAccount::SetBannedUntilTime(std::time_t BannedUntil) -{ - if ((BannedUntil == 0) || (BannedUntil > std::time(NULL))) - { - mBannedUntil = BannedUntil; - return true; - } - else - { - return false; - } -} - -bool PAccount::IsBanned() const -{ - return (mBannedUntil > std::time(nullptr)); -} - -bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword) -{ - ClearPassword[0] = 0; - - if(PassLen < 128) - { - if(Key[0]>7) // TODO: >7 correct? - { - for(int i=0; i>1] = (char)(((PasswordData[i]&0xf0)>>4) - +((PasswordData[i+1]&0x0f)<<4)-Key[0]); - ClearPassword[PassLen>>1]=0; - } - else - { - for(int i=0; iPrint(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); - return false; - } -} - -bool PAccount::Authenticate(const char *Password) const -{ - if(mID == 0) // User doesn't exist and that hasn't been checked ! - { - Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str()); - return false; - } - - return(mPassword == Password); -} - -bool PAccount::Create() -{ - if(Save(true)) { - //mID = MySQL->GetLastInfoInsertId(); - mID = MySQL->GetLastInsertId(); - return true; - } - else - { - return false; - } -} - -bool PAccount::Save(bool CreateMode) -{ - char escUsername[256]; - char escPassword[256]; - MySQL->EscapeString(mName.c_str(), escUsername, 256); - MySQL->EscapeString(mPassword.c_str(), escPassword, 256); - - std::string Query; - Query = CreateMode ? "INSERT INTO" : "UPDATE"; - Query += " accounts SET "; - Query += Ssprintf(" a_username='%s', a_password = '%s'", escUsername, escPassword); - Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil); - if(!CreateMode ) - { - Query += Ssprintf(" a_lastused = NOW()"); - Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID); - } - else - Query += Ssprintf(" a_creationdate = NOW()"); - - //if(MySQL->InfoQuery(Query.c_str())) - if(MySQL->Query(Query.c_str())) - { - Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID); - //MySQL->ShowInfoSQLError(); - MySQL->ShowSQLError(); - return false; - } - return true; -} - -std::string PAccount::GetBannedTime() const -{ - const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"}; - - std::time_t timediff = mBannedUntil - std::time(NULL); - if(timediff <=0) - { - return "0 more seconds. Please relog"; - } - - long counter; - int type; - - if(timediff > 86400) // days - { - counter = timediff / 86400; - type = 3; - } - else if(timediff > 3600) // hours - { - counter = timediff / 3600; - type = 2; - } - else if(timediff > 60) // Minutes - { - counter = timediff / 60; - type = 1; - } - else // Seconds - { - counter = timediff; - type = 0; - } - - return Ssprintf("%d more %s", counter, unit[type]); -} +#include "InfoServer/Includes.hxx" +#include "Common/Includes.hxx" + +/* +NOTE ABOUT ACCESS LEVELS IN THE MYSQL DATABASE: +a_priv: +0 = unregistered user +1 = Registered user +30 = volunteer +50 = GM +100 = Admin + +a_status: +0 = Offline +1 = Online +2 = Banned +*/ + +/** Static members **/ +RegEx* PAccount::mUsernameRegexFilter = nullptr; +RegEx* PAccount::mPasswordRegexFilter = nullptr; + +bool PAccount::SetUsernameRegexFilter(const char* RegexStr) +{ + if(mUsernameRegexFilter) + { + delete mUsernameRegexFilter; + mUsernameRegexFilter = NULL; + } + + if(RegexStr) + { + try { + mUsernameRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); + } + catch (...) { + return false; + } + } + return true; +} + +bool PAccount::SetPasswordRegexFilter(const char* RegexStr) +{ + if(mPasswordRegexFilter) + { + delete mPasswordRegexFilter; + mPasswordRegexFilter = NULL; + } + + if(RegexStr) + { + try { + mPasswordRegexFilter = new RegEx(RegexStr, PCRE_CASELESS); + } + catch (...) { + return false; + } + } + return true; +} + +bool PAccount::IsUsernameWellFormed(const char *Username) +{ + if(mUsernameRegexFilter) + { + return mUsernameRegexFilter->Search(Username); + } + else + return true; +} + +bool PAccount::IsPasswordWellFormed(const char *Password) +{ + if(mPasswordRegexFilter) + { + return mPasswordRegexFilter->Search(Password); + } + else + return true; +} + +/** Instance members **/ +PAccount::PAccount() +{ + mID = 0; + mLevel = PAL_BANNED; + mStatus = PAS_OFFLINE; + mBannedUntil = 0; +} + +PAccount::PAccount(const uint32_t AccountId) +{ + char query[256]; + mID = 0; + snprintf(query, 256, "SELECT * FROM accounts WHERE a_id = %d LIMIT 1;", AccountId); + LoadFromQuery(query); +} + +PAccount::PAccount(const char *Username) +{ + char query[256]; + mID = 0; + if(IsUsernameWellFormed(Username)) { + char escUsername[256]; + MySQL->EscapeString(Username, escUsername, 256); + snprintf(query, 256, "SELECT * FROM accounts WHERE a_username = '%s' LIMIT 1;", escUsername); + LoadFromQuery(query); + } +} + +bool PAccount::LoadFromQuery(char* query) +{ + MYSQL_ROW row = 0; + MYSQL_RES *result = 0; + + bool FinalResult = false; + + //result = MySQL->InfoResQuery(query); + result = MySQL->ResQuery(query); + if(result == NULL) + { + Console->Print(RED, BLACK, "Failed to load AccountData from SQL"); + //MySQL->ShowInfoSQLError(); + MySQL->ShowSQLError(); + return false; + } + + if((row = mysql_fetch_row(result))) + { + mID = atoi(row[a_id]); + mName = row[a_username]; + mPassword = row[a_password]; + + mBannedUntil = atoi(row[a_bandate]); + if(mBannedUntil > std::time(NULL)) + { + mStatus = PAS_BANNED; + mLevel = PAL_BANNED; + } + else + { + mStatus = PAS_OFFLINE; + mLevel = atoi(row[a_priv]); + } + + FinalResult = true; + } + else + { +Console->Print(YELLOW, BLACK, "Failed to load AccountData from SQL; Nothing to load..."); + } + + //MySQL->FreeInfoSQLResult(result); + MySQL->FreeSQLResult(result); + return FinalResult; +} + +uint32_t PAccount::GetID() const +{ + return mID; +} + +bool PAccount::SetName(const std::string &Username) +{ + if(IsUsernameWellFormed(Username.c_str())) + { + mName = Username; + return true; + } + else + { + return false; + } +} + +const std::string &PAccount::GetName() const +{ + return mName; +} + +bool PAccount::SetPassword(const std::string &Password) +{ + if(IsPasswordWellFormed(Password.c_str())) + { + mPassword = Password; + return true; + } + else + { + return false; + } +} + +bool PAccount::SetPasswordEncoded(const uint8_t* PasswordData, int PassLen, const uint8_t* Key) +{ + char Pass[128]; + + if(DecodePassword(PasswordData, PassLen, Key, Pass)) + { + return SetPassword((std::string)Pass); + } + else + { + Console->Print(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); + return false; + } +} + +const std::string &PAccount::GetPassword() const +{ + return mPassword; +} + +bool PAccount::SetLevel(int newLevel) +{ + if((newLevel >= PAL_BANNED) && (newLevel <= PAL_ADMIN)) + { + mLevel = newLevel; + return true; + } + else + { + return false; + } +} + +int32_t PAccount::GetLevel() const +{ + return mLevel; +} + +std::string PAccount::GetLevelString() const +{ + switch(mLevel) + { + case PAL_BANNED : return "banned"; + case PAL_UNREGPLAYER : return "unregplayer"; + case PAL_REGPLAYER : return "regplayer"; + case PAL_VOLUNTEER : return "volunteer"; + case PAL_GM : return "gm"; + case PAL_ADMIN : return "admin"; + } + + return "custom"; +} + +bool PAccount::SetStatus(PAccountStatus Status) +{ + mStatus = Status; + return true; +} + +PAccountStatus PAccount::GetStatus() const +{ + return mStatus; +} + +bool PAccount::SetBannedUntilTime(std::time_t BannedUntil) +{ + if ((BannedUntil == 0) || (BannedUntil > std::time(NULL))) + { + mBannedUntil = BannedUntil; + return true; + } + else + { + return false; + } +} + +bool PAccount::IsBanned() const +{ + return (mBannedUntil > std::time(nullptr)); +} + +bool PAccount::DecodePassword(const uint8_t* PasswordData, int PassLen, const uint8_t *Key, char* ClearPassword) +{ + ClearPassword[0] = 0; + + if(PassLen < 128) + { + if(Key[0]>7) // TODO: >7 correct? + { + for(int i=0; i>1] = (char)(((PasswordData[i]&0xf0)>>4) + +((PasswordData[i+1]&0x0f)<<4)-Key[0]); + ClearPassword[PassLen>>1]=0; + } + else + { + for(int i=0; iPrint(RED, BLACK, "[Error]: user %s : malformed auth data (size=%d)", mName.c_str(), PassLen); + return false; + } +} + +bool PAccount::Authenticate(const char *Password) const +{ + if(mID == 0) // User doesn't exist and that hasn't been checked ! + { + Console->Print(RED, BLACK, "[Bug]: user %s doesn't exist and was not checked by code !", mName.c_str()); + return false; + } + + return(mPassword == Password); +} + +bool PAccount::Create() +{ + if(Save(true)) { + //mID = MySQL->GetLastInfoInsertId(); + mID = MySQL->GetLastInsertId(); + return true; + } + else + { + return false; + } +} + +bool PAccount::Save(bool CreateMode) +{ + char escUsername[256]; + char escPassword[256]; + MySQL->EscapeString(mName.c_str(), escUsername, 256); + MySQL->EscapeString(mPassword.c_str(), escPassword, 256); + + std::string Query; + Query = CreateMode ? "INSERT INTO" : "UPDATE"; + Query += " accounts SET "; + Query += Ssprintf(" a_username='%s', a_password = '%s'", escUsername, escPassword); + Query += Ssprintf(", a_priv = %d, a_status = %d, a_bandate = %d", mLevel, mStatus, mBannedUntil); + if(!CreateMode ) + { + Query += Ssprintf(" a_lastused = NOW()"); + Query += Ssprintf(" WHERE a_id = %d LIMIT 1", mID); + } + else + Query += Ssprintf(" a_creationdate = NOW()"); + + //if(MySQL->InfoQuery(Query.c_str())) + if(MySQL->Query(Query.c_str())) + { + Console->Print(RED, BLACK, "[Error] Failed to %s account %s (id %d)", CreateMode ? "create" : "update", mName.c_str(), mID); + //MySQL->ShowInfoSQLError(); + MySQL->ShowSQLError(); + return false; + } + return true; +} + +std::string PAccount::GetBannedTime() const +{ + const char* unit[5] = {"seconds", "minutes", "hours", "days", "weeks"}; + + std::time_t timediff = mBannedUntil - std::time(NULL); + if(timediff <=0) + { + return "0 more seconds. Please relog"; + } + + long counter; + int type; + + if(timediff > 86400) // days + { + counter = timediff / 86400; + type = 3; + } + else if(timediff > 3600) // hours + { + counter = timediff / 3600; + type = 2; + } + else if(timediff > 60) // Minutes + { + counter = timediff / 60; + type = 1; + } + else // Seconds + { + counter = timediff; + type = 0; + } + + return Ssprintf("%d more %s", counter, unit[type]); +} diff --git a/TinNS/Source/InfoServer/Accounts.hxx b/TinNS/Source/InfoServer/Accounts.hxx index 96bd185..6ad130c 100644 --- a/TinNS/Source/InfoServer/Accounts.hxx +++ b/TinNS/Source/InfoServer/Accounts.hxx @@ -1,103 +1,103 @@ -#pragma once - -#include -#include -#include - -class RegEx; - -/* -0 = unregistered user -1 = Registered user -30 = volunteer -50 = GM -100 = Admin -*/ - -// New way of AccountLevel handling: -// Every level is possible, the following values are only edge values. We need a bit control about that -#define PAL_BANNED -1 -#define PAL_UNREGPLAYER 0 -#define PAL_REGPLAYER 1 -#define PAL_VOLUNTEER 30 -#define PAL_GM 50 -#define PAL_ADMIN 100 - -// Max number of char slots per account -#define MAX_CHARS_PER_ACCOUNT 4 - -/* -0 = Offline -1 = Online -2 = Banned -*/ - -enum PAccountStatus -{ - PAS_OFFLINE = 0, - PAS_ONLINE = 1, - PAS_BANNED = 2 -}; - -class PAccount -{ - private : - // SQL Layout - enum { - a_id, - a_username, - a_password, - a_priv, - a_status, - a_bandate, - a_emailaddress, - a_creationdate, - a_lastused - }; - - // static members - static RegEx *mUsernameRegexFilter; - static RegEx *mPasswordRegexFilter; - - // instance members - uint32_t mID; - std::string mName; - std::string mPassword; - int32_t mLevel; - PAccountStatus mStatus; - std::time_t mBannedUntil; - - bool LoadFromQuery(char *query); - bool DecodePassword(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key, char *ClearPassword); - -public: - PAccount(); - PAccount(const uint32_t AccountId); - PAccount(const char *Username); - - static bool SetUsernameRegexFilter(const char *RegexStr); - static bool SetPasswordRegexFilter(const char *RegexStr); - static bool IsUsernameWellFormed(const char *Username); - static bool IsPasswordWellFormed(const char *Password); - - uint32_t GetID() const; - bool SetName(const std::string &Pass); - const std::string &GetName() const; - bool SetPassword(const std::string &Pass); - bool SetPasswordEncoded(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key); - const std::string &GetPassword() const; - bool SetLevel(int32_t newLevel); - int32_t GetLevel() const; - std::string GetLevelString() const; - bool SetStatus(PAccountStatus Status); - PAccountStatus GetStatus() const; - bool SetBannedUntilTime(std::time_t BannedUntil); - bool IsBanned() const; - std::string GetBannedTime() const; - bool Authenticate(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key); - bool Authenticate(const char *Password) const; - bool Create(); - bool Save(bool CreateMode = false); - - //u32 GetCharIdBySlot(const u32 SlotId); -}; +#pragma once + +#include +#include +#include + +class RegEx; + +/* +0 = unregistered user +1 = Registered user +30 = volunteer +50 = GM +100 = Admin +*/ + +// New way of AccountLevel handling: +// Every level is possible, the following values are only edge values. We need a bit control about that +#define PAL_BANNED -1 +#define PAL_UNREGPLAYER 0 +#define PAL_REGPLAYER 1 +#define PAL_VOLUNTEER 30 +#define PAL_GM 50 +#define PAL_ADMIN 100 + +// Max number of char slots per account +#define MAX_CHARS_PER_ACCOUNT 4 + +/* +0 = Offline +1 = Online +2 = Banned +*/ + +enum PAccountStatus +{ + PAS_OFFLINE = 0, + PAS_ONLINE = 1, + PAS_BANNED = 2 +}; + +class PAccount +{ + private : + // SQL Layout + enum { + a_id, + a_username, + a_password, + a_priv, + a_status, + a_bandate, + a_emailaddress, + a_creationdate, + a_lastused + }; + + // static members + static RegEx *mUsernameRegexFilter; + static RegEx *mPasswordRegexFilter; + + // instance members + uint32_t mID; + std::string mName; + std::string mPassword; + int32_t mLevel; + PAccountStatus mStatus; + std::time_t mBannedUntil; + + bool LoadFromQuery(char *query); + bool DecodePassword(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key, char *ClearPassword); + +public: + PAccount(); + PAccount(const uint32_t AccountId); + PAccount(const char *Username); + + static bool SetUsernameRegexFilter(const char *RegexStr); + static bool SetPasswordRegexFilter(const char *RegexStr); + static bool IsUsernameWellFormed(const char *Username); + static bool IsPasswordWellFormed(const char *Password); + + uint32_t GetID() const; + bool SetName(const std::string &Pass); + const std::string &GetName() const; + bool SetPassword(const std::string &Pass); + bool SetPasswordEncoded(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key); + const std::string &GetPassword() const; + bool SetLevel(int32_t newLevel); + int32_t GetLevel() const; + std::string GetLevelString() const; + bool SetStatus(PAccountStatus Status); + PAccountStatus GetStatus() const; + bool SetBannedUntilTime(std::time_t BannedUntil); + bool IsBanned() const; + std::string GetBannedTime() const; + bool Authenticate(const uint8_t *PasswordData, int32_t PassLen, const uint8_t *Key); + bool Authenticate(const char *Password) const; + bool Create(); + bool Save(bool CreateMode = false); + + //u32 GetCharIdBySlot(const u32 SlotId); +}; diff --git a/TinNS/Source/InfoServer/Client.cxx b/TinNS/Source/InfoServer/Client.cxx index 12ea790..7a6898a 100644 --- a/TinNS/Source/InfoServer/Client.cxx +++ b/TinNS/Source/InfoServer/Client.cxx @@ -1,84 +1,84 @@ -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -PClient::PClient(int32_t Index) -{ - mIndex = Index; - mConnection = PCC_NONE; - mAccountID = 0; -} - -PClient::~PClient() -{ - if(m_TCPConnection) - { - delete m_TCPConnection; - } -} - -int32_t PClient::GetIndex() const -{ - return mIndex; -} - -void PClient::setTCPConnection(ConnectionTCP *conn) -{ - m_TCPConnection = conn; mConnection = PCC_INFO; -} - -ConnectionTCP *PClient::getTCPConn() const -{ - return m_TCPConnection; -} - -int32_t PClient::GetConnection() const -{ - return mConnection; -} - -const char *PClient::GetAddress() const -{ - return m_TCPConnection->getRemoteAddress(); -} - -void PClient::setAccountID(uint32_t nAccountID) -{ - mAccountID = nAccountID; -} - -uint32_t PClient::getAccountID() -{ - return mAccountID; -} - -void PClient::InfoDisconnect() -{ - if(m_TCPConnection) - { - delete m_TCPConnection; - } - m_TCPConnection = 0; - - //mConnection &= ~PCC_INFO; - mConnection = PCC_NONE; - mAccountID = 0; -} - -void PClient::Update() -{ - if(m_TCPConnection) - { - if(m_TCPConnection->timeOut()) - { - Console->Print("InfoSocket: Client %i: timeout", mIndex); - InfoServer->ClientDisconnected(this); - } - else - { - if(!m_TCPConnection->update()) - { - InfoServer->ClientDisconnected(this); - } - } - } -} +#include "InfoServer/Includes.hxx" +#include "Common/Includes.hxx" + +PClient::PClient(int32_t Index) +{ + mIndex = Index; + mConnection = PCC_NONE; + mAccountID = 0; +} + +PClient::~PClient() +{ + if(m_TCPConnection) + { + delete m_TCPConnection; + } +} + +int32_t PClient::GetIndex() const +{ + return mIndex; +} + +void PClient::setTCPConnection(ConnectionTCP *conn) +{ + m_TCPConnection = conn; mConnection = PCC_INFO; +} + +ConnectionTCP *PClient::getTCPConn() const +{ + return m_TCPConnection; +} + +int32_t PClient::GetConnection() const +{ + return mConnection; +} + +const char *PClient::GetAddress() const +{ + return m_TCPConnection->getRemoteAddress(); +} + +void PClient::setAccountID(uint32_t nAccountID) +{ + mAccountID = nAccountID; +} + +uint32_t PClient::getAccountID() +{ + return mAccountID; +} + +void PClient::InfoDisconnect() +{ + if(m_TCPConnection) + { + delete m_TCPConnection; + } + m_TCPConnection = 0; + + //mConnection &= ~PCC_INFO; + mConnection = PCC_NONE; + mAccountID = 0; +} + +void PClient::Update() +{ + if(m_TCPConnection) + { + if(m_TCPConnection->timeOut()) + { + Console->Print("InfoSocket: Client %i: timeout", mIndex); + InfoServer->ClientDisconnected(this); + } + else + { + if(!m_TCPConnection->update()) + { + InfoServer->ClientDisconnected(this); + } + } + } +} diff --git a/TinNS/Source/InfoServer/Client.hxx b/TinNS/Source/InfoServer/Client.hxx index 44d284b..4d7b884 100644 --- a/TinNS/Source/InfoServer/Client.hxx +++ b/TinNS/Source/InfoServer/Client.hxx @@ -1,33 +1,33 @@ -#pragma once - -#include - -class ConnectionTCP; - -enum PClientConnection -{ - PCC_NONE = 0, - PCC_INFO = 1 -}; - -class PClient { -private: - ConnectionTCP* m_TCPConnection; - int32_t mIndex; - int32_t mConnection; - uint32_t mAccountID; - -public: - PClient(int32_t Index); - ~PClient(); - - int32_t GetIndex() const; - void setTCPConnection(ConnectionTCP *conn); - ConnectionTCP *getTCPConn() const; - int32_t GetConnection() const; - const char *GetAddress() const; - void setAccountID(uint32_t nAccountID); - uint32_t getAccountID(); - void InfoDisconnect(); - void Update(); -}; +#pragma once + +#include + +class ConnectionTCP; + +enum PClientConnection +{ + PCC_NONE = 0, + PCC_INFO = 1 +}; + +class PClient { +private: + ConnectionTCP* m_TCPConnection; + int32_t mIndex; + int32_t mConnection; + uint32_t mAccountID; + +public: + PClient(int32_t Index); + ~PClient(); + + int32_t GetIndex() const; + void setTCPConnection(ConnectionTCP *conn); + ConnectionTCP *getTCPConn() const; + int32_t GetConnection() const; + const char *GetAddress() const; + void setAccountID(uint32_t nAccountID); + uint32_t getAccountID(); + void InfoDisconnect(); + void Update(); +}; diff --git a/TinNS/Source/InfoServer/ConfigTemplate.hxx b/TinNS/Source/InfoServer/ConfigTemplate.hxx index 92eced8..8e4ac9a 100644 --- a/TinNS/Source/InfoServer/ConfigTemplate.hxx +++ b/TinNS/Source/InfoServer/ConfigTemplate.hxx @@ -1,30 +1,30 @@ -#pragma once - -static const char *InfoConfigTemplate[][2] = { - // {option_name, default_value} if default_value is empty string, it means option is mandatory - // List ends with empty string for option_name - {"sql_host", "127.0.0.1"}, // should be renanmed to info_sql_host - {"sql_port", "3306"}, // should be renanmed to info_sql_port - {"sql_username", ""}, // should be renanmed to info_sql_username - {"sql_password", ""}, // should be renanmed to info_sql_password - {"global_sql_database", "infoserver"}, // should be renanmed to info_sql_database - {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive. - {"auto_accounts", "0"}, - {"infoserver_port", "7000"}, - {"gameserver_livecheck", "60"}, - {"minlevel", "0"}, - {"maxclients", "50"}, - {"require_validation", "0"}, - {"isc_method", "1"}, - {"isc_infoserverport", "9991"}, - {"isc_connect_pw", "changeme"}, - {"username_filter", "^[a-z][\\w\\-]{2,14}$"}, - {"password_filter", "^[[:graph:]]{3,15}$"}, - {"sqlite_databasefile", "infoDB.s3db"}, - {"database_type", "sqlite"}, - -// For futur use: -// {"max_chars_per_account", "4"}, - - {"", ""} // do not change this line (end mark) -}; +#pragma once + +static const char *InfoConfigTemplate[][2] = { + // {option_name, default_value} if default_value is empty string, it means option is mandatory + // List ends with empty string for option_name + {"sql_host", "127.0.0.1"}, // should be renanmed to info_sql_host + {"sql_port", "3306"}, // should be renanmed to info_sql_port + {"sql_username", ""}, // should be renanmed to info_sql_username + {"sql_password", ""}, // should be renanmed to info_sql_password + {"global_sql_database", "infoserver"}, // should be renanmed to info_sql_database + {"mysql_wait_timeout", "28800"}, // value of the wait_timout system variable from the MySQL server (same for game & info DB atm). 0 to disable keepalive. + {"auto_accounts", "0"}, + {"infoserver_port", "7000"}, + {"gameserver_livecheck", "60"}, + {"minlevel", "0"}, + {"maxclients", "50"}, + {"require_validation", "0"}, + {"isc_method", "1"}, + {"isc_infoserverport", "9991"}, + {"isc_connect_pw", "changeme"}, + {"username_filter", "^[a-z][\\w\\-]{2,14}$"}, + {"password_filter", "^[[:graph:]]{3,15}$"}, + {"sqlite_databasefile", "infoDB.s3db"}, + {"database_type", "sqlite"}, + +// For futur use: +// {"max_chars_per_account", "4"}, + + {"", ""} // do not change this line (end mark) +}; diff --git a/TinNS/Source/InfoServer/Includes.cxx b/TinNS/Source/InfoServer/Includes.cxx index 28ea027..d61e1a2 100644 --- a/TinNS/Source/InfoServer/Includes.cxx +++ b/TinNS/Source/InfoServer/Includes.cxx @@ -1,185 +1,185 @@ -#include -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -const char ServerVersion[] = TINNS_INFO_VERSION; -const char SVNRevision[] = TINNS_SVN_REVISION; - -ServerSocket* ServerSock = 0; -PMySQL *MySQL = 0; -PConsole *Console = 0; -PServer *Server = 0; -PConfig *Config = 0; -PInfoServer *InfoServer = 0; -//PAccounts *Accounts = 0; // To be removed - -bool Init() -{ - Console = new PConsole("log/infoserver.log"); // Make that from config file !!! - Console->Print("Starting TinNS Infoserver"); - Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\"); - Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |"); - Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |"); - Console->Print(WHITE, BLUE, "| maintainer Akiko |"); - Console->Print(WHITE, BLUE, "| ========================================== |"); - Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |"); - Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |"); - Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |"); - Console->Print(WHITE, BLUE, "| - Namikon - Balm |"); - Console->Print(WHITE, BLUE, "| - Hammag |"); - Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); - Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |"); - Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |"); - Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); - Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |"); - Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/"); - - //char svnrev[10]; - //GetSVNRev(svnrev); - Console->LPrint("You are running TinNS Infoserver version"); - Console->LPrint(GREEN, BLACK, " %s", ServerVersion); - Console->LPrint(WHITE, BLACK, " - SVN Rev"); - Console->LPrint(GREEN, BLACK, " %s", SVNRevision); - Console->LClose(); - - Config = new PConfig(); - if(!Config->LoadOptions(InfoConfigTemplate, "./conf/infoserver.conf")) - return false; //Shutdown(); - if(!AdditionnalConfigChecks()) - return false; //Shutdown(); - - ServerSock = new ServerSocket(); - Server = new PServer(); - - MySQL = new PMySQL(); - if(MySQL->Connect() == false) - return false; //Shutdown(); - - InfoServer = new PInfoServer(); - //Accounts = new PAccounts(); // To be removed - - return true; -} - -void Shutdown() -{ - if(Server) Server->Shutdown(); - if(InfoServer) delete InfoServer; - if(MySQL) delete MySQL; - if(Config) delete Config; - if(Console) delete Console; - if(ServerSock) delete ServerSock; - exit(0); -} - -bool AdditionnalConfigChecks() -{ - //NOTA: empty config values are never accepted by PConfig objects - - int numErr, numWarn; - - //std::string sqlhost = Config->GetOption("sql_host"); - std::string sqlusername = Config->GetOption("sql_username"); - //std::string sqlpassword = Config->GetOption("sql_password"); - //std::string global_sql_database = Config->GetOption("global_sql_database"); - int sqlport = Config->GetOptionInt("sql_port"); - int auto_accounts = Config->GetOptionInt("auto_accounts"); - int infoserver_port = Config->GetOptionInt("infoserver_port"); - int gameserver_livecheck = Config->GetOptionInt("gameserver_livecheck"); - int minlevel = Config->GetOptionInt("minlevel"); - int maxclients = Config->GetOptionInt("maxclients"); - - numErr = numWarn = 0; - - /*if(strcmp(sqlhost.c_str(), "") == 0) - { - Console->Print("%s sql_host is empty", Console->ColorText(RED, BLACK, "Config error:")); - numErr++; - }*/ - - /*if(strcmp(sqlusername.c_str(), "") == 0) - { - Console->Print("%s sql_username is empty", Console->ColorText(RED, BLACK, "Config error:")); - numErr++; - } - else*/ - if(strcmp(sqlusername.c_str(), "root") ==0) - { - Console->Print("%s Config: sqlusername is \"root\", which is pretty insecure.", Console->ColorText(YELLOW, BLACK, "[Warning]")); - numWarn++; - } - - /*if(strcmp(sqlpassword.c_str(), "") == 0); - { - Console->Print("%s sql_password is empty", Console->ColorText(RED, BLACK, "Config error:")); - numErr++; - } - - if(strcmp(global_sql_database.c_str(), "") == 0); - { - Console->Print("%s global_sql_database is empty", Console->ColorText(RED, BLACK, "Config error:")); - numErr++; - }*/ - - if(sqlport < 1025 || sqlport > 65535) - { - Console->Print("%s Config: sql_port is usually between 1025 and 65535!", Console->ColorText(YELLOW, BLACK, "[Warning]")); - numWarn++; - } - - if(auto_accounts != 0 && auto_accounts != 1) - { - Console->Print("%s Config: auto_accounts has to be either 0 or 1!", Console->ColorText(RED, BLACK, "[Error]")); - numErr++; - } - - if(infoserver_port < 1025 || infoserver_port > 65535) - { - Console->Print("%s Config: infoserver_port has to be between 1025 and 65535!", Console->ColorText(RED, BLACK, "[Error]")); - numErr++; - } - // This assertion is wrong, as sql server and info server can be on differents computers - /*else if(infoserver_port == sqlport) - { - Console->Print("%s infoserver_port has to be different from sql_port!", Console->ColorText(RED, BLACK, "Config error:")); - numErr++; - }*/ - - if(gameserver_livecheck <= 0) - { - Console->Print("%s Config: gameserver_livecheck cannot equal or less than 0", Console->ColorText(RED, BLACK, "[Error]")); - numErr++; - } - else if(gameserver_livecheck < 2) - { - Console->Print("%s Config: gameserver_livecheck is pretty low, this may cause increased mysql load", Console->ColorText(YELLOW, BLACK, "[Warning]")); - numWarn++; - } - else if(gameserver_livecheck > 120 && gameserver_livecheck < 600) - { - Console->Print("%s Config: gameserver_livecheck is pretty high, this may cause offline servers shown as online and a wrong usercount", Console->ColorText(YELLOW, BLACK, "[Warning]")); - numWarn++; - } - else if(gameserver_livecheck > 600) - { - Console->Print("%s Config: gameserver_livecheck is too high. Use a value between 0 and 600", Console->ColorText(RED, BLACK, "[Error]")); - numErr++; - } - - if(minlevel < 0 || minlevel > 255) - { - Console->Print("%s Config: minlevel has to be between 0 and 255", Console->ColorText(RED, BLACK, "[Error]")); - numErr++; - } - - if(maxclients < 1 ) - { - Console->Print("%s Config: maxclients has to be higher or equal to 1", Console->ColorText(RED, BLACK, "[Error]")); - numErr++; - } - - if(numErr == 0 /*&& numWarn == 0*/) - return true; - else - return false; -} +#include +#include "InfoServer/Includes.hxx" +#include "Common/Includes.hxx" + +const char ServerVersion[] = TINNS_INFO_VERSION; +const char SVNRevision[] = TINNS_SVN_REVISION; + +ServerSocket* ServerSock = 0; +PMySQL *MySQL = 0; +PConsole *Console = 0; +PServer *Server = 0; +PConfig *Config = 0; +PInfoServer *InfoServer = 0; +//PAccounts *Accounts = 0; // To be removed + +bool Init() +{ + Console = new PConsole("log/infoserver.log"); // Make that from config file !!! + Console->Print("Starting TinNS Infoserver"); + Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\"); + Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |"); + Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |"); + Console->Print(WHITE, BLUE, "| maintainer Akiko |"); + Console->Print(WHITE, BLUE, "| ========================================== |"); + Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |"); + Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |"); + Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |"); + Console->Print(WHITE, BLUE, "| - Namikon - Balm |"); + Console->Print(WHITE, BLUE, "| - Hammag |"); + Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); + Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |"); + Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |"); + Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); + Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |"); + Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/"); + + //char svnrev[10]; + //GetSVNRev(svnrev); + Console->LPrint("You are running TinNS Infoserver version"); + Console->LPrint(GREEN, BLACK, " %s", ServerVersion); + Console->LPrint(WHITE, BLACK, " - SVN Rev"); + Console->LPrint(GREEN, BLACK, " %s", SVNRevision); + Console->LClose(); + + Config = new PConfig(); + if(!Config->LoadOptions(InfoConfigTemplate, "./conf/infoserver.conf")) + return false; //Shutdown(); + if(!AdditionnalConfigChecks()) + return false; //Shutdown(); + + ServerSock = new ServerSocket(); + Server = new PServer(); + + MySQL = new PMySQL(); + if(MySQL->Connect() == false) + return false; //Shutdown(); + + InfoServer = new PInfoServer(); + //Accounts = new PAccounts(); // To be removed + + return true; +} + +void Shutdown() +{ + if(Server) Server->Shutdown(); + if(InfoServer) delete InfoServer; + if(MySQL) delete MySQL; + if(Config) delete Config; + if(Console) delete Console; + if(ServerSock) delete ServerSock; + exit(0); +} + +bool AdditionnalConfigChecks() +{ + //NOTA: empty config values are never accepted by PConfig objects + + int numErr, numWarn; + + //std::string sqlhost = Config->GetOption("sql_host"); + std::string sqlusername = Config->GetOption("sql_username"); + //std::string sqlpassword = Config->GetOption("sql_password"); + //std::string global_sql_database = Config->GetOption("global_sql_database"); + int sqlport = Config->GetOptionInt("sql_port"); + int auto_accounts = Config->GetOptionInt("auto_accounts"); + int infoserver_port = Config->GetOptionInt("infoserver_port"); + int gameserver_livecheck = Config->GetOptionInt("gameserver_livecheck"); + int minlevel = Config->GetOptionInt("minlevel"); + int maxclients = Config->GetOptionInt("maxclients"); + + numErr = numWarn = 0; + + /*if(strcmp(sqlhost.c_str(), "") == 0) + { + Console->Print("%s sql_host is empty", Console->ColorText(RED, BLACK, "Config error:")); + numErr++; + }*/ + + /*if(strcmp(sqlusername.c_str(), "") == 0) + { + Console->Print("%s sql_username is empty", Console->ColorText(RED, BLACK, "Config error:")); + numErr++; + } + else*/ + if(strcmp(sqlusername.c_str(), "root") ==0) + { + Console->Print("%s Config: sqlusername is \"root\", which is pretty insecure.", Console->ColorText(YELLOW, BLACK, "[Warning]")); + numWarn++; + } + + /*if(strcmp(sqlpassword.c_str(), "") == 0); + { + Console->Print("%s sql_password is empty", Console->ColorText(RED, BLACK, "Config error:")); + numErr++; + } + + if(strcmp(global_sql_database.c_str(), "") == 0); + { + Console->Print("%s global_sql_database is empty", Console->ColorText(RED, BLACK, "Config error:")); + numErr++; + }*/ + + if(sqlport < 1025 || sqlport > 65535) + { + Console->Print("%s Config: sql_port is usually between 1025 and 65535!", Console->ColorText(YELLOW, BLACK, "[Warning]")); + numWarn++; + } + + if(auto_accounts != 0 && auto_accounts != 1) + { + Console->Print("%s Config: auto_accounts has to be either 0 or 1!", Console->ColorText(RED, BLACK, "[Error]")); + numErr++; + } + + if(infoserver_port < 1025 || infoserver_port > 65535) + { + Console->Print("%s Config: infoserver_port has to be between 1025 and 65535!", Console->ColorText(RED, BLACK, "[Error]")); + numErr++; + } + // This assertion is wrong, as sql server and info server can be on differents computers + /*else if(infoserver_port == sqlport) + { + Console->Print("%s infoserver_port has to be different from sql_port!", Console->ColorText(RED, BLACK, "Config error:")); + numErr++; + }*/ + + if(gameserver_livecheck <= 0) + { + Console->Print("%s Config: gameserver_livecheck cannot equal or less than 0", Console->ColorText(RED, BLACK, "[Error]")); + numErr++; + } + else if(gameserver_livecheck < 2) + { + Console->Print("%s Config: gameserver_livecheck is pretty low, this may cause increased mysql load", Console->ColorText(YELLOW, BLACK, "[Warning]")); + numWarn++; + } + else if(gameserver_livecheck > 120 && gameserver_livecheck < 600) + { + Console->Print("%s Config: gameserver_livecheck is pretty high, this may cause offline servers shown as online and a wrong usercount", Console->ColorText(YELLOW, BLACK, "[Warning]")); + numWarn++; + } + else if(gameserver_livecheck > 600) + { + Console->Print("%s Config: gameserver_livecheck is too high. Use a value between 0 and 600", Console->ColorText(RED, BLACK, "[Error]")); + numErr++; + } + + if(minlevel < 0 || minlevel > 255) + { + Console->Print("%s Config: minlevel has to be between 0 and 255", Console->ColorText(RED, BLACK, "[Error]")); + numErr++; + } + + if(maxclients < 1 ) + { + Console->Print("%s Config: maxclients has to be higher or equal to 1", Console->ColorText(RED, BLACK, "[Error]")); + numErr++; + } + + if(numErr == 0 /*&& numWarn == 0*/) + return true; + else + return false; +} diff --git a/TinNS/Source/InfoServer/Includes.hxx b/TinNS/Source/InfoServer/Includes.hxx index eff92ed..1253897 100644 --- a/TinNS/Source/InfoServer/Includes.hxx +++ b/TinNS/Source/InfoServer/Includes.hxx @@ -1,24 +1,24 @@ -#pragma once - -#include "InfoServer/Accounts.hxx" -#include "InfoServer/ConfigTemplate.hxx" -#include "InfoServer/Client.hxx" -#include "InfoServer/InfoServer.hxx" -#include "InfoServer/Server.hxx" -#include "InfoServer/Sql.hxx" - -extern class ServerSocket* ServerSock; -extern class PConsole *Console; -extern class PServer *Server; -extern class PConfig *Config; -extern class PInfoServer *InfoServer; - -extern class PMySQL* MySQL; -//extern class PAccounts* Accounts; // To be removed - -extern const char ServerVersion[]; -extern const char SVNRevision[]; - -bool Init(); -void Shutdown(); -bool AdditionnalConfigChecks(); +#pragma once + +#include "InfoServer/Accounts.hxx" +#include "InfoServer/ConfigTemplate.hxx" +#include "InfoServer/Client.hxx" +#include "InfoServer/InfoServer.hxx" +#include "InfoServer/Server.hxx" +#include "InfoServer/Sql.hxx" + +extern class ServerSocket* ServerSock; +extern class PConsole *Console; +extern class PServer *Server; +extern class PConfig *Config; +extern class PInfoServer *InfoServer; + +extern class PMySQL* MySQL; +//extern class PAccounts* Accounts; // To be removed + +extern const char ServerVersion[]; +extern const char SVNRevision[]; + +bool Init(); +void Shutdown(); +bool AdditionnalConfigChecks(); diff --git a/TinNS/Source/InfoServer/InfoServer.cxx b/TinNS/Source/InfoServer/InfoServer.cxx index 3d92783..9b2f990 100644 --- a/TinNS/Source/InfoServer/InfoServer.cxx +++ b/TinNS/Source/InfoServer/InfoServer.cxx @@ -1,576 +1,576 @@ -#include -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -struct PInfoState -{ - enum State - { - IS_UNKNOWN, - IS_CONNECTED, - IS_HANDSHAKE0, - IS_AUTHENTICATE, - IS_SERVERLIST - } mState; - - bool mWaitSend; // wait-for-completition flag - PInfoState() - { - mState = IS_UNKNOWN; - mWaitSend = false; - }; -}; - -PInfoServer::PInfoServer() -{ - //mNumClients = 1; - mLivecheckInterval = Config->GetOptionInt("gameserver_livecheck"); -} - -PInfoServer::~PInfoServer() -{ - Console->Print("Closing Infoserver..."); - - ServerSock->closeServer(); - - for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++) - delete i->second; -} - -void PInfoServer::Start() -{ - uint16_t Port = Config->GetOptionInt("infoserver_port"); - Console->LPrint("Starting Infoserver on port %i...", Port); - - if(ServerSock->open(Port)) - { - Console->LPrint(GREEN, BLACK, "Success"); - Console->LClose(); - } - else - { - Console->LPrint(RED, BLACK, "Failed"); - Console->LClose(); - } - ServerSock->settimeout(0, 10000); - GSLiveCheck(); -} - -void PInfoServer::Update() -{ - if(ServerSock->newConnection()) - { - int32_t clid = Server->NewClient(); - if(clid!=-1) - { - Console->Print(GREEN, BLACK, "Infoserver: client [%i] connected", clid); - PClient *Client = Server->GetClient(clid); - - ConnectionTCP* tcpConn = ServerSock->getTCPConnection(); - Client->setTCPConnection(tcpConn); - - Console->Print("Client address: %s", Client->GetAddress()); - //++mNumClients; - - PInfoState *state = new PInfoState(); - ClientStates.insert(std::make_pair(Client, state)); - state->mState = PInfoState::IS_CONNECTED; - } else - { - Console->Print("Infoserver: Client connection refused (server full?)"); - } - } - - for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();) - { - PClient *Client = i->first; - PInfoState *State = i->second; - // node gets erased in FinalizeClient, increment iterator now - ++i; - if(!ProcessClient(Client, State)) - FinalizeClient(Client, State); - } -} - -void PInfoServer::GSLiveCheck() -{ - MYSQL_ROW row; - MYSQL_RES *result; - char query[256]; - snprintf (query, 256, "SELECT *, (NOW()< (`s_lastupdate` + INTERVAL %d SECOND)) FROM `server_list`", mLivecheckInterval); - - result = MySQL->ResQuery(query); - if (result == nullptr) - { - Console->Print("Livecheck: %s unable to read server list!", Console->ColorText(RED, BLACK, "[Warning]")); - MySQL->ShowSQLError(); - return; - } - if(mysql_num_rows(result) == 0) - { - Console->Print("Livecheck: %s no gameserver found!", Console->ColorText(RED, BLACK, "[Warning]")); - MySQL->FreeSQLResult(result); - return; - } - - ServerMap::iterator it; - while((row = mysql_fetch_row(result))) - { - it = Serverlist.find(atoi(row[s_id])); - if(it != Serverlist.end()) - { - strncpy(it->second.mName, row[s_name], MAX_SERVER_NAME_LENGTH); - it->second.mLanIp = IPStringToDWord(row[s_lanaddr]); - it->second.mWanIp = IPStringToDWord(row[s_wanaddr]); - it->second.mPort = atoi(row[s_port]); - it->second.mPlayers = atoi(row[s_players]); - /* Prepared for future addon Servers by Accesslevel */ - // it->second.mMinLv = atoi(row[s_minlv]); - /* ------------------------------------------------ */ - - // ToDo: If statement correct? Maybe GSLiveCheck() has - // to be called every mLinvecheckInterval seconds.... We'll - // see when Gameserver has been rewritten - - if(row[s_timecheck] && (atoi(row[s_timecheck]) == 1)) - { - it->second.mLasttimestamp = atol(row[s_lastupdate]); - it->second.mOnline = true; - } - else - { - it->second.mOnline = false; - } - - it->second.mUpdated = true; - } - else - { - GameServers tmpServer; - - strncpy(tmpServer.mName, row[s_name], MAX_SERVER_NAME_LENGTH); - tmpServer.mLanIp = IPStringToDWord(row[s_lanaddr]); - tmpServer.mWanIp = IPStringToDWord(row[s_wanaddr]); - tmpServer.mLasttimestamp = atol(row[s_lastupdate]); - tmpServer.mPlayers = atoi(row[s_players]); - tmpServer.mPort = atoi(row[s_port]); - tmpServer.mOnline = true; - tmpServer.mUpdated = true; - Console->Print("Added GameServer %s", tmpServer.mName); - /* Prepared for future addon Servers by Accesslevel */ - // tmpServer.mMinLv = atoi(row[s_minlv]); - /* ------------------------------------------------ */ - - Serverlist.insert(std::make_pair(atoi(row[s_id]), tmpServer)); - } - } - MySQL->FreeSQLResult(result); - - for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++) - { - if(it->second.mUpdated == false) - Serverlist.erase(it); - else - it->second.mUpdated = false; - } - -} - -void PInfoServer::ClientDisconnected(PClient *Client) -{ - InfoStateMap::iterator node = ClientStates.find(Client); - if(node == ClientStates.end()) - return; - - PInfoState *State = node->second; - FinalizeClient(Client, State); -} - -bool PInfoServer::HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize) -{ - //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68}; - - switch(State->mState) - { - case PInfoState::IS_HANDSHAKE0 : - { - if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x78) - { - //FIXME: this packet seems to be unnecessary, although it appears in traffic dumps - // (causes clientside "Wrong protocol" errors) - //Socket->Write(HANDSHAKE1A, 6); - State->mState = PInfoState::IS_AUTHENTICATE; - } - else - { - Console->Print(RED, BLACK, "Infoserver protocol error (IS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]); - return false; - } - break; - } - default: - break; - } - - return true; -} - -bool PInfoServer::HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize) -{ - int32_t returnval = 0; - // ReturnValue values: - // 0: No error - // -1: Wrong/Unknown username - // -2: Wrong Password - // -3: Malformed Auth Data. Please relog - // -4: Database error, contact admin - // -5: No such account, Account created. Please relog - // -6: Could not create autoaccount, PW too short - // -7: Could not create autoaccount, Name too short - // -8: Could not create autoaccount, PW and Name too short - // -9: Duplicate entry for Username! Contact Admin - // -10: User is banned - // -11: Insufficient access rights - // -12: Account is not yet activated (accesslevel = 0) - // -99: General fault. Contact admin - ConnectionTCP *Socket = Client->getTCPConn(); - PAccount* currentAccount = NULL; - - if (PacketSize > 20 && *(uint16_t *)&Packet[3] == 0x8084) - { - const uint8_t *Key = &Packet[5]; // password key - uint16_t ULen = *(uint16_t *)&Packet[16]; // username length - uint16_t PLen = *(uint16_t *)&Packet[18]; // password length - char *UserName = (char *)&Packet[20]; // account name - const uint8_t *PW = &Packet[20 + ULen]; // encoded password - - if (UserName[ULen-1]) // Check that string is well terminated - { - Console->Print("Infoserver: Client [%d]: Username was not NULL-terminated !", Client->GetIndex()); - returnval = -1; - } - else - { - currentAccount = new PAccount(UserName); - if(!currentAccount->GetID()) - { - if(Config->GetOptionInt("auto_accounts")) // Autoaccount - { - delete currentAccount; - currentAccount = new PAccount(); - - if(!currentAccount->SetName(UserName)) // !!! len - { - returnval = -7; - } - if(!currentAccount->SetPasswordEncoded(PW, PLen, Key)) - { - returnval = returnval ? -8 : -6; - } - - if(!returnval) - { - if(currentAccount->Create()) - { - returnval = -5; - } - else - { - returnval = -4; - } - } - } - else - { - returnval = -1; - } - } - else - { - if(currentAccount->Authenticate(PW, PLen, Key)) - { // Username & Password correct - if(currentAccount->IsBanned()) - { - returnval = -10; - } - else if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) // insufficient access rights - { - returnval = -11; - } - else if(Config->GetOptionInt("require_validation") == 1 && currentAccount->GetLevel() == PAL_UNREGPLAYER) - { - returnval = -12; - } - else - { - Client->setAccountID(currentAccount->GetID()); - returnval = 0; - } - - } - else - { - returnval = -2; - } - } - } - - bool Failed = false; - if(returnval == 0) - { - uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00 }; - *(uint32_t *)&AUTHOK[5] = currentAccount->GetID(); - Socket->write(AUTHOK, 28); - State->mState = PInfoState::IS_SERVERLIST; - } - else - { - Console->Print("Infoserver: User '%s': authentication failed. Errorcode %d", UserName, returnval); - Failed = true; // auth failed - } - if(Failed == true) - { - std::string errorReason; - switch(returnval) - { - // It seems that the client cuts the line off after 40 chars... -// |1 |10 |20 |30 |40 |50 |60 |70 |80 - case -99: - { - //errorReason = "General fault in processing your login request"; - errorReason = "General fault while login request"; - break; - } - case -12: - { - //errorReason = "Account not activated. Please check your EMails"; - errorReason = "Error: Your account is not activated"; - break; - } - case -11: - { - //errorReason = "Login rejected. You have to be " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher"; - errorReason = "Level " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher required"; - break; - } - case -10: - { - errorReason = "You are banned for " + currentAccount->GetBannedTime(); - break; - } - case -9: - { - //errorReason = "Duplicate entry for this login. Contact Admin"; - errorReason = "Duplicate entry found. Contact Admin"; - break; - } - case -8: - { - //errorReason = "Autoaccount failed, name and password too short"; - errorReason = "AutoAcc failed, name and pwd too short"; - break; - } - case -7: - { - errorReason = "Autoaccount failed, name is too short"; - break; - } - case -6: - { - //errorReason = "Autoaccount failed, password is too short"; - errorReason = "Autoaccount failed, pwd is too short"; - break; - } - case -5: - { - errorReason = "New Account created, please login again"; - break; - } - case -4: - { - errorReason = "Database error, contact Administrator"; - break; - } - case -3: - { - errorReason = "Malformed AuthData. Please login again"; - break; - } - case -2: - { - errorReason = "Wrong password"; - break; - } - case -1: - { - errorReason = "Unknown username"; - break; - } - } - uint8_t AUTHFAILED_HEADER[] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00}; - uint8_t AUTHFAILED_FOOTER[] = {0x00, 0x40}; - *(uint16_t *)&AUTHFAILED_HEADER[1] = errorReason.size() + 8; - *(uint16_t *)&AUTHFAILED_HEADER[7] = errorReason.size() + 1; - //*(uint8_t*)&AUTHFAILED_FOOTER[1] = {0x40}; - - Socket->write(AUTHFAILED_HEADER, sizeof(AUTHFAILED_HEADER)); - Socket->write(errorReason.c_str(), errorReason.size()); - Socket->write(AUTHFAILED_FOOTER, sizeof(AUTHFAILED_FOOTER)); - FinalizeClientDelayed(Client, State); - State->mState=PInfoState::IS_UNKNOWN; - } - } - else - { - Console->Print(RED, BLACK, "Infoserver protocol error (IS_AUTHENTICATE): invalid packet [%04x]", - *(uint16_t *)&Packet[3]); - return false; - } - - return true; -} - -bool PInfoServer::HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize) -{ - uint8_t SERVERLIST_HEAD[] = {0xfe, 0x00, 0x00, 0x83, 0x83, 0x01, 0x00, 0x0d, 0x00}; - uint8_t SERVERLIST[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t SERVERLIST_FOOTER[] = {0x00}; - - ConnectionTCP *Socket = Client->getTCPConn(); - - uint32_t tID = *(uint32_t *)&Packet[5]; - PAccount* currentAccount = new PAccount(Client->getAccountID()); - uint32_t aID = currentAccount->GetID(); - - if(!aID || (aID != tID)) - { - Console->Print("%s invalid userID %d (auth with id %d)", Console->ColorText(YELLOW, BLACK, "Warning:"), tID, aID); - delete currentAccount; - return false; - } - - if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) - { - Console->Print("%s someone tried to bypass the login process! UserID %d", Console->ColorText(RED, BLACK, "Warning:"), aID); - delete currentAccount; - return false; - } - - if(PacketSize == 31 && *(uint16_t *)&Packet[3]==0x8284) - { - GSLiveCheck(); // Perform livecheck to have up-to-date data - - int32_t len = 0; - int32_t num = 0; - for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++) - { - num++; - len += 14 + strlen(it->second.mName); - } - - *(uint16_t *)&SERVERLIST_HEAD[1] = len; - *(uint8_t *)&SERVERLIST_HEAD[5] = num; - Socket->write(SERVERLIST_HEAD, sizeof(SERVERLIST_HEAD)); - - for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++) - { - /* Prepared for future addon Servers by Accesslevel */ -// if(accesslevel >= it->second.mMinLv) -// { - /* ------------------------------------------------ */ - // Todo: Set correct lan/wan IP here! - *(uint32_t *)&SERVERLIST[0] = it->second.mLanIp; - *(uint16_t *)&SERVERLIST[4] = it->second.mPort; - *(uint8_t *)&SERVERLIST[8] = strlen(it->second.mName) + 1; - *(uint16_t *)&SERVERLIST[9] = it->second.mPlayers; - if(it->second.mOnline == true) - { - Console->Print("Sending server name: %s ip: %s player: %d port: %d online: yes", it->second.mName, - IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort); - *(uint16_t *)&SERVERLIST[11] = 1; - } - else if(it->second.mOnline == false) - { - Console->Print("Sending server name: %s ip: %s player: %d port: %d online: no", it->second.mName, - IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort); - *(uint16_t *)&SERVERLIST[11] = 0; - } - Socket->write(SERVERLIST, sizeof(SERVERLIST)); - Socket->write(it->second.mName, strlen(it->second.mName)); - Socket->write(SERVERLIST_FOOTER, sizeof(SERVERLIST_FOOTER)); - /* Prepared for future addon Servers by Accesslevel */ -// } - /* ------------------------------------------------ */ - } - } - else - { - Console->Print(RED, BLACK, "Infoserver protocol error (IS_SERVERLIST): invalid packet [%04x]", - *(uint16_t *)&Packet[3]); - delete currentAccount; - return false; - } - delete currentAccount; - return true; -} - -bool PInfoServer::ProcessClient(PClient *Client, PInfoState *State) -{ - static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x66}; - - if(!State) - { - InfoStateMap::iterator node = ClientStates.find(Client); - if(node == ClientStates.end()) - return false; - - State = node->second; - } - - ConnectionTCP *Socket = Client->getTCPConn(); - - if(State->mWaitSend && Socket->getSendBufferSize()==0) - return false; - - if(State->mState==PInfoState::IS_CONNECTED) - { - Socket->write(HANDSHAKE0A, 6); - State->mState = PInfoState::IS_HANDSHAKE0; - } - - int32_t PacketSize=0; - const uint8_t *Packet = Socket->read(&PacketSize); - if(PacketSize > 0) - { - switch(State->mState) - { - case PInfoState::IS_HANDSHAKE0: - return HandleHandshake(State, Packet, PacketSize); - - case PInfoState::IS_AUTHENTICATE: - return HandleAuthenticate(Client, State, Packet, PacketSize); - - case PInfoState::IS_SERVERLIST: - return HandleServerList(Client, Packet, PacketSize); - default: - break; - } - } - return true; -} - -void PInfoServer::FinalizeClient(PClient *Client, PInfoState *State) -{ - Console->Print(RED, BLACK, "Infoserver: client %s disconnected", Client->GetAddress()); - Client->InfoDisconnect(); - ClientStates.erase(Client); - delete State; -} - -void PInfoServer::FinalizeClientDelayed(PClient *Client, PInfoState *State) -{ - Console->Print("Infoserver: client %i is about to be disconnected", Client->GetIndex()); - State->mWaitSend = true; -} +#include +#include "InfoServer/Includes.hxx" +#include "Common/Includes.hxx" + +struct PInfoState +{ + enum State + { + IS_UNKNOWN, + IS_CONNECTED, + IS_HANDSHAKE0, + IS_AUTHENTICATE, + IS_SERVERLIST + } mState; + + bool mWaitSend; // wait-for-completition flag + PInfoState() + { + mState = IS_UNKNOWN; + mWaitSend = false; + }; +}; + +PInfoServer::PInfoServer() +{ + //mNumClients = 1; + mLivecheckInterval = Config->GetOptionInt("gameserver_livecheck"); +} + +PInfoServer::~PInfoServer() +{ + Console->Print("Closing Infoserver..."); + + ServerSock->closeServer(); + + for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++) + delete i->second; +} + +void PInfoServer::Start() +{ + uint16_t Port = Config->GetOptionInt("infoserver_port"); + Console->LPrint("Starting Infoserver on port %i...", Port); + + if(ServerSock->open(Port)) + { + Console->LPrint(GREEN, BLACK, "Success"); + Console->LClose(); + } + else + { + Console->LPrint(RED, BLACK, "Failed"); + Console->LClose(); + } + ServerSock->settimeout(0, 10000); + GSLiveCheck(); +} + +void PInfoServer::Update() +{ + if(ServerSock->newConnection()) + { + int32_t clid = Server->NewClient(); + if(clid!=-1) + { + Console->Print(GREEN, BLACK, "Infoserver: client [%i] connected", clid); + PClient *Client = Server->GetClient(clid); + + ConnectionTCP* tcpConn = ServerSock->getTCPConnection(); + Client->setTCPConnection(tcpConn); + + Console->Print("Client address: %s", Client->GetAddress()); + //++mNumClients; + + PInfoState *state = new PInfoState(); + ClientStates.insert(std::make_pair(Client, state)); + state->mState = PInfoState::IS_CONNECTED; + } else + { + Console->Print("Infoserver: Client connection refused (server full?)"); + } + } + + for(InfoStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();) + { + PClient *Client = i->first; + PInfoState *State = i->second; + // node gets erased in FinalizeClient, increment iterator now + ++i; + if(!ProcessClient(Client, State)) + FinalizeClient(Client, State); + } +} + +void PInfoServer::GSLiveCheck() +{ + MYSQL_ROW row; + MYSQL_RES *result; + char query[256]; + snprintf (query, 256, "SELECT *, (NOW()< (`s_lastupdate` + INTERVAL %d SECOND)) FROM `server_list`", mLivecheckInterval); + + result = MySQL->ResQuery(query); + if (result == nullptr) + { + Console->Print("Livecheck: %s unable to read server list!", Console->ColorText(RED, BLACK, "[Warning]")); + MySQL->ShowSQLError(); + return; + } + if(mysql_num_rows(result) == 0) + { + Console->Print("Livecheck: %s no gameserver found!", Console->ColorText(RED, BLACK, "[Warning]")); + MySQL->FreeSQLResult(result); + return; + } + + ServerMap::iterator it; + while((row = mysql_fetch_row(result))) + { + it = Serverlist.find(atoi(row[s_id])); + if(it != Serverlist.end()) + { + strncpy(it->second.mName, row[s_name], MAX_SERVER_NAME_LENGTH); + it->second.mLanIp = IPStringToDWord(row[s_lanaddr]); + it->second.mWanIp = IPStringToDWord(row[s_wanaddr]); + it->second.mPort = atoi(row[s_port]); + it->second.mPlayers = atoi(row[s_players]); + /* Prepared for future addon Servers by Accesslevel */ + // it->second.mMinLv = atoi(row[s_minlv]); + /* ------------------------------------------------ */ + + // ToDo: If statement correct? Maybe GSLiveCheck() has + // to be called every mLinvecheckInterval seconds.... We'll + // see when Gameserver has been rewritten + + if(row[s_timecheck] && (atoi(row[s_timecheck]) == 1)) + { + it->second.mLasttimestamp = atol(row[s_lastupdate]); + it->second.mOnline = true; + } + else + { + it->second.mOnline = false; + } + + it->second.mUpdated = true; + } + else + { + GameServers tmpServer; + + strncpy(tmpServer.mName, row[s_name], MAX_SERVER_NAME_LENGTH); + tmpServer.mLanIp = IPStringToDWord(row[s_lanaddr]); + tmpServer.mWanIp = IPStringToDWord(row[s_wanaddr]); + tmpServer.mLasttimestamp = atol(row[s_lastupdate]); + tmpServer.mPlayers = atoi(row[s_players]); + tmpServer.mPort = atoi(row[s_port]); + tmpServer.mOnline = true; + tmpServer.mUpdated = true; + Console->Print("Added GameServer %s", tmpServer.mName); + /* Prepared for future addon Servers by Accesslevel */ + // tmpServer.mMinLv = atoi(row[s_minlv]); + /* ------------------------------------------------ */ + + Serverlist.insert(std::make_pair(atoi(row[s_id]), tmpServer)); + } + } + MySQL->FreeSQLResult(result); + + for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++) + { + if(it->second.mUpdated == false) + Serverlist.erase(it); + else + it->second.mUpdated = false; + } + +} + +void PInfoServer::ClientDisconnected(PClient *Client) +{ + InfoStateMap::iterator node = ClientStates.find(Client); + if(node == ClientStates.end()) + return; + + PInfoState *State = node->second; + FinalizeClient(Client, State); +} + +bool PInfoServer::HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize) +{ + //static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x68}; + + switch(State->mState) + { + case PInfoState::IS_HANDSHAKE0 : + { + if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x78) + { + //FIXME: this packet seems to be unnecessary, although it appears in traffic dumps + // (causes clientside "Wrong protocol" errors) + //Socket->Write(HANDSHAKE1A, 6); + State->mState = PInfoState::IS_AUTHENTICATE; + } + else + { + Console->Print(RED, BLACK, "Infoserver protocol error (IS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]); + return false; + } + break; + } + default: + break; + } + + return true; +} + +bool PInfoServer::HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize) +{ + int32_t returnval = 0; + // ReturnValue values: + // 0: No error + // -1: Wrong/Unknown username + // -2: Wrong Password + // -3: Malformed Auth Data. Please relog + // -4: Database error, contact admin + // -5: No such account, Account created. Please relog + // -6: Could not create autoaccount, PW too short + // -7: Could not create autoaccount, Name too short + // -8: Could not create autoaccount, PW and Name too short + // -9: Duplicate entry for Username! Contact Admin + // -10: User is banned + // -11: Insufficient access rights + // -12: Account is not yet activated (accesslevel = 0) + // -99: General fault. Contact admin + ConnectionTCP *Socket = Client->getTCPConn(); + PAccount* currentAccount = NULL; + + if (PacketSize > 20 && *(uint16_t *)&Packet[3] == 0x8084) + { + const uint8_t *Key = &Packet[5]; // password key + uint16_t ULen = *(uint16_t *)&Packet[16]; // username length + uint16_t PLen = *(uint16_t *)&Packet[18]; // password length + char *UserName = (char *)&Packet[20]; // account name + const uint8_t *PW = &Packet[20 + ULen]; // encoded password + + if (UserName[ULen-1]) // Check that string is well terminated + { + Console->Print("Infoserver: Client [%d]: Username was not NULL-terminated !", Client->GetIndex()); + returnval = -1; + } + else + { + currentAccount = new PAccount(UserName); + if(!currentAccount->GetID()) + { + if(Config->GetOptionInt("auto_accounts")) // Autoaccount + { + delete currentAccount; + currentAccount = new PAccount(); + + if(!currentAccount->SetName(UserName)) // !!! len + { + returnval = -7; + } + if(!currentAccount->SetPasswordEncoded(PW, PLen, Key)) + { + returnval = returnval ? -8 : -6; + } + + if(!returnval) + { + if(currentAccount->Create()) + { + returnval = -5; + } + else + { + returnval = -4; + } + } + } + else + { + returnval = -1; + } + } + else + { + if(currentAccount->Authenticate(PW, PLen, Key)) + { // Username & Password correct + if(currentAccount->IsBanned()) + { + returnval = -10; + } + else if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) // insufficient access rights + { + returnval = -11; + } + else if(Config->GetOptionInt("require_validation") == 1 && currentAccount->GetLevel() == PAL_UNREGPLAYER) + { + returnval = -12; + } + else + { + Client->setAccountID(currentAccount->GetID()); + returnval = 0; + } + + } + else + { + returnval = -2; + } + } + } + + bool Failed = false; + if(returnval == 0) + { + uint8_t AUTHOK[28]={0xfe, 0x19, 0x00, 0x83, 0x81, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00 }; + *(uint32_t *)&AUTHOK[5] = currentAccount->GetID(); + Socket->write(AUTHOK, 28); + State->mState = PInfoState::IS_SERVERLIST; + } + else + { + Console->Print("Infoserver: User '%s': authentication failed. Errorcode %d", UserName, returnval); + Failed = true; // auth failed + } + if(Failed == true) + { + std::string errorReason; + switch(returnval) + { + // It seems that the client cuts the line off after 40 chars... +// |1 |10 |20 |30 |40 |50 |60 |70 |80 + case -99: + { + //errorReason = "General fault in processing your login request"; + errorReason = "General fault while login request"; + break; + } + case -12: + { + //errorReason = "Account not activated. Please check your EMails"; + errorReason = "Error: Your account is not activated"; + break; + } + case -11: + { + //errorReason = "Login rejected. You have to be " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher"; + errorReason = "Level " + GetAccessString(Config->GetOptionInt("minlevel")) + " or higher required"; + break; + } + case -10: + { + errorReason = "You are banned for " + currentAccount->GetBannedTime(); + break; + } + case -9: + { + //errorReason = "Duplicate entry for this login. Contact Admin"; + errorReason = "Duplicate entry found. Contact Admin"; + break; + } + case -8: + { + //errorReason = "Autoaccount failed, name and password too short"; + errorReason = "AutoAcc failed, name and pwd too short"; + break; + } + case -7: + { + errorReason = "Autoaccount failed, name is too short"; + break; + } + case -6: + { + //errorReason = "Autoaccount failed, password is too short"; + errorReason = "Autoaccount failed, pwd is too short"; + break; + } + case -5: + { + errorReason = "New Account created, please login again"; + break; + } + case -4: + { + errorReason = "Database error, contact Administrator"; + break; + } + case -3: + { + errorReason = "Malformed AuthData. Please login again"; + break; + } + case -2: + { + errorReason = "Wrong password"; + break; + } + case -1: + { + errorReason = "Unknown username"; + break; + } + } + uint8_t AUTHFAILED_HEADER[] = {0xfe, 0x0c, 0x00, 0x83, 0x86, 0x05, 0x00, 0x06, 0x00}; + uint8_t AUTHFAILED_FOOTER[] = {0x00, 0x40}; + *(uint16_t *)&AUTHFAILED_HEADER[1] = errorReason.size() + 8; + *(uint16_t *)&AUTHFAILED_HEADER[7] = errorReason.size() + 1; + //*(uint8_t*)&AUTHFAILED_FOOTER[1] = {0x40}; + + Socket->write(AUTHFAILED_HEADER, sizeof(AUTHFAILED_HEADER)); + Socket->write(errorReason.c_str(), errorReason.size()); + Socket->write(AUTHFAILED_FOOTER, sizeof(AUTHFAILED_FOOTER)); + FinalizeClientDelayed(Client, State); + State->mState=PInfoState::IS_UNKNOWN; + } + } + else + { + Console->Print(RED, BLACK, "Infoserver protocol error (IS_AUTHENTICATE): invalid packet [%04x]", + *(uint16_t *)&Packet[3]); + return false; + } + + return true; +} + +bool PInfoServer::HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize) +{ + uint8_t SERVERLIST_HEAD[] = {0xfe, 0x00, 0x00, 0x83, 0x83, 0x01, 0x00, 0x0d, 0x00}; + uint8_t SERVERLIST[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t SERVERLIST_FOOTER[] = {0x00}; + + ConnectionTCP *Socket = Client->getTCPConn(); + + uint32_t tID = *(uint32_t *)&Packet[5]; + PAccount* currentAccount = new PAccount(Client->getAccountID()); + uint32_t aID = currentAccount->GetID(); + + if(!aID || (aID != tID)) + { + Console->Print("%s invalid userID %d (auth with id %d)", Console->ColorText(YELLOW, BLACK, "Warning:"), tID, aID); + delete currentAccount; + return false; + } + + if(currentAccount->GetLevel() < Config->GetOptionInt("minlevel")) + { + Console->Print("%s someone tried to bypass the login process! UserID %d", Console->ColorText(RED, BLACK, "Warning:"), aID); + delete currentAccount; + return false; + } + + if(PacketSize == 31 && *(uint16_t *)&Packet[3]==0x8284) + { + GSLiveCheck(); // Perform livecheck to have up-to-date data + + int32_t len = 0; + int32_t num = 0; + for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++) + { + num++; + len += 14 + strlen(it->second.mName); + } + + *(uint16_t *)&SERVERLIST_HEAD[1] = len; + *(uint8_t *)&SERVERLIST_HEAD[5] = num; + Socket->write(SERVERLIST_HEAD, sizeof(SERVERLIST_HEAD)); + + for(ServerMap::iterator it = Serverlist.begin(); it != Serverlist.end(); it++) + { + /* Prepared for future addon Servers by Accesslevel */ +// if(accesslevel >= it->second.mMinLv) +// { + /* ------------------------------------------------ */ + // Todo: Set correct lan/wan IP here! + *(uint32_t *)&SERVERLIST[0] = it->second.mLanIp; + *(uint16_t *)&SERVERLIST[4] = it->second.mPort; + *(uint8_t *)&SERVERLIST[8] = strlen(it->second.mName) + 1; + *(uint16_t *)&SERVERLIST[9] = it->second.mPlayers; + if(it->second.mOnline == true) + { + Console->Print("Sending server name: %s ip: %s player: %d port: %d online: yes", it->second.mName, + IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort); + *(uint16_t *)&SERVERLIST[11] = 1; + } + else if(it->second.mOnline == false) + { + Console->Print("Sending server name: %s ip: %s player: %d port: %d online: no", it->second.mName, + IPlongToString(it->second.mLanIp), it->second.mPlayers, it->second.mPort); + *(uint16_t *)&SERVERLIST[11] = 0; + } + Socket->write(SERVERLIST, sizeof(SERVERLIST)); + Socket->write(it->second.mName, strlen(it->second.mName)); + Socket->write(SERVERLIST_FOOTER, sizeof(SERVERLIST_FOOTER)); + /* Prepared for future addon Servers by Accesslevel */ +// } + /* ------------------------------------------------ */ + } + } + else + { + Console->Print(RED, BLACK, "Infoserver protocol error (IS_SERVERLIST): invalid packet [%04x]", + *(uint16_t *)&Packet[3]); + delete currentAccount; + return false; + } + delete currentAccount; + return true; +} + +bool PInfoServer::ProcessClient(PClient *Client, PInfoState *State) +{ + static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x66}; + + if(!State) + { + InfoStateMap::iterator node = ClientStates.find(Client); + if(node == ClientStates.end()) + return false; + + State = node->second; + } + + ConnectionTCP *Socket = Client->getTCPConn(); + + if(State->mWaitSend && Socket->getSendBufferSize()==0) + return false; + + if(State->mState==PInfoState::IS_CONNECTED) + { + Socket->write(HANDSHAKE0A, 6); + State->mState = PInfoState::IS_HANDSHAKE0; + } + + int32_t PacketSize=0; + const uint8_t *Packet = Socket->read(&PacketSize); + if(PacketSize > 0) + { + switch(State->mState) + { + case PInfoState::IS_HANDSHAKE0: + return HandleHandshake(State, Packet, PacketSize); + + case PInfoState::IS_AUTHENTICATE: + return HandleAuthenticate(Client, State, Packet, PacketSize); + + case PInfoState::IS_SERVERLIST: + return HandleServerList(Client, Packet, PacketSize); + default: + break; + } + } + return true; +} + +void PInfoServer::FinalizeClient(PClient *Client, PInfoState *State) +{ + Console->Print(RED, BLACK, "Infoserver: client %s disconnected", Client->GetAddress()); + Client->InfoDisconnect(); + ClientStates.erase(Client); + delete State; +} + +void PInfoServer::FinalizeClientDelayed(PClient *Client, PInfoState *State) +{ + Console->Print("Infoserver: client %i is about to be disconnected", Client->GetIndex()); + State->mWaitSend = true; +} diff --git a/TinNS/Source/InfoServer/InfoServer.hxx b/TinNS/Source/InfoServer/InfoServer.hxx index 350391b..3295d7b 100644 --- a/TinNS/Source/InfoServer/InfoServer.hxx +++ b/TinNS/Source/InfoServer/InfoServer.hxx @@ -1,64 +1,64 @@ -#pragma once - -#include -#include - -class PClient; -struct PInfoState; - -#define MAX_SERVER_NAME_LENGTH 45 -struct GameServers { - char mName[MAX_SERVER_NAME_LENGTH]; - uint32_t mLanIp; - uint32_t mWanIp; - int16_t mPort; - int32_t mPlayers; - bool mOnline; - bool mUpdated; - time_t mLasttimestamp; -/* Prepared for future addon Servers by Accesslevel */ -// int mMinLv; -/* ------------------------------------------------ */ -}; - -class PInfoServer { -private: - // SQL layout - enum { - s_id, - s_name, - s_wanaddr, - s_port, - s_players, - s_lastupdate, - s_lanaddr, - s_timecheck // computed field, not in table ! - }; - //int mNumClients; - typedef std::map InfoStateMap; - InfoStateMap ClientStates; - - typedef std::map ServerMap; - ServerMap Serverlist; - - //time_t mLastLivecheck; - int mLivecheckInterval; - void GSLiveCheck(); - -protected: - bool ProcessClient(PClient *Client, PInfoState *State = nullptr); - void FinalizeClient(PClient *Client, PInfoState *State); - void FinalizeClientDelayed(PClient *Client, PInfoState *State); - - bool HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize); - bool HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize); - bool HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize); - -public: - PInfoServer(); - ~PInfoServer(); - - void Start(); - void Update(); - void ClientDisconnected(PClient *Client); -}; +#pragma once + +#include +#include + +class PClient; +struct PInfoState; + +#define MAX_SERVER_NAME_LENGTH 45 +struct GameServers { + char mName[MAX_SERVER_NAME_LENGTH]; + uint32_t mLanIp; + uint32_t mWanIp; + int16_t mPort; + int32_t mPlayers; + bool mOnline; + bool mUpdated; + time_t mLasttimestamp; +/* Prepared for future addon Servers by Accesslevel */ +// int mMinLv; +/* ------------------------------------------------ */ +}; + +class PInfoServer { +private: + // SQL layout + enum { + s_id, + s_name, + s_wanaddr, + s_port, + s_players, + s_lastupdate, + s_lanaddr, + s_timecheck // computed field, not in table ! + }; + //int mNumClients; + typedef std::map InfoStateMap; + InfoStateMap ClientStates; + + typedef std::map ServerMap; + ServerMap Serverlist; + + //time_t mLastLivecheck; + int mLivecheckInterval; + void GSLiveCheck(); + +protected: + bool ProcessClient(PClient *Client, PInfoState *State = nullptr); + void FinalizeClient(PClient *Client, PInfoState *State); + void FinalizeClientDelayed(PClient *Client, PInfoState *State); + + bool HandleHandshake(PInfoState *State, const uint8_t *Packet, int32_t PacketSize); + bool HandleAuthenticate(PClient *Client, PInfoState *State, const uint8_t *Packet, int32_t PacketSize); + bool HandleServerList(PClient *Client, const uint8_t *Packet, int32_t PacketSize); + +public: + PInfoServer(); + ~PInfoServer(); + + void Start(); + void Update(); + void ClientDisconnected(PClient *Client); +}; diff --git a/TinNS/Source/InfoServer/Main.cxx b/TinNS/Source/InfoServer/Main.cxx index 0c87d5e..1f79e9a 100644 --- a/TinNS/Source/InfoServer/Main.cxx +++ b/TinNS/Source/InfoServer/Main.cxx @@ -1,35 +1,35 @@ -#include -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -void signal_handler(int signal) -{ - if (signal == SIGINT) - Shutdown(); -} - -int main() -{ - signal(SIGINT, signal_handler); - - if (!Init()) - { - if(Console) - Console->Print("%s Aborting startup.", Console->ColorText(RED, BLACK, "[Fatal]")); - Shutdown(); // exits with 0 ... - } - - InfoServer->Start(); - Console->Print("Infoserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online")); - - while (true) - { - ServerSock->update(); - Server->Update(); - InfoServer->Update(); - MySQL->Update(); // MySQL keepalive - Console->Update(); - } - - return 0; -} +#include +#include "InfoServer/Includes.hxx" +#include "Common/Includes.hxx" + +void signal_handler(int signal) +{ + if (signal == SIGINT) + Shutdown(); +} + +int main() +{ + signal(SIGINT, signal_handler); + + if (!Init()) + { + if(Console) + Console->Print("%s Aborting startup.", Console->ColorText(RED, BLACK, "[Fatal]")); + Shutdown(); // exits with 0 ... + } + + InfoServer->Start(); + Console->Print("Infoserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online")); + + while (true) + { + ServerSock->update(); + Server->Update(); + InfoServer->Update(); + MySQL->Update(); // MySQL keepalive + Console->Update(); + } + + return 0; +} diff --git a/TinNS/Source/InfoServer/Server.cxx b/TinNS/Source/InfoServer/Server.cxx index 370063f..0c9d3e0 100644 --- a/TinNS/Source/InfoServer/Server.cxx +++ b/TinNS/Source/InfoServer/Server.cxx @@ -1,80 +1,80 @@ -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -PServer::PServer() -{ - mMaxClients = Config->GetOptionInt("maxclients"); - - mClients.reserve(mMaxClients); - mNumClients = 0; - for (int32_t i=0; i= mMaxClients) - return 0; - - return mClients[Client]; -} - -void PServer::Update() -{ - for (int32_t i=0; iUpdate(); - if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0) - { - Console->Print("Removing client ..."); - delete mClients[i]; - mClients[i]=0; - --mNumClients; - } - } - } -} - -void PServer::Shutdown() -{ - Console->Print("======================"); - Console->Print("Shutting down Infoserver..."); - for (int32_t i=0; iGetOptionInt("maxclients"); + + mClients.reserve(mMaxClients); + mNumClients = 0; + for (int32_t i=0; i= mMaxClients) + return 0; + + return mClients[Client]; +} + +void PServer::Update() +{ + for (int32_t i=0; iUpdate(); + if(mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0) + { + Console->Print("Removing client ..."); + delete mClients[i]; + mClients[i]=0; + --mNumClients; + } + } + } +} + +void PServer::Shutdown() +{ + Console->Print("======================"); + Console->Print("Shutting down Infoserver..."); + for (int32_t i=0; i -#include - -class PClient; - -class PServer { -private: - int32_t mMaxClients; - int32_t mNumClients; - std::vector mClients; - -public: - PServer(); - ~PServer(); - - int32_t GetNumClients() const; - int32_t NewClient(); - PClient *GetClient(int32_t Client) const; - void Update(); - void Shutdown(); -}; +#pragma once + +#include +#include + +class PClient; + +class PServer { +private: + int32_t mMaxClients; + int32_t mNumClients; + std::vector mClients; + +public: + PServer(); + ~PServer(); + + int32_t GetNumClients() const; + int32_t NewClient(); + PClient *GetClient(int32_t Client) const; + void Update(); + void Shutdown(); +}; diff --git a/TinNS/Source/InfoServer/Sql.cxx b/TinNS/Source/InfoServer/Sql.cxx index 6dbdf96..d43c4e4 100644 --- a/TinNS/Source/InfoServer/Sql.cxx +++ b/TinNS/Source/InfoServer/Sql.cxx @@ -1,147 +1,147 @@ -#include -#include "InfoServer/Includes.hxx" -#include "Common/Includes.hxx" - -PMySQL::PMySQL() -{ - port = Config->GetOptionInt("sql_port"); - strncpy(host, Config->GetOption("sql_host").c_str(), 100); - strncpy(userName, Config->GetOption("sql_username").c_str(), 100); - strncpy(password, Config->GetOption("sql_password").c_str(), 100); - strncpy(database, Config->GetOption("global_sql_database").c_str(), 100); - - mKeepaliveDelay = (time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive - if (mKeepaliveDelay == 0) - { - Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]")); - } - else if (mKeepaliveDelay < 60) - { - Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay); - mKeepaliveDelay = 60; - } - mLastKeepaliveSent = 0; -} - -PMySQL::~PMySQL() -{ - Console->Print("Closing MySQL connection..."); - mysql_close(dbHandle); -} - -void PMySQL::Update() -{ - // MySQL keepalive - time_t t = std::time(NULL); - if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay)) - { - MYSQL_RES *result; - char query[24]; - snprintf (query, 24, "SELECT NOW()"); - - result = ResQuery(query); - if(!result) - { - Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); - ShowSQLError(); - return; - } - else - FreeSQLResult(result); - - mLastKeepaliveSent = std::time(NULL); -//Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]")); - } -} - -MYSQL *PMySQL::GetHandle() -{ - return dbHandle; -} - -bool PMySQL::Connect() -{ - Console->LPrint("Establishing link to MySQL Database..."); - - dbHandle = mysql_init(NULL); - - if(dbHandle) - { - //Console->Print("MySQL-Handle successfully initialized."); - } - else - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LClose(); - Console->Print(" MySQL-Handle couldn't be created!"); - exit(0); - } - - if(!mysql_real_connect(dbHandle, host, userName, password, database, port, NULL, 0)) - { - Console->LPrint(RED, BLACK, "[ERROR]"); - Console->LClose(); - Console->Print("Unable to connect to MySQL Database. MySQL returned: %s", mysql_error(dbHandle)); - return false; - } - else - { - Console->LPrint(GREEN, BLACK, "Success"); - Console->LClose(); - return true; - } -} - -MYSQL_RES *PMySQL::ResQuery(const char *query) -{ - int32_t sql_result = 0; - MYSQL_RES *result; - - sql_result = mysql_real_query(dbHandle, query, strlen(query)); - if(sql_result) - { - return NULL; - } - result = mysql_store_result(dbHandle); - if(!result) - { - return NULL; - } - - return result; -} - -int32_t PMySQL::Query(const char *query) -{ - int32_t sql_result = 0; - sql_result = mysql_real_query(dbHandle, query, strlen(query)); - - return sql_result; -} - -void PMySQL::ShowSQLError() -{ - Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(dbHandle)); -} - -void PMySQL::FreeSQLResult(MYSQL_RES *res) -{ - mysql_free_result(res); -} - -uint32_t PMySQL::GetLastInsertId() -{ - return mysql_insert_id(dbHandle); -} - -uint32_t PMySQL::EscapeString(const char *nText, char *dText, uint32_t dMaxLength) -{ - uint32_t nLength = strlen(nText); - uint32_t tMax = (dMaxLength - 1)/2; - if(nLength > tMax) - { - nLength = tMax; - } - - return mysql_real_escape_string(dbHandle, dText, nText, nLength); -} +#include +#include "InfoServer/Includes.hxx" +#include "Common/Includes.hxx" + +PMySQL::PMySQL() +{ + port = Config->GetOptionInt("sql_port"); + strncpy(host, Config->GetOption("sql_host").c_str(), 100); + strncpy(userName, Config->GetOption("sql_username").c_str(), 100); + strncpy(password, Config->GetOption("sql_password").c_str(), 100); + strncpy(database, Config->GetOption("global_sql_database").c_str(), 100); + + mKeepaliveDelay = (time_t) (Config->GetOptionInt("mysql_wait_timeout") * 0.9) ; // we take 90% of the wait_timeout to trigger keepalive + if (mKeepaliveDelay == 0) + { + Console->Print("%s MySQL keepalive disabled by config", Console->ColorText(GREEN, BLACK, "[Info]")); + } + else if (mKeepaliveDelay < 60) + { + Console->Print("%s Configuration option 'mysql_wait_timeout' is too low (%d sec). Reset to 60 sec.", Console->ColorText(YELLOW, BLACK, "[Notice]"), mKeepaliveDelay); + mKeepaliveDelay = 60; + } + mLastKeepaliveSent = 0; +} + +PMySQL::~PMySQL() +{ + Console->Print("Closing MySQL connection..."); + mysql_close(dbHandle); +} + +void PMySQL::Update() +{ + // MySQL keepalive + time_t t = std::time(NULL); + if ((mKeepaliveDelay > 0) && ((t - mLastKeepaliveSent) > mKeepaliveDelay)) + { + MYSQL_RES *result; + char query[24]; + snprintf (query, 24, "SELECT NOW()"); + + result = ResQuery(query); + if(!result) + { + Console->Print("%s Can't send InfoDB keepalive; MySQL returned", Console->ColorText(RED, BLACK, "[Error]")); + ShowSQLError(); + return; + } + else + FreeSQLResult(result); + + mLastKeepaliveSent = std::time(NULL); +//Console->Print("%s MySQL keepalive sent", Console->ColorText(GREEN, BLACK, "[Debug]")); + } +} + +MYSQL *PMySQL::GetHandle() +{ + return dbHandle; +} + +bool PMySQL::Connect() +{ + Console->LPrint("Establishing link to MySQL Database..."); + + dbHandle = mysql_init(NULL); + + if(dbHandle) + { + //Console->Print("MySQL-Handle successfully initialized."); + } + else + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LClose(); + Console->Print(" MySQL-Handle couldn't be created!"); + exit(0); + } + + if(!mysql_real_connect(dbHandle, host, userName, password, database, port, NULL, 0)) + { + Console->LPrint(RED, BLACK, "[ERROR]"); + Console->LClose(); + Console->Print("Unable to connect to MySQL Database. MySQL returned: %s", mysql_error(dbHandle)); + return false; + } + else + { + Console->LPrint(GREEN, BLACK, "Success"); + Console->LClose(); + return true; + } +} + +MYSQL_RES *PMySQL::ResQuery(const char *query) +{ + int32_t sql_result = 0; + MYSQL_RES *result; + + sql_result = mysql_real_query(dbHandle, query, strlen(query)); + if(sql_result) + { + return NULL; + } + result = mysql_store_result(dbHandle); + if(!result) + { + return NULL; + } + + return result; +} + +int32_t PMySQL::Query(const char *query) +{ + int32_t sql_result = 0; + sql_result = mysql_real_query(dbHandle, query, strlen(query)); + + return sql_result; +} + +void PMySQL::ShowSQLError() +{ + Console->Print(RED, BLACK, "MySQL Error: %s", mysql_error(dbHandle)); +} + +void PMySQL::FreeSQLResult(MYSQL_RES *res) +{ + mysql_free_result(res); +} + +uint32_t PMySQL::GetLastInsertId() +{ + return mysql_insert_id(dbHandle); +} + +uint32_t PMySQL::EscapeString(const char *nText, char *dText, uint32_t dMaxLength) +{ + uint32_t nLength = strlen(nText); + uint32_t tMax = (dMaxLength - 1)/2; + if(nLength > tMax) + { + nLength = tMax; + } + + return mysql_real_escape_string(dbHandle, dText, nText, nLength); +} diff --git a/TinNS/Source/InfoServer/Sql.hxx b/TinNS/Source/InfoServer/Sql.hxx index c58dc27..9a83d61 100644 --- a/TinNS/Source/InfoServer/Sql.hxx +++ b/TinNS/Source/InfoServer/Sql.hxx @@ -1,35 +1,35 @@ -#pragma once - -#include -#ifdef MYSQL_INC_DIR -#include -#else -#include -#endif - -class PMySQL { -private: - int32_t port; - char host[100]; - char userName[100]; - char password[100]; - char database[100]; - MYSQL *dbHandle; - time_t mKeepaliveDelay; - time_t mLastKeepaliveSent; - -public: - PMySQL(); - ~PMySQL(); - - void Update(); - MYSQL *GetHandle(); - - bool Connect(); - int32_t Query(const char *query); - MYSQL_RES *ResQuery(const char *query); - void ShowSQLError(); - void FreeSQLResult(MYSQL_RES *res); - uint32_t GetLastInsertId(); - uint32_t EscapeString(const char *nText, char *dText, uint32_t dMaxLength); -}; +#pragma once + +#include +#ifdef MYSQL_INC_DIR +#include +#else +#include +#endif + +class PMySQL { +private: + int32_t port; + char host[100]; + char userName[100]; + char password[100]; + char database[100]; + MYSQL *dbHandle; + time_t mKeepaliveDelay; + time_t mLastKeepaliveSent; + +public: + PMySQL(); + ~PMySQL(); + + void Update(); + MYSQL *GetHandle(); + + bool Connect(); + int32_t Query(const char *query); + MYSQL_RES *ResQuery(const char *query); + void ShowSQLError(); + void FreeSQLResult(MYSQL_RES *res); + uint32_t GetLastInsertId(); + uint32_t EscapeString(const char *nText, char *dText, uint32_t dMaxLength); +}; diff --git a/TinNS/Source/PatchServer/Client.cxx b/TinNS/Source/PatchServer/Client.cxx index e4b5036..1af7a18 100644 --- a/TinNS/Source/PatchServer/Client.cxx +++ b/TinNS/Source/PatchServer/Client.cxx @@ -1,71 +1,71 @@ -#include "PatchServer/Includes.hxx" -#include "Common/Includes.hxx" - -PClient::PClient(int32_t Index) -{ - mIndex = Index; - mConnection = PCC_NONE; -} - -PClient::~PClient() -{ - if(m_TCPConnection) - { - delete m_TCPConnection; - } -} - -int32_t PClient::GetIndex() const -{ - return mIndex; -} - -int32_t PClient::GetConnection() const -{ - return mConnection; -} - -const char *PClient::GetAddress() const -{ - return m_TCPConnection->getRemoteAddress(); -} - -void PClient::setTCPConnection(ConnectionTCP *conn) -{ - m_TCPConnection = conn; - mConnection = PCC_PATCH; -} - -ConnectionTCP *PClient::getTCPConn() -{ - return m_TCPConnection; -} - -void PClient::Update() -{ - if(m_TCPConnection) - { - if(m_TCPConnection->timeOut()) - { - Console->Print("Patchsocket: Client %i: timeout", mIndex); - PatchServer->ClientDisconnected(this); - } - else - { - if(!m_TCPConnection->update()) - { - PatchServer->ClientDisconnected(this); - } - } - } -} - -void PClient::PatchDisconnect() -{ - if(m_TCPConnection) - { - delete m_TCPConnection; - } - mConnection = PCC_NONE; - m_TCPConnection = 0; -} +#include "PatchServer/Includes.hxx" +#include "Common/Includes.hxx" + +PClient::PClient(int32_t Index) +{ + mIndex = Index; + mConnection = PCC_NONE; +} + +PClient::~PClient() +{ + if(m_TCPConnection) + { + delete m_TCPConnection; + } +} + +int32_t PClient::GetIndex() const +{ + return mIndex; +} + +int32_t PClient::GetConnection() const +{ + return mConnection; +} + +const char *PClient::GetAddress() const +{ + return m_TCPConnection->getRemoteAddress(); +} + +void PClient::setTCPConnection(ConnectionTCP *conn) +{ + m_TCPConnection = conn; + mConnection = PCC_PATCH; +} + +ConnectionTCP *PClient::getTCPConn() +{ + return m_TCPConnection; +} + +void PClient::Update() +{ + if(m_TCPConnection) + { + if(m_TCPConnection->timeOut()) + { + Console->Print("Patchsocket: Client %i: timeout", mIndex); + PatchServer->ClientDisconnected(this); + } + else + { + if(!m_TCPConnection->update()) + { + PatchServer->ClientDisconnected(this); + } + } + } +} + +void PClient::PatchDisconnect() +{ + if(m_TCPConnection) + { + delete m_TCPConnection; + } + mConnection = PCC_NONE; + m_TCPConnection = 0; +} diff --git a/TinNS/Source/PatchServer/Client.hxx b/TinNS/Source/PatchServer/Client.hxx index c0abe39..03c68c9 100644 --- a/TinNS/Source/PatchServer/Client.hxx +++ b/TinNS/Source/PatchServer/Client.hxx @@ -1,29 +1,29 @@ -#pragma once - -#include - -class ConnectionTCP; - -enum PClientConnection { - PCC_NONE = 0, - PCC_PATCH = 1 -}; - -class PClient { -private: - ConnectionTCP *m_TCPConnection; - int32_t mIndex; - int32_t mConnection; - -public: - PClient(int32_t Index); - ~PClient(); - - int32_t GetIndex() const; - int32_t GetConnection() const; - const char *GetAddress() const; - void setTCPConnection(ConnectionTCP *conn); - ConnectionTCP *getTCPConn(); - void Update(); - void PatchDisconnect(); -}; +#pragma once + +#include + +class ConnectionTCP; + +enum PClientConnection { + PCC_NONE = 0, + PCC_PATCH = 1 +}; + +class PClient { +private: + ConnectionTCP *m_TCPConnection; + int32_t mIndex; + int32_t mConnection; + +public: + PClient(int32_t Index); + ~PClient(); + + int32_t GetIndex() const; + int32_t GetConnection() const; + const char *GetAddress() const; + void setTCPConnection(ConnectionTCP *conn); + ConnectionTCP *getTCPConn(); + void Update(); + void PatchDisconnect(); +}; diff --git a/TinNS/Source/PatchServer/ConfigTemplate.hxx b/TinNS/Source/PatchServer/ConfigTemplate.hxx index 4b58417..080faef 100644 --- a/TinNS/Source/PatchServer/ConfigTemplate.hxx +++ b/TinNS/Source/PatchServer/ConfigTemplate.hxx @@ -1,16 +1,16 @@ -#pragma once - -static const char *PatchConfigTemplate[][2] = { - // {option_name, default_value} if default_value is empty string, it means option is mandatory - // List ends with empty string for option_name - {"server_version", "200"}, - {"patchserver_port", "8040"}, - {"patches_path", "./patches"}, - {"file_path", "./files"}, - {"max_file_xfers", "5"}, - {"patch_packet_size", "512"}, - {"maxclients", "5"}, - {"gm_slots", "2"}, - - {"", ""} // do not change this line (end mark) -}; +#pragma once + +static const char *PatchConfigTemplate[][2] = { + // {option_name, default_value} if default_value is empty string, it means option is mandatory + // List ends with empty string for option_name + {"server_version", "200"}, + {"patchserver_port", "8040"}, + {"patches_path", "./patches"}, + {"file_path", "./files"}, + {"max_file_xfers", "5"}, + {"patch_packet_size", "512"}, + {"maxclients", "5"}, + {"gm_slots", "2"}, + + {"", ""} // do not change this line (end mark) +}; diff --git a/TinNS/Source/PatchServer/Includes.cxx b/TinNS/Source/PatchServer/Includes.cxx index b6551de..b691713 100644 --- a/TinNS/Source/PatchServer/Includes.cxx +++ b/TinNS/Source/PatchServer/Includes.cxx @@ -1,61 +1,61 @@ -#include "PatchServer/Includes.hxx" -#include "Common/Includes.hxx" - -const char ServerVersion[] = TINNS_PATCH_VERSION; -const char SVNRevision[] = TINNS_SVN_REVISION; - -ServerSocket* ServerSock = 0; -PConsole *Console = 0; -PServer *Server = 0; -PConfig *Config = 0; -PFileSystem *Filesystem = 0; -PPatchServer *PatchServer = 0; - -bool InitTinNS() -{ - Console = new PConsole("log/patchserver.log"); // Make that from config file !!! - Console->Print("Starting TinNS Patchserver..."); - Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\"); - Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |"); - Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |"); - Console->Print(WHITE, BLUE, "| maintainer Akiko |"); - Console->Print(WHITE, BLUE, "| ========================================== |"); - Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |"); - Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |"); - Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |"); - Console->Print(WHITE, BLUE, "| - Namikon - Balm |"); - Console->Print(WHITE, BLUE, "| - Hammag |"); - Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); - Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |"); - Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |"); - Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); - Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |"); - Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/"); - - //char svnrev[10]; - //GetSVNRev(svnrev); - Console->LPrint("You are running TinNS Patchserver version"); - Console->LPrint(GREEN, BLACK, " %s", ServerVersion); - Console->LPrint(WHITE, BLACK, " - SVN Rev"); - Console->LPrint(GREEN, BLACK, " %s", SVNRevision); - Console->LClose(); - - Config = new PConfig(); - if(!Config->LoadOptions(PatchConfigTemplate ,"./conf/patchserver.conf")) - Shutdown(); - - ServerSock = new ServerSocket(); - Server = new PServer(); - PatchServer = new PPatchServer(); - - return true; -} - -void Shutdown() -{ - if(PatchServer) delete PatchServer; - if(Config) delete Config; - if(Console) delete Console; - if(ServerSock) delete ServerSock; - exit(0); -} +#include "PatchServer/Includes.hxx" +#include "Common/Includes.hxx" + +const char ServerVersion[] = TINNS_PATCH_VERSION; +const char SVNRevision[] = TINNS_SVN_REVISION; + +ServerSocket* ServerSock = 0; +PConsole *Console = 0; +PServer *Server = 0; +PConfig *Config = 0; +PFileSystem *Filesystem = 0; +PPatchServer *PatchServer = 0; + +bool InitTinNS() +{ + Console = new PConsole("log/patchserver.log"); // Make that from config file !!! + Console->Print("Starting TinNS Patchserver..."); + Console->Print(WHITE, BLUE, "/-------------------------------------------------------------------\\"); + Console->Print(WHITE, BLUE, "| TinNS (TinNS is not a Neocron Server) |"); + Console->Print(WHITE, BLUE, "| Copyright (C) 2005 Linux Addicted Community |"); + Console->Print(WHITE, BLUE, "| maintainer Akiko |"); + Console->Print(WHITE, BLUE, "| ========================================== |"); + Console->Print(WHITE, BLUE, "| Head coders: The packet analyzing team: |"); + Console->Print(WHITE, BLUE, "| - Akiko - MaxxJag |"); + Console->Print(WHITE, BLUE, "| - bakkdoor - Sting |"); + Console->Print(WHITE, BLUE, "| - Namikon - Balm |"); + Console->Print(WHITE, BLUE, "| - Hammag |"); + Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); + Console->Print(WHITE, BLUE, "| This project would'nt be at its current stage without the help |"); + Console->Print(WHITE, BLUE, "| from the NeoPolis team, special thanks to you guys! |"); + Console->Print(WHITE, BLUE, "|-------------------------------------------------------------------|"); + Console->Print(WHITE, BLUE, "| This project is under GPL, see any source file for more details |"); + Console->Print(WHITE, BLUE, "\\-------------------------------------------------------------------/"); + + //char svnrev[10]; + //GetSVNRev(svnrev); + Console->LPrint("You are running TinNS Patchserver version"); + Console->LPrint(GREEN, BLACK, " %s", ServerVersion); + Console->LPrint(WHITE, BLACK, " - SVN Rev"); + Console->LPrint(GREEN, BLACK, " %s", SVNRevision); + Console->LClose(); + + Config = new PConfig(); + if(!Config->LoadOptions(PatchConfigTemplate ,"./conf/patchserver.conf")) + Shutdown(); + + ServerSock = new ServerSocket(); + Server = new PServer(); + PatchServer = new PPatchServer(); + + return true; +} + +void Shutdown() +{ + if(PatchServer) delete PatchServer; + if(Config) delete Config; + if(Console) delete Console; + if(ServerSock) delete ServerSock; + exit(0); +} diff --git a/TinNS/Source/PatchServer/Includes.hxx b/TinNS/Source/PatchServer/Includes.hxx index b6fd386..16cf78d 100644 --- a/TinNS/Source/PatchServer/Includes.hxx +++ b/TinNS/Source/PatchServer/Includes.hxx @@ -1,19 +1,19 @@ -#pragma once - -#include "PatchServer/Client.hxx" -#include "PatchServer/ConfigTemplate.hxx" -#include "PatchServer/PatchServer.hxx" -#include "PatchServer/Server.hxx" - -extern class ServerSocket* ServerSock; -extern class PConsole *Console; -extern class PConfig *Config; -extern class PFileSystem *Filesystem; -extern class PServer *Server; -extern class PPatchServer *PatchServer; - -extern const char ServerVersion[]; -extern const char SVNRevision[]; - -bool InitTinNS(); -void Shutdown(); +#pragma once + +#include "PatchServer/Client.hxx" +#include "PatchServer/ConfigTemplate.hxx" +#include "PatchServer/PatchServer.hxx" +#include "PatchServer/Server.hxx" + +extern class ServerSocket* ServerSock; +extern class PConsole *Console; +extern class PConfig *Config; +extern class PFileSystem *Filesystem; +extern class PServer *Server; +extern class PPatchServer *PatchServer; + +extern const char ServerVersion[]; +extern const char SVNRevision[]; + +bool InitTinNS(); +void Shutdown(); diff --git a/TinNS/Source/PatchServer/Main.cxx b/TinNS/Source/PatchServer/Main.cxx index c2d4d83..0a5dba1 100644 --- a/TinNS/Source/PatchServer/Main.cxx +++ b/TinNS/Source/PatchServer/Main.cxx @@ -1,36 +1,36 @@ -#include -#include -#include -#include "PatchServer/Includes.hxx" -#include "Common/Includes.hxx" - -void signal_handler(int signal) -{ - if (signal == SIGINT) - Shutdown(); - else - psignal(signal, "Unkown signal: "); -} - -int main() -{ - signal(SIGINT, signal_handler); - - - if (!InitTinNS()) - while (true) - std::this_thread::sleep_for(std::chrono::seconds(1)); - - PatchServer->Start(); - Console->Print("Patchserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online")); - - while (true) - { - ServerSock->update(); - Server->Update(); - PatchServer->Update(); - // sched_yield(); - } - - return 0; -} +#include +#include +#include +#include "PatchServer/Includes.hxx" +#include "Common/Includes.hxx" + +void signal_handler(int signal) +{ + if (signal == SIGINT) + Shutdown(); + else + psignal(signal, "Unkown signal: "); +} + +int main() +{ + signal(SIGINT, signal_handler); + + + if (!InitTinNS()) + while (true) + std::this_thread::sleep_for(std::chrono::seconds(1)); + + PatchServer->Start(); + Console->Print("Patchserver is now %s. Waiting for clients...", Console->ColorText(GREEN, BLACK, "Online")); + + while (true) + { + ServerSock->update(); + Server->Update(); + PatchServer->Update(); + // sched_yield(); + } + + return 0; +} diff --git a/TinNS/Source/PatchServer/PatchServer.cxx b/TinNS/Source/PatchServer/PatchServer.cxx index ae4c1e7..8326dcc 100644 --- a/TinNS/Source/PatchServer/PatchServer.cxx +++ b/TinNS/Source/PatchServer/PatchServer.cxx @@ -1,502 +1,502 @@ -#include -#include -#include "PatchServer/Includes.hxx" -#include "Common/Includes.hxx" - -const uint16_t PATCH_PORT = 7000; - -struct PPatchState { - enum State - { - PS_UNKNOWN, - PS_CONNECTED, - PS_HANDSHAKE0, - PS_HANDSHAKE1, - PS_VERSIONREQUEST, - PS_GETPATCHORFILE, - PS_SENDPATCH, - PS_SENDFILE - } mState; - - uint16_t mSerial; - - uint32_t mCurrentPatch; - uint32_t mPatchOffset; - uint32_t mPatchSize; - std::FILE *mPatchFile; - - std::string mCurrentFile; - uint32_t mFileOffset; - uint32_t mFileSize; - PFile *mSendFile; - - bool mWaitSend; // wait-for-completition flag - PPatchState() - { - mState = PS_UNKNOWN; - mSerial = 0; - mCurrentPatch = 0; - mPatchOffset = 0; - mPatchFile = 0; - - mCurrentFile = ""; - mFileOffset = 0; - mFileSize = 0; - mSendFile = 0; - - mWaitSend = false; - }; - - ~PPatchState() - { - if(mPatchFile) - std::fclose(mPatchFile); - if(mSendFile) - Filesystem->Close(mSendFile); - } -}; - -// ------------------------------------------------------- - -PPatchServer::PPatchServer() -{ - //mNumClients = 1; - mNumFileTransfers = 0; -} - -PPatchServer::~PPatchServer() -{ - ServerSock->closeServer(); - - for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++) - delete i->second; -} - -void PPatchServer::Start() -{ - uint16_t Port = Config->GetOptionInt("patchserver_port"); - if(Port==0) - Port=PATCH_PORT; - - Console->LPrint("Starting Patchserver on port %i...", Port); - if(ServerSock->open(Port)) - { - Console->LPrint(GREEN, BLACK, "Success"); - } - else - { - Console->LPrint(RED, BLACK, "ERROR"); - } - Console->LClose(); - ServerSock->settimeout(0, 10000); -} - -void PPatchServer::Update() -{ - //ServerSock->update(); - - if(ServerSock->newConnection()) - { - int32_t clid = Server->NewClient(); - if(clid!=-1) - { - Console->Print(GREEN, BLACK, "Patchserver: client [%i] connected", clid); - PClient *Client = Server->GetClient(clid); - - ConnectionTCP* tcpConn = ServerSock->getTCPConnection(); - Client->setTCPConnection(tcpConn); - - Console->Print("Client address: %s", Client->GetAddress()); - //++mNumClients; - - PPatchState *state = new PPatchState(); - ClientStates.insert(std::make_pair(Client, state)); - state->mState = PPatchState::PS_CONNECTED; - } else - { - Console->Print("Patchserver: Client connection refused (server full?)"); - } - } - - for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();) - { - PClient *Client = i->first; - PPatchState *State = i->second; - // node gets erased in FinalizeClient, increment iterator now - ++i; - if(!ProcessClient(Client, State)) - { - FinalizeClient(Client, State); - } - } -} - -void PPatchServer::FinalizeClient(PClient *Client, PPatchState *State) -{ - Console->Print(RED, BLACK, "Patchserver: client %s disconnected", Client->GetAddress()); - Client->PatchDisconnect(); - ClientStates.erase(Client); - if(State->mPatchFile) - --mNumFileTransfers; - if(State->mSendFile) - --mNumFileTransfers; - delete State; -} - -// completes pending packets before disconnect -void PPatchServer::FinalizeClientDelayed(PClient *Client, PPatchState *State) -{ - Console->Print("Patchserver: client %i is about to be disconnected", Client->GetIndex()); - State->mWaitSend = true; -} - -void PPatchServer::ClientDisconnected(PClient *Client) -{ - PatchStateMap::iterator node = ClientStates.find(Client); - if(node == ClientStates.end()) - return; - - PPatchState *State = node->second; - FinalizeClient(Client, State); -} - -bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize) -{ - static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73}; - - ConnectionTCP *Socket = Client->getTCPConn(); - - switch(State->mState) - { - case PPatchState::PS_HANDSHAKE0 : - { - if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0280 && Packet[5]==0x64) - { - Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A)); - State->mState = PPatchState::PS_HANDSHAKE1; - } else - { - Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]); - return false; - } - - break; - } - - case PPatchState::PS_HANDSHAKE1 : - { - if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x6c) - State->mState = PPatchState::PS_VERSIONREQUEST; - else - { - Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(uint16_t*)&Packet[3]); - return false; - } - break; - } - default: - break; - } - - return true; -} - -bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize) -{ - static uint8_t VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - ConnectionTCP *Socket = Client->getTCPConn(); - if(PacketSize==9 && *(uint16_t*)&Packet[3]==0x007b) - { - State->mSerial = *(uint16_t*)&Packet[7]; - *(uint16_t*)&VERSIONPACKET[7]=State->mSerial; - uint32_t ver = Config->GetOptionInt("server_version"); - *(uint32_t*)&VERSIONPACKET[9]=ver; - Socket->write(VERSIONPACKET, 13); - State->mState = PPatchState::PS_GETPATCHORFILE; - } else - { - Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(uint16_t*)&Packet[3]); - return false; - } - - return true; -} - -bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize) -{ - static uint8_t STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static uint8_t STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - static uint8_t FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00}; - - ConnectionTCP *Socket = Client->getTCPConn(); - // request patch - if(PacketSize==13 && *(uint16_t*)&Packet[3]==0x007c) - { - int32_t nmax = Config->GetOptionInt("max_file_xfers"); - if(mNumFileTransfers>=nmax) - { - Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex()); - return false; - } - if(State->mPatchFile) - { - std::fclose(State->mPatchFile); - State->mPatchFile=0; - --mNumFileTransfers; - } - if(State->mSendFile) - { - Filesystem->Close(State->mSendFile); - State->mSendFile=0; - --mNumFileTransfers; - } - State->mSerial = *(uint16_t*)&Packet[7]; - State->mCurrentPatch = *(uint32_t*)&Packet[9]; - Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch); - if((bool)(State->mPatchSize = StartPatch(State))) - { - Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize); - *(uint16_t*)&STARTPATCH[7]=State->mSerial; - *(uint32_t*)&STARTPATCH[9]=State->mPatchSize; - Socket->write(STARTPATCH, 13); - State->mState = PPatchState::PS_SENDPATCH; - } else - { - Console->Print("Patchserver: Patch not available"); - *(uint16_t*)&FILEERROR[7]=State->mSerial; - Socket->write(FILEERROR, 9); - FinalizeClientDelayed(Client, State); - State->mState=PPatchState::PS_UNKNOWN; - return true; - } - } else - // request file - if(PacketSize > 9 && *(uint16_t*)&Packet[3]==0x004d) - { - int32_t nmax = Config->GetOptionInt("max_file_xfers"); - if(mNumFileTransfers>=nmax) - { - Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex()); - return false; - } - if(State->mPatchFile) - { - std::fclose(State->mPatchFile); - State->mPatchFile=0; - --mNumFileTransfers; - } - if(State->mSendFile) - { - Filesystem->Close(State->mSendFile); - State->mSendFile=0; - --mNumFileTransfers; - } - // request file - State->mSerial = *(uint16_t*)&Packet[7]; - char fn[256]; - strncpy(fn, (const char*)&Packet[10], Packet[9]); - fn[Packet[9]]=0; - State->mCurrentFile = fn; - - Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn); - if((bool)(State->mFileSize = StartFile(State))) - { - Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize); - *(uint16_t*)&STARTFILE[7]=State->mSerial; - *(uint32_t*)&STARTFILE[9]=State->mFileSize; - Socket->write(STARTFILE, 13); - State->mState = PPatchState::PS_SENDFILE; - } else - { - Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str()); - *(uint16_t*)&FILEERROR[7]=State->mSerial; - Socket->write(FILEERROR, 9); - FinalizeClientDelayed(Client, State); - State->mState=PPatchState::PS_UNKNOWN; - return true; - } - } else - // send patch data - if(PacketSize==17 && *(uint16_t*)&Packet[3]==0x007d) - { - State->mSerial = *(uint16_t*)&Packet[7]; - State->mCurrentPatch = *(uint32_t*)&Packet[9]; - State->mPatchOffset = *(uint32_t*)&Packet[13]; - if(!SendPatchData(Client, State)) - { - Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex()); - Console->Print("Patchserver: (probably due to garbage packets)"); - // state is undefined now, kill this client - return false; - } - } else - // send file data - if(PacketSize > 13 && *(uint16_t*)&Packet[3]==0x00037) - { - State->mSerial = *(uint16_t*)&Packet[7]; - State->mFileOffset = *(uint32_t*)&Packet[9]; - if(!SendFileData(Client, State)) - { - Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex()); - Console->Print("Patchserver: (probably due to garbage packets)"); - // state is undefined now, kill this client - return false; - } - } else - { - Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet"); - return false; - } - - return true; -} - -uint32_t PPatchServer::StartPatch(PPatchState *State) -{ - std::stringstream path; - char patchname[13]; - snprintf(patchname, 13, "sp%06d.pat", State->mCurrentPatch); - path << Config->GetOption("patches_path") << "/" << patchname << '\0'; - State->mPatchFile = std::fopen(path.str().c_str(), "rb"); - if(State->mPatchFile) - { - ++mNumFileTransfers; - fseek(State->mPatchFile, 0, SEEK_END); - uint32_t size = ftell(State->mPatchFile); - fseek(State->mPatchFile, 0, SEEK_SET); - return size; - } - return 0; -} - -bool PPatchServer::SendPatchData(PClient *Client, PPatchState *State) const -{ - if(!State->mPatchFile) - return false; - - uint16_t size = Config->GetOptionInt("patch_packet_size"); - - const int32_t BUFFERSIZE = 4082; - - size = std::min(BUFFERSIZE, std::max((int32_t)size, 64)); - static uint8_t Buffer[BUFFERSIZE+13]; - - if(fseek(State->mPatchFile, State->mPatchOffset, SEEK_SET)!=0) - return false; - - size = fread(&Buffer[13], 1, size, State->mPatchFile); - Buffer[0]=0xfe; - *(uint16_t*)&Buffer[1]=size+10; - Buffer[3]=0x39; - Buffer[4]=0x02; - Buffer[5]=0x00; - Buffer[6]=0x00; - *(uint16_t*)&Buffer[7]=State->mSerial; - *(uint32_t*)&Buffer[9]=size; - return Client->getTCPConn()->write(Buffer, size+13)==size+13; -} - -uint32_t PPatchServer::StartFile(PPatchState *State) -{ - // security checks: reject file paths containing ':', '..' or slashes/backslashes at the beginning - if((State->mCurrentFile.find(':') != std::string::npos) - || (State->mCurrentFile.find("..") != std::string::npos) - || (State->mCurrentFile.find('/') == 0) - || (State->mCurrentFile.find('\\') == 0)) - { - return 0; - } - - //std::stringstream path; - //path << Config->GetOption("file_path") << "/" << State->mCurrentFile << '\0'; - State->mSendFile = Filesystem->Open("", State->mCurrentFile.c_str(), Config->GetOption("file_path")); - if(State->mSendFile) - { - ++mNumFileTransfers; - uint32_t size = State->mSendFile->GetSize(); - return size; - } - return 0; -} - -bool PPatchServer::SendFileData(PClient *Client, PPatchState *State) const -{ - if(!State->mSendFile) - return false; - - uint16_t size = Config->GetOptionInt("patch_packet_size"); - - const int32_t BUFFERSIZE = 4082; - - size = std::min(BUFFERSIZE, std::max((int32_t)size, 1)); - static uint8_t Buffer[BUFFERSIZE+13]; - - State->mSendFile->Seek(State->mFileOffset); - - size = State->mSendFile->Read(&Buffer[13], size); - Buffer[0]=0xfe; - *(uint16_t*)&Buffer[1]=size+10; - Buffer[3]=0x3c; - Buffer[4]=0x02; - Buffer[5]=0x00; - Buffer[6]=0x00; - *(uint16_t*)&Buffer[7]=State->mSerial; - *(uint32_t*)&Buffer[9]=size; - return Client->getTCPConn()->write(Buffer, size+13)==size+13; -} - -bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State) -{ - static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b}; - - if(!State) - { - PatchStateMap::iterator node = ClientStates.find(Client); - if(node == ClientStates.end()) - return false; - - State = node->second; - } - - ConnectionTCP *Socket = Client->getTCPConn(); - - if(State->mWaitSend && Socket->getSendBufferSize()==0) - return false; - - if(State->mState==PPatchState::PS_CONNECTED) - { - Console->Print("Sending Handshake 0A"); - Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A)); - //short unsigned int packet = (short unsigned int) HANDSHAKE0A; - //Socket->write(htons(packet)); - State->mState = PPatchState::PS_HANDSHAKE0; - Socket->flushSendBuffer(); - } - - int32_t PacketSize = 0; - const uint8_t *Packet = Socket->read(&PacketSize); - if(PacketSize > 0) - { - switch(State->mState) - { - case PPatchState::PS_HANDSHAKE1 : - case PPatchState::PS_HANDSHAKE0 : - Console->Print("Handling Handshake 0 and 1"); - return HandleHandshake(Client, State, Packet, PacketSize); - - case PPatchState::PS_VERSIONREQUEST : - Console->Print("Handling Client Versionsrequest"); - return HandleVersionRequest(Client, State, Packet, PacketSize); - - case PPatchState::PS_GETPATCHORFILE : - case PPatchState::PS_SENDPATCH : - case PPatchState::PS_SENDFILE : - Console->Print("Getpatchforfile, sendpatch, sendfile"); - return HandleFileRequests(Client, State, Packet, PacketSize); - default: - break; - } - } - return true; -} +#include +#include +#include "PatchServer/Includes.hxx" +#include "Common/Includes.hxx" + +const uint16_t PATCH_PORT = 7000; + +struct PPatchState { + enum State + { + PS_UNKNOWN, + PS_CONNECTED, + PS_HANDSHAKE0, + PS_HANDSHAKE1, + PS_VERSIONREQUEST, + PS_GETPATCHORFILE, + PS_SENDPATCH, + PS_SENDFILE + } mState; + + uint16_t mSerial; + + uint32_t mCurrentPatch; + uint32_t mPatchOffset; + uint32_t mPatchSize; + std::FILE *mPatchFile; + + std::string mCurrentFile; + uint32_t mFileOffset; + uint32_t mFileSize; + PFile *mSendFile; + + bool mWaitSend; // wait-for-completition flag + PPatchState() + { + mState = PS_UNKNOWN; + mSerial = 0; + mCurrentPatch = 0; + mPatchOffset = 0; + mPatchFile = 0; + + mCurrentFile = ""; + mFileOffset = 0; + mFileSize = 0; + mSendFile = 0; + + mWaitSend = false; + }; + + ~PPatchState() + { + if(mPatchFile) + std::fclose(mPatchFile); + if(mSendFile) + Filesystem->Close(mSendFile); + } +}; + +// ------------------------------------------------------- + +PPatchServer::PPatchServer() +{ + //mNumClients = 1; + mNumFileTransfers = 0; +} + +PPatchServer::~PPatchServer() +{ + ServerSock->closeServer(); + + for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end(); i++) + delete i->second; +} + +void PPatchServer::Start() +{ + uint16_t Port = Config->GetOptionInt("patchserver_port"); + if(Port==0) + Port=PATCH_PORT; + + Console->LPrint("Starting Patchserver on port %i...", Port); + if(ServerSock->open(Port)) + { + Console->LPrint(GREEN, BLACK, "Success"); + } + else + { + Console->LPrint(RED, BLACK, "ERROR"); + } + Console->LClose(); + ServerSock->settimeout(0, 10000); +} + +void PPatchServer::Update() +{ + //ServerSock->update(); + + if(ServerSock->newConnection()) + { + int32_t clid = Server->NewClient(); + if(clid!=-1) + { + Console->Print(GREEN, BLACK, "Patchserver: client [%i] connected", clid); + PClient *Client = Server->GetClient(clid); + + ConnectionTCP* tcpConn = ServerSock->getTCPConnection(); + Client->setTCPConnection(tcpConn); + + Console->Print("Client address: %s", Client->GetAddress()); + //++mNumClients; + + PPatchState *state = new PPatchState(); + ClientStates.insert(std::make_pair(Client, state)); + state->mState = PPatchState::PS_CONNECTED; + } else + { + Console->Print("Patchserver: Client connection refused (server full?)"); + } + } + + for(PatchStateMap::iterator i=ClientStates.begin(); i!=ClientStates.end();) + { + PClient *Client = i->first; + PPatchState *State = i->second; + // node gets erased in FinalizeClient, increment iterator now + ++i; + if(!ProcessClient(Client, State)) + { + FinalizeClient(Client, State); + } + } +} + +void PPatchServer::FinalizeClient(PClient *Client, PPatchState *State) +{ + Console->Print(RED, BLACK, "Patchserver: client %s disconnected", Client->GetAddress()); + Client->PatchDisconnect(); + ClientStates.erase(Client); + if(State->mPatchFile) + --mNumFileTransfers; + if(State->mSendFile) + --mNumFileTransfers; + delete State; +} + +// completes pending packets before disconnect +void PPatchServer::FinalizeClientDelayed(PClient *Client, PPatchState *State) +{ + Console->Print("Patchserver: client %i is about to be disconnected", Client->GetIndex()); + State->mWaitSend = true; +} + +void PPatchServer::ClientDisconnected(PClient *Client) +{ + PatchStateMap::iterator node = ClientStates.find(Client); + if(node == ClientStates.end()) + return; + + PPatchState *State = node->second; + FinalizeClient(Client, State); +} + +bool PPatchServer::HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize) +{ + static const uint8_t HANDSHAKE1A[6]={0xfe, 0x03, 0x00, 0x80, 0x01, 0x73}; + + ConnectionTCP *Socket = Client->getTCPConn(); + + switch(State->mState) + { + case PPatchState::PS_HANDSHAKE0 : + { + if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0280 && Packet[5]==0x64) + { + Socket->write(HANDSHAKE1A, sizeof(HANDSHAKE1A)); + State->mState = PPatchState::PS_HANDSHAKE1; + } else + { + Console->Print("Patchserver protocol error (PS_HANDSHAKE0): invalid packet [%04x]", *(uint16_t*)&Packet[3]); + return false; + } + + break; + } + + case PPatchState::PS_HANDSHAKE1 : + { + if(PacketSize==6 && *(uint16_t*)&Packet[3]==0x0080 && Packet[5]==0x6c) + State->mState = PPatchState::PS_VERSIONREQUEST; + else + { + Console->Print("Patchserver protocol error (PS_HANDSHAKE1): invalid packet [%04x]", *(uint16_t*)&Packet[3]); + return false; + } + break; + } + default: + break; + } + + return true; +} + +bool PPatchServer::HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize) +{ + static uint8_t VERSIONPACKET[13]={0xfe, 0x0a, 0x00, 0x37, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + ConnectionTCP *Socket = Client->getTCPConn(); + if(PacketSize==9 && *(uint16_t*)&Packet[3]==0x007b) + { + State->mSerial = *(uint16_t*)&Packet[7]; + *(uint16_t*)&VERSIONPACKET[7]=State->mSerial; + uint32_t ver = Config->GetOptionInt("server_version"); + *(uint32_t*)&VERSIONPACKET[9]=ver; + Socket->write(VERSIONPACKET, 13); + State->mState = PPatchState::PS_GETPATCHORFILE; + } else + { + Console->Print("Patchserver protocol error (PS_VERSIONREQUEST): invalid packet [%04x]", *(uint16_t*)&Packet[3]); + return false; + } + + return true; +} + +bool PPatchServer::HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize) +{ + static uint8_t STARTPATCH[13]={0xfe, 0x0a, 0x00, 0x38, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t STARTFILE[13]={0xfe, 0x0a, 0x00, 0x3b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + static uint8_t FILEERROR[9]={0xfe, 0x06, 0x00, 0x3d, 0x02, 0x00, 0x00, 0x00, 0x00}; + + ConnectionTCP *Socket = Client->getTCPConn(); + // request patch + if(PacketSize==13 && *(uint16_t*)&Packet[3]==0x007c) + { + int32_t nmax = Config->GetOptionInt("max_file_xfers"); + if(mNumFileTransfers>=nmax) + { + Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex()); + return false; + } + if(State->mPatchFile) + { + std::fclose(State->mPatchFile); + State->mPatchFile=0; + --mNumFileTransfers; + } + if(State->mSendFile) + { + Filesystem->Close(State->mSendFile); + State->mSendFile=0; + --mNumFileTransfers; + } + State->mSerial = *(uint16_t*)&Packet[7]; + State->mCurrentPatch = *(uint32_t*)&Packet[9]; + Console->Print("Patchserver: Patch request from client %i (v%i)", Client->GetIndex(), State->mCurrentPatch); + if((bool)(State->mPatchSize = StartPatch(State))) + { + Console->Print("Patchserver: Patch is available, %d bytes", State->mPatchSize); + *(uint16_t*)&STARTPATCH[7]=State->mSerial; + *(uint32_t*)&STARTPATCH[9]=State->mPatchSize; + Socket->write(STARTPATCH, 13); + State->mState = PPatchState::PS_SENDPATCH; + } else + { + Console->Print("Patchserver: Patch not available"); + *(uint16_t*)&FILEERROR[7]=State->mSerial; + Socket->write(FILEERROR, 9); + FinalizeClientDelayed(Client, State); + State->mState=PPatchState::PS_UNKNOWN; + return true; + } + } else + // request file + if(PacketSize > 9 && *(uint16_t*)&Packet[3]==0x004d) + { + int32_t nmax = Config->GetOptionInt("max_file_xfers"); + if(mNumFileTransfers>=nmax) + { + Console->Print("Patchserver: max file xfers exceed, killing client %i", Client->GetIndex()); + return false; + } + if(State->mPatchFile) + { + std::fclose(State->mPatchFile); + State->mPatchFile=0; + --mNumFileTransfers; + } + if(State->mSendFile) + { + Filesystem->Close(State->mSendFile); + State->mSendFile=0; + --mNumFileTransfers; + } + // request file + State->mSerial = *(uint16_t*)&Packet[7]; + char fn[256]; + strncpy(fn, (const char*)&Packet[10], Packet[9]); + fn[Packet[9]]=0; + State->mCurrentFile = fn; + + Console->Print("Patchserver: File request from client %i (%s)", Client->GetIndex(), fn); + if((bool)(State->mFileSize = StartFile(State))) + { + Console->Print("Patchserver: File %s is available, %d bytes", State->mCurrentFile.c_str(), State->mFileSize); + *(uint16_t*)&STARTFILE[7]=State->mSerial; + *(uint32_t*)&STARTFILE[9]=State->mFileSize; + Socket->write(STARTFILE, 13); + State->mState = PPatchState::PS_SENDFILE; + } else + { + Console->Print("Patchserver: Requested file %s not available", State->mCurrentFile.c_str()); + *(uint16_t*)&FILEERROR[7]=State->mSerial; + Socket->write(FILEERROR, 9); + FinalizeClientDelayed(Client, State); + State->mState=PPatchState::PS_UNKNOWN; + return true; + } + } else + // send patch data + if(PacketSize==17 && *(uint16_t*)&Packet[3]==0x007d) + { + State->mSerial = *(uint16_t*)&Packet[7]; + State->mCurrentPatch = *(uint32_t*)&Packet[9]; + State->mPatchOffset = *(uint32_t*)&Packet[13]; + if(!SendPatchData(Client, State)) + { + Console->Print("Patchserver: SendPatchData failed on client %i", Client->GetIndex()); + Console->Print("Patchserver: (probably due to garbage packets)"); + // state is undefined now, kill this client + return false; + } + } else + // send file data + if(PacketSize > 13 && *(uint16_t*)&Packet[3]==0x00037) + { + State->mSerial = *(uint16_t*)&Packet[7]; + State->mFileOffset = *(uint32_t*)&Packet[9]; + if(!SendFileData(Client, State)) + { + Console->Print("Patchserver: SendFileData failed on client %i", Client->GetIndex()); + Console->Print("Patchserver: (probably due to garbage packets)"); + // state is undefined now, kill this client + return false; + } + } else + { + Console->Print("Patchserver protocol error (PS_GETPATCHORFILE): unknown packet"); + return false; + } + + return true; +} + +uint32_t PPatchServer::StartPatch(PPatchState *State) +{ + std::stringstream path; + char patchname[13]; + snprintf(patchname, 13, "sp%06d.pat", State->mCurrentPatch); + path << Config->GetOption("patches_path") << "/" << patchname << '\0'; + State->mPatchFile = std::fopen(path.str().c_str(), "rb"); + if(State->mPatchFile) + { + ++mNumFileTransfers; + fseek(State->mPatchFile, 0, SEEK_END); + uint32_t size = ftell(State->mPatchFile); + fseek(State->mPatchFile, 0, SEEK_SET); + return size; + } + return 0; +} + +bool PPatchServer::SendPatchData(PClient *Client, PPatchState *State) const +{ + if(!State->mPatchFile) + return false; + + uint16_t size = Config->GetOptionInt("patch_packet_size"); + + const int32_t BUFFERSIZE = 4082; + + size = std::min(BUFFERSIZE, std::max((int32_t)size, 64)); + static uint8_t Buffer[BUFFERSIZE+13]; + + if(fseek(State->mPatchFile, State->mPatchOffset, SEEK_SET)!=0) + return false; + + size = fread(&Buffer[13], 1, size, State->mPatchFile); + Buffer[0]=0xfe; + *(uint16_t*)&Buffer[1]=size+10; + Buffer[3]=0x39; + Buffer[4]=0x02; + Buffer[5]=0x00; + Buffer[6]=0x00; + *(uint16_t*)&Buffer[7]=State->mSerial; + *(uint32_t*)&Buffer[9]=size; + return Client->getTCPConn()->write(Buffer, size+13)==size+13; +} + +uint32_t PPatchServer::StartFile(PPatchState *State) +{ + // security checks: reject file paths containing ':', '..' or slashes/backslashes at the beginning + if((State->mCurrentFile.find(':') != std::string::npos) + || (State->mCurrentFile.find("..") != std::string::npos) + || (State->mCurrentFile.find('/') == 0) + || (State->mCurrentFile.find('\\') == 0)) + { + return 0; + } + + //std::stringstream path; + //path << Config->GetOption("file_path") << "/" << State->mCurrentFile << '\0'; + State->mSendFile = Filesystem->Open("", State->mCurrentFile.c_str(), Config->GetOption("file_path")); + if(State->mSendFile) + { + ++mNumFileTransfers; + uint32_t size = State->mSendFile->GetSize(); + return size; + } + return 0; +} + +bool PPatchServer::SendFileData(PClient *Client, PPatchState *State) const +{ + if(!State->mSendFile) + return false; + + uint16_t size = Config->GetOptionInt("patch_packet_size"); + + const int32_t BUFFERSIZE = 4082; + + size = std::min(BUFFERSIZE, std::max((int32_t)size, 1)); + static uint8_t Buffer[BUFFERSIZE+13]; + + State->mSendFile->Seek(State->mFileOffset); + + size = State->mSendFile->Read(&Buffer[13], size); + Buffer[0]=0xfe; + *(uint16_t*)&Buffer[1]=size+10; + Buffer[3]=0x3c; + Buffer[4]=0x02; + Buffer[5]=0x00; + Buffer[6]=0x00; + *(uint16_t*)&Buffer[7]=State->mSerial; + *(uint32_t*)&Buffer[9]=size; + return Client->getTCPConn()->write(Buffer, size+13)==size+13; +} + +bool PPatchServer::ProcessClient(PClient *Client, PPatchState *State) +{ + static const uint8_t HANDSHAKE0A[6]={0xfe, 0x03, 0x00, 0x80, 0x03, 0x6b}; + + if(!State) + { + PatchStateMap::iterator node = ClientStates.find(Client); + if(node == ClientStates.end()) + return false; + + State = node->second; + } + + ConnectionTCP *Socket = Client->getTCPConn(); + + if(State->mWaitSend && Socket->getSendBufferSize()==0) + return false; + + if(State->mState==PPatchState::PS_CONNECTED) + { + Console->Print("Sending Handshake 0A"); + Socket->write(HANDSHAKE0A, sizeof(HANDSHAKE0A)); + //short unsigned int packet = (short unsigned int) HANDSHAKE0A; + //Socket->write(htons(packet)); + State->mState = PPatchState::PS_HANDSHAKE0; + Socket->flushSendBuffer(); + } + + int32_t PacketSize = 0; + const uint8_t *Packet = Socket->read(&PacketSize); + if(PacketSize > 0) + { + switch(State->mState) + { + case PPatchState::PS_HANDSHAKE1 : + case PPatchState::PS_HANDSHAKE0 : + Console->Print("Handling Handshake 0 and 1"); + return HandleHandshake(Client, State, Packet, PacketSize); + + case PPatchState::PS_VERSIONREQUEST : + Console->Print("Handling Client Versionsrequest"); + return HandleVersionRequest(Client, State, Packet, PacketSize); + + case PPatchState::PS_GETPATCHORFILE : + case PPatchState::PS_SENDPATCH : + case PPatchState::PS_SENDFILE : + Console->Print("Getpatchforfile, sendpatch, sendfile"); + return HandleFileRequests(Client, State, Packet, PacketSize); + default: + break; + } + } + return true; +} diff --git a/TinNS/Source/PatchServer/PatchServer.hxx b/TinNS/Source/PatchServer/PatchServer.hxx index 9d517b2..ae2c041 100644 --- a/TinNS/Source/PatchServer/PatchServer.hxx +++ b/TinNS/Source/PatchServer/PatchServer.hxx @@ -1,38 +1,38 @@ -#pragma once - -#include -#include - -class PClient; -struct PPatchState; - -class PPatchServer { -private: - int mNumClients; - int mNumFileTransfers; - typedef std::map PatchStateMap; - PatchStateMap ClientStates; - -protected: - bool ProcessClient(PClient *Client, PPatchState *State = nullptr); -// uint32_t StartPatch(PClient *Client, PPatchState *State); - uint32_t StartPatch(PPatchState *State); - bool SendPatchData(PClient *Client, PPatchState *State) const; -// u32 StartFile(PClient *Client, PPatchState *State); - uint32_t StartFile(PPatchState *State); - bool SendFileData(PClient *Client, PPatchState *State) const; - void FinalizeClient(PClient *Client, PPatchState *State); - void FinalizeClientDelayed(PClient *Client, PPatchState *State); - - bool HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize); - bool HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize); - bool HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize); - -public: - PPatchServer(); - ~PPatchServer(); - - void Start(); - void Update(); - void ClientDisconnected(PClient *Client); -}; +#pragma once + +#include +#include + +class PClient; +struct PPatchState; + +class PPatchServer { +private: + int mNumClients; + int mNumFileTransfers; + typedef std::map PatchStateMap; + PatchStateMap ClientStates; + +protected: + bool ProcessClient(PClient *Client, PPatchState *State = nullptr); +// uint32_t StartPatch(PClient *Client, PPatchState *State); + uint32_t StartPatch(PPatchState *State); + bool SendPatchData(PClient *Client, PPatchState *State) const; +// u32 StartFile(PClient *Client, PPatchState *State); + uint32_t StartFile(PPatchState *State); + bool SendFileData(PClient *Client, PPatchState *State) const; + void FinalizeClient(PClient *Client, PPatchState *State); + void FinalizeClientDelayed(PClient *Client, PPatchState *State); + + bool HandleHandshake(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize); + bool HandleVersionRequest(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize); + bool HandleFileRequests(PClient *Client, PPatchState *State, const uint8_t *Packet, int32_t PacketSize); + +public: + PPatchServer(); + ~PPatchServer(); + + void Start(); + void Update(); + void ClientDisconnected(PClient *Client); +}; diff --git a/TinNS/Source/PatchServer/Server.cxx b/TinNS/Source/PatchServer/Server.cxx index 0ee9260..6eefaac 100644 --- a/TinNS/Source/PatchServer/Server.cxx +++ b/TinNS/Source/PatchServer/Server.cxx @@ -1,95 +1,95 @@ -#include "PatchServer/Includes.hxx" -#include "Common/Includes.hxx" - -PServer::PServer() -{ - mNumClients = 0; - mMaxClients = Config->GetOptionInt("maxclients"); - mGMSlots = Config->GetOptionInt("gm_slots"); - - if (mMaxClients==0) - mMaxClients=1; - if (mGMSlots==0) - mGMSlots=1; - mClients.reserve(mMaxClients + mGMSlots); - for (int32_t i=0; iPrint("%d %d", mMaxClients, mGMSlots); - if (mNumClients==mMaxClients+mGMSlots) - return -1; - for (int32_t i=0; i= mMaxClients+mGMSlots) - return 0; - - return mClients[Client]; -} - -void PServer::Update() -{ - for (int32_t i=0; iUpdate(); - if (mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0) - { - Console->Print("Removing client ..."); - delete mClients[i]; - mClients[i]=0; - --mNumClients; - } - } - } -} - -void PServer::Shutdown() -{ - Console->Print("======================"); - Console->Print("Shutting down Patchserver..."); - for (int32_t i=0; iGetOptionInt("maxclients"); + mGMSlots = Config->GetOptionInt("gm_slots"); + + if (mMaxClients==0) + mMaxClients=1; + if (mGMSlots==0) + mGMSlots=1; + mClients.reserve(mMaxClients + mGMSlots); + for (int32_t i=0; iPrint("%d %d", mMaxClients, mGMSlots); + if (mNumClients==mMaxClients+mGMSlots) + return -1; + for (int32_t i=0; i= mMaxClients+mGMSlots) + return 0; + + return mClients[Client]; +} + +void PServer::Update() +{ + for (int32_t i=0; iUpdate(); + if (mClients[i]->GetConnection()==PCC_NONE && mClients[i]->getTCPConn() == 0) + { + Console->Print("Removing client ..."); + delete mClients[i]; + mClients[i]=0; + --mNumClients; + } + } + } +} + +void PServer::Shutdown() +{ + Console->Print("======================"); + Console->Print("Shutting down Patchserver..."); + for (int32_t i=0; i -#include - -class PClient; - -class PServer { -private: - int32_t mMaxClients; - int32_t mGMSlots; - int32_t mNumClients; - std::vector mClients; - -public: - PServer(); - ~PServer(); - - int32_t GetMaxClients() const; - int32_t GetGMSlots() const; - int32_t GetNumClients() const; - int32_t NewClient(); - PClient *GetClient(int32_t Client) const; - void Update(); - void Shutdown(); -}; +#pragma once + +#include +#include + +class PClient; + +class PServer { +private: + int32_t mMaxClients; + int32_t mGMSlots; + int32_t mNumClients; + std::vector mClients; + +public: + PServer(); + ~PServer(); + + int32_t GetMaxClients() const; + int32_t GetGMSlots() const; + int32_t GetNumClients() const; + int32_t NewClient(); + PClient *GetClient(int32_t Client) const; + void Update(); + void Shutdown(); +};