mirror of
https://github.com/EQEmu/Server.git
synced 2026-04-03 21:42:26 +00:00
Merge branch 'master' into lsid
This commit is contained in:
commit
e0391dfcb8
@ -17,10 +17,7 @@
|
|||||||
|:---:|:---:|:---:|
|
|:---:|:---:|:---:|
|
||||||
|**Install Count**|||
|
|**Install Count**|||
|
||||||
### > Windows
|
### > Windows
|
||||||
* [Easy Install](http://wiki.eqemulator.org/p?Akkas_PEQ_Server_Installer&frm=Main#from-scratch-installation-instructions-windows)
|
* [Install](https://github.com/EQEmu/Server/wiki/Windows-Server)
|
||||||
* [Advanced Setup](http://wiki.eqemulator.org/p?Complete_Windows-based_Server_Setup_Guide)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### > Debian/Ubuntu/CentOS/Fedora
|
### > Debian/Ubuntu/CentOS/Fedora
|
||||||
* You can use curl or wget to kick off the installer (whichever your OS has)
|
* You can use curl or wget to kick off the installer (whichever your OS has)
|
||||||
@ -55,7 +52,7 @@ forum, although pull requests will be much quicker and easier on all parties.
|
|||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
- [EQEmulator Forums](http://www.eqemulator.org/forums)
|
||||||
- [EQEmulator Wiki](http://wiki.eqemulator.org/i?M=Wiki)
|
- [EQEmulator Wiki](https://github.com/EQEmu/Server/wiki)
|
||||||
|
|
||||||
## Related Repositories
|
## Related Repositories
|
||||||
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
|
* [ProjectEQ Quests](https://github.com/ProjectEQ/projecteqquests)
|
||||||
|
|||||||
@ -472,16 +472,6 @@ bool Database::CheckDatabaseConversions() {
|
|||||||
CheckDatabaseConvertPPDeblob();
|
CheckDatabaseConvertPPDeblob();
|
||||||
CheckDatabaseConvertCorpseDeblob();
|
CheckDatabaseConvertCorpseDeblob();
|
||||||
|
|
||||||
/* Fetch EQEmu Server script */
|
|
||||||
if (!std::ifstream("eqemu_server.pl")){
|
|
||||||
std::cout << "Pulling down automatic database upgrade script..." << std::endl;
|
|
||||||
#ifdef _WIN32
|
|
||||||
system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl'); if ($response->is_success){ open(FILE, '> eqemu_server.pl'); print FILE $response->decoded_content; close(FILE); }\"");
|
|
||||||
#else
|
|
||||||
system("wget --no-check-certificate -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Run EQEmu Server script (Checks for database updates) */
|
/* Run EQEmu Server script (Checks for database updates) */
|
||||||
system("perl eqemu_server.pl ran_from_world");
|
system("perl eqemu_server.pl ran_from_world");
|
||||||
|
|
||||||
|
|||||||
@ -23,351 +23,112 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
std::string EQEmuConfig::ConfigFile = "eqemu_config.xml";
|
std::string EQEmuConfig::ConfigFile = "eqemu_config.json";
|
||||||
EQEmuConfig *EQEmuConfig::_config = nullptr;
|
EQEmuConfig *EQEmuConfig::_config = nullptr;
|
||||||
|
|
||||||
void EQEmuConfig::do_world(TiXmlElement *ele)
|
void EQEmuConfig::parse_config() {
|
||||||
{
|
|
||||||
const char *text;
|
ShortName = _root["server"]["world"].get("shortname", "").asString();
|
||||||
TiXmlElement * sub_ele;;
|
LongName = _root["server"]["world"].get("longname", "").asString();
|
||||||
text = ParseTextBlock(ele, "shortname");
|
WorldAddress = _root["server"]["world"].get("address", "").asString();
|
||||||
if (text) {
|
LocalAddress = _root["server"]["world"].get("localaddress", "").asString();
|
||||||
ShortName = text;
|
MaxClients = atoi(_root["server"]["world"].get("maxclients", "-1").asString().c_str());
|
||||||
}
|
SharedKey = _root["server"]["world"].get("key", "").asString();
|
||||||
text = ParseTextBlock(ele, "longname");
|
LoginCount = 0;
|
||||||
if (text) {
|
|
||||||
LongName = text;
|
if (_root["server"]["world"]["loginserver"].isObject()) {
|
||||||
}
|
LoginHost = _root["server"]["world"]["loginserver"].get("host", "login.eqemulator.net").asString();
|
||||||
text = ParseTextBlock(ele, "address", true);
|
LoginPort = atoi(_root["server"]["world"]["loginserver"].get("port", "5998").asString().c_str());
|
||||||
if (text) {
|
LoginLegacy = false;
|
||||||
WorldAddress = text;
|
if (_root["server"]["world"]["loginserver"].get("legacy", "0").asString() == "1") LoginLegacy = true;
|
||||||
}
|
LoginAccount = _root["server"]["world"]["loginserver"].get("account", "").asString();
|
||||||
text = ParseTextBlock(ele, "localaddress", true);
|
LoginPassword = _root["server"]["world"]["loginserver"].get("password", "").asString();
|
||||||
if (text) {
|
|
||||||
LocalAddress = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "maxclients", true);
|
|
||||||
if (text) {
|
|
||||||
MaxClients = atoi(text);
|
|
||||||
}
|
|
||||||
// Get the <key> element
|
|
||||||
text = ParseTextBlock(ele, "key", true);
|
|
||||||
if (text) {
|
|
||||||
SharedKey = text;
|
|
||||||
}
|
|
||||||
// Get the <loginserver> element
|
|
||||||
sub_ele = ele->FirstChildElement("loginserver");
|
|
||||||
if (sub_ele) {
|
|
||||||
text = ParseTextBlock(sub_ele, "host", true);
|
|
||||||
if (text) {
|
|
||||||
LoginHost = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "port", true);
|
|
||||||
if (text) {
|
|
||||||
LoginPort = atoi(text);
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "legacy", true);
|
|
||||||
if (text) {
|
|
||||||
LoginLegacy = atoi(text) > 0 ? true : false;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "account", true);
|
|
||||||
if (text) {
|
|
||||||
LoginAccount = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "password", true);
|
|
||||||
if (text) {
|
|
||||||
LoginPassword = text;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
char str[32];
|
char str[32];
|
||||||
|
loginlist.Clear();
|
||||||
do {
|
do {
|
||||||
sprintf(str, "loginserver%i", ++LoginCount);
|
sprintf(str, "loginserver%i", ++LoginCount);
|
||||||
sub_ele = ele->FirstChildElement(str);
|
if (!_root["server"]["world"][str].isObject()) {
|
||||||
if (sub_ele) {
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
auto loginconfig = new LoginConfig;
|
auto loginconfig = new LoginConfig;
|
||||||
text = ParseTextBlock(sub_ele, "host", true);
|
loginconfig->LoginHost = _root["server"]["world"][str].get("host", "login.eqemulator.net").asString();
|
||||||
if (text) {
|
loginconfig->LoginPort = atoi(_root["server"]["world"][str].get("port", "5998").asString().c_str());
|
||||||
loginconfig->LoginHost = text;
|
loginconfig->LoginAccount = _root["server"]["world"][str].get("account", "").asString();
|
||||||
}
|
loginconfig->LoginPassword = _root["server"]["world"][str].get("password", "").asString();
|
||||||
text = ParseTextBlock(sub_ele, "port", true);
|
|
||||||
if (text) {
|
loginconfig->LoginLegacy = false;
|
||||||
loginconfig->LoginPort = atoi(text);
|
if (_root["server"]["world"][str].get("legacy", "0").asString() == "1") loginconfig->LoginLegacy = true;
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "legacy", true);
|
|
||||||
if (text) {
|
|
||||||
loginconfig->LoginLegacy = atoi(text) > 0 ? true : false;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "account", true);
|
|
||||||
if (text) {
|
|
||||||
loginconfig->LoginAccount = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(sub_ele, "password", true);
|
|
||||||
if (text) {
|
|
||||||
loginconfig->LoginPassword = text;
|
|
||||||
}
|
|
||||||
loginlist.Insert(loginconfig);
|
loginlist.Insert(loginconfig);
|
||||||
}
|
} while (LoginCount < 100);
|
||||||
} while (sub_ele);
|
|
||||||
}
|
|
||||||
// Check for locked
|
|
||||||
sub_ele = ele->FirstChildElement("locked");
|
|
||||||
if (sub_ele != nullptr) {
|
|
||||||
Locked = true;
|
|
||||||
}
|
|
||||||
// Get the <tcp> element
|
|
||||||
sub_ele = ele->FirstChildElement("tcp");
|
|
||||||
if (sub_ele != nullptr) {
|
|
||||||
text = sub_ele->Attribute("ip");
|
|
||||||
if (text) {
|
|
||||||
WorldIP = text;
|
|
||||||
}
|
|
||||||
text = sub_ele->Attribute("port");
|
|
||||||
if (text) {
|
|
||||||
WorldTCPPort = atoi(text);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub_ele = ele->FirstChildElement("telnet");
|
|
||||||
if (sub_ele != nullptr) {
|
|
||||||
text = sub_ele->Attribute("ip");
|
|
||||||
if (text) {
|
|
||||||
TelnetIP = text;
|
|
||||||
}
|
|
||||||
text = sub_ele->Attribute("port");
|
|
||||||
if (text) {
|
|
||||||
TelnetTCPPort = atoi(text);
|
|
||||||
}
|
|
||||||
text = sub_ele->Attribute("enabled");
|
|
||||||
if (text && !strcasecmp(text, "true")) {
|
|
||||||
TelnetEnabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the <http> element
|
//<locked> from xml converts to json as locked: "", so i default to "false".
|
||||||
sub_ele = ele->FirstChildElement("http");
|
//The only way to enable locked is by switching to true, meaning this value is always false until manually set true
|
||||||
if (sub_ele != nullptr) {
|
Locked = false;
|
||||||
// text = sub_ele->Attribute("ip");
|
if (_root["server"]["world"].get("locked", "false").asString() == "true") Locked = true;
|
||||||
// if (text)
|
WorldIP = _root["server"]["world"]["tcp"].get("host", "127.0.0.1").asString();
|
||||||
// WorldIP=text;
|
WorldTCPPort = atoi(_root["server"]["world"]["tcp"].get("port", "9000").asString().c_str());
|
||||||
text = sub_ele->Attribute("mimefile");
|
|
||||||
if (text) {
|
TelnetIP = _root["server"]["world"]["telnet"].get("ip", "127.0.0.1").asString();
|
||||||
WorldHTTPMimeFile = text;
|
TelnetTCPPort = atoi(_root["server"]["world"]["telnet"].get("port", "9001").asString().c_str());
|
||||||
}
|
TelnetEnabled = false;
|
||||||
text = sub_ele->Attribute("port");
|
if (_root["server"]["world"]["telnet"].get("enabled", "false").asString() == "true") TelnetEnabled = true;
|
||||||
if (text) {
|
|
||||||
WorldHTTPPort = atoi(text);
|
WorldHTTPMimeFile = _root["server"]["world"]["http"].get("mimefile", "mime.types").asString();
|
||||||
}
|
WorldHTTPPort = atoi(_root["server"]["world"]["http"].get("port", "9080").asString().c_str());
|
||||||
text = sub_ele->Attribute("enabled");
|
WorldHTTPEnabled = false;
|
||||||
if (text && !strcasecmp(text, "true")) {
|
if (_root["server"]["world"]["http"].get("enabled", "false").asString() == "true") WorldHTTPEnabled = true;
|
||||||
WorldHTTPEnabled = true;
|
|
||||||
}
|
ChatHost = _root["server"]["chatserver"].get("host", "eqchat.eqemulator.net").asString();
|
||||||
}
|
ChatPort = atoi(_root["server"]["chatserver"].get("port", "7778").asString().c_str());
|
||||||
|
|
||||||
|
MailHost = _root["server"]["mailserver"].get("host", "eqmail.eqemulator.net").asString();
|
||||||
|
MailPort = atoi(_root["server"]["mailserver"].get("port", "7778").asString().c_str());
|
||||||
|
|
||||||
|
DatabaseUsername = _root["server"]["database"].get("username", "eq").asString();
|
||||||
|
DatabasePassword = _root["server"]["database"].get("password", "eq").asString();
|
||||||
|
DatabaseHost = _root["server"]["database"].get("host", "localhost").asString();
|
||||||
|
DatabasePort = atoi(_root["server"]["database"].get("port", "3306").asString().c_str());
|
||||||
|
DatabaseDB = _root["server"]["database"].get("db", "eq").asString();
|
||||||
|
|
||||||
|
QSDatabaseHost = _root["server"]["qsdatabase"].get("host", "localhost").asString();
|
||||||
|
QSDatabasePort = atoi(_root["server"]["qsdatabase"].get("port", "3306").asString().c_str());
|
||||||
|
QSDatabaseUsername = _root["server"]["qsdatabase"].get("username", "eq").asString();
|
||||||
|
QSDatabasePassword = _root["server"]["qsdatabase"].get("password", "eq").asString();
|
||||||
|
QSDatabaseDB = _root["server"]["qsdatabase"].get("db", "eq").asString();
|
||||||
|
|
||||||
|
DefaultStatus = atoi(_root["server"]["zones"].get("defaultstatus", 0).asString().c_str());
|
||||||
|
ZonePortLow = atoi(_root["server"]["zones"]["ports"].get("low", "7000").asString().c_str());
|
||||||
|
ZonePortHigh = atoi(_root["server"]["zones"]["ports"].get("high", "7999").asString().c_str());
|
||||||
|
|
||||||
|
SpellsFile = _root["server"]["files"].get("spells", "spells_us.txt").asString();
|
||||||
|
OpCodesFile = _root["server"]["files"].get("opcodes", "opcodes.conf").asString();
|
||||||
|
PluginPlFile = _root["server"]["files"].get("plugin.pl", "plugin.pl").asString();
|
||||||
|
|
||||||
|
MapDir = _root["server"]["directories"].get("maps", "Maps/").asString();
|
||||||
|
QuestDir = _root["server"]["directories"].get("quests", "quests/").asString();
|
||||||
|
PluginDir = _root["server"]["directories"].get("plugins", "plugins/").asString();
|
||||||
|
LuaModuleDir = _root["server"]["directories"].get("lua_modules", "lua_modules/").asString();
|
||||||
|
PatchDir = _root["server"]["directories"].get("patches", "./").asString();
|
||||||
|
SharedMemDir = _root["server"]["directories"].get("shared_memory", "shared/").asString();
|
||||||
|
LogDir = _root["server"]["directories"].get("logs", "logs/").asString();
|
||||||
|
|
||||||
|
LogPrefix = _root["server"]["launcher"].get("logprefix", "logs/zone-").asString();
|
||||||
|
LogSuffix = _root["server"]["launcher"].get("logsuffix", ".log").asString();
|
||||||
|
RestartWait = atoi(_root["server"]["launcher"]["timers"].get("restart", "10000").asString().c_str());
|
||||||
|
TerminateWait = atoi(_root["server"]["launcher"]["timers"].get("reterminate", "10000").asString().c_str());
|
||||||
|
InitialBootWait = atoi(_root["server"]["launcher"]["timers"].get("initial", "20000").asString().c_str());
|
||||||
|
ZoneBootInterval = atoi(_root["server"]["launcher"]["timers"].get("interval", "2000").asString().c_str());
|
||||||
|
#ifdef WIN32
|
||||||
|
ZoneExe = _root["server"]["launcher"].get("exe", "zone.exe").asString();
|
||||||
|
#else
|
||||||
|
ZoneExe = _root["server"]["launcher"].get("exe", "./zone").asString();
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EQEmuConfig::do_chatserver(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
text = ParseTextBlock(ele, "host", true);
|
|
||||||
if (text) {
|
|
||||||
ChatHost = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "port", true);
|
|
||||||
if (text) {
|
|
||||||
ChatPort = atoi(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_mailserver(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
text = ParseTextBlock(ele, "host", true);
|
|
||||||
if (text) {
|
|
||||||
MailHost = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "port", true);
|
|
||||||
if (text) {
|
|
||||||
MailPort = atoi(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_database(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
text = ParseTextBlock(ele, "host", true);
|
|
||||||
if (text) {
|
|
||||||
DatabaseHost = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "port", true);
|
|
||||||
if (text) {
|
|
||||||
DatabasePort = atoi(text);
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "username", true);
|
|
||||||
if (text) {
|
|
||||||
DatabaseUsername = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "password", true);
|
|
||||||
if (text) {
|
|
||||||
DatabasePassword = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "db", true);
|
|
||||||
if (text) {
|
|
||||||
DatabaseDB = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void EQEmuConfig::do_qsdatabase(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
text = ParseTextBlock(ele, "host", true);
|
|
||||||
if (text) {
|
|
||||||
QSDatabaseHost = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "port", true);
|
|
||||||
if (text) {
|
|
||||||
QSDatabasePort = atoi(text);
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "username", true);
|
|
||||||
if (text) {
|
|
||||||
QSDatabaseUsername = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "password", true);
|
|
||||||
if (text) {
|
|
||||||
QSDatabasePassword = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "db", true);
|
|
||||||
if (text) {
|
|
||||||
QSDatabaseDB = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_zones(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
TiXmlElement *sub_ele;
|
|
||||||
// TiXmlNode *node,*sub_node;
|
|
||||||
text = ParseTextBlock(ele, "defaultstatus", true);
|
|
||||||
if (text) {
|
|
||||||
DefaultStatus = atoi(text);
|
|
||||||
}
|
|
||||||
// Get the <ports> element
|
|
||||||
sub_ele = ele->FirstChildElement("ports");
|
|
||||||
if (sub_ele != nullptr) {
|
|
||||||
text = sub_ele->Attribute("low");
|
|
||||||
if (text) {
|
|
||||||
ZonePortLow = atoi(text);
|
|
||||||
};
|
|
||||||
text = sub_ele->Attribute("high");
|
|
||||||
if (text) {
|
|
||||||
ZonePortHigh = atoi(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_files(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
text = ParseTextBlock(ele, "spells", true);
|
|
||||||
if (text) {
|
|
||||||
SpellsFile = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "opcodes", true);
|
|
||||||
if (text) {
|
|
||||||
OpCodesFile = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "plugin.pl", true);
|
|
||||||
if (text) {
|
|
||||||
PluginPlFile = text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_directories(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
text = ParseTextBlock(ele, "maps", true);
|
|
||||||
if (text) {
|
|
||||||
MapDir = text;
|
|
||||||
if ( MapDir.back() != '/' )
|
|
||||||
MapDir += '/';
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "quests", true);
|
|
||||||
if (text) {
|
|
||||||
QuestDir = text;
|
|
||||||
if ( QuestDir.back() != '/' )
|
|
||||||
QuestDir += '/';
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "plugins", true);
|
|
||||||
if (text) {
|
|
||||||
PluginDir = text;
|
|
||||||
if ( PluginDir.back() != '/' )
|
|
||||||
PluginDir += '/';
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "lua_modules", true);
|
|
||||||
if (text) {
|
|
||||||
LuaModuleDir = text;
|
|
||||||
if ( LuaModuleDir.back() != '/' )
|
|
||||||
LuaModuleDir += '/';
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "patches", true);
|
|
||||||
if (text) {
|
|
||||||
PatchDir = text;
|
|
||||||
if ( PatchDir.back() != '/' )
|
|
||||||
PatchDir += '/';
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "shared_memory", true);
|
|
||||||
if (text) {
|
|
||||||
SharedMemDir = text;
|
|
||||||
if ( SharedMemDir.back() != '/' )
|
|
||||||
SharedMemDir += '/';
|
|
||||||
}
|
|
||||||
//Not Fully Implemented yet LogDir
|
|
||||||
text = ParseTextBlock(ele, "logs", true);
|
|
||||||
if (text) {
|
|
||||||
LogDir = text;
|
|
||||||
if ( LogDir.back() != '/' )
|
|
||||||
LogDir += '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void EQEmuConfig::do_launcher(TiXmlElement *ele)
|
|
||||||
{
|
|
||||||
const char *text;
|
|
||||||
TiXmlElement *sub_ele;
|
|
||||||
text = ParseTextBlock(ele, "logprefix", true);
|
|
||||||
if (text) {
|
|
||||||
LogPrefix = text;
|
|
||||||
}
|
|
||||||
text = ParseTextBlock(ele, "logsuffix", true);
|
|
||||||
if (text) {
|
|
||||||
LogSuffix = text;
|
|
||||||
}
|
|
||||||
// Get the <exe> element
|
|
||||||
text = ParseTextBlock(ele, "exe", true);
|
|
||||||
if (text) {
|
|
||||||
ZoneExe = text;
|
|
||||||
}
|
|
||||||
// Get the <timers> element
|
|
||||||
sub_ele = ele->FirstChildElement("timers");
|
|
||||||
if (sub_ele != nullptr) {
|
|
||||||
text = sub_ele->Attribute("restart");
|
|
||||||
if (text) {
|
|
||||||
RestartWait = atoi(text);
|
|
||||||
}
|
|
||||||
text = sub_ele->Attribute("reterminate");
|
|
||||||
if (text) {
|
|
||||||
TerminateWait = atoi(text);
|
|
||||||
}
|
|
||||||
text = sub_ele->Attribute("initial");
|
|
||||||
if (text) {
|
|
||||||
InitialBootWait = atoi(text);
|
|
||||||
}
|
|
||||||
text = sub_ele->Attribute("interval");
|
|
||||||
if (text) {
|
|
||||||
ZoneBootInterval = atoi(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string EQEmuConfig::GetByName(const std::string &var_name) const
|
std::string EQEmuConfig::GetByName(const std::string &var_name) const
|
||||||
{
|
{
|
||||||
if (var_name == "ShortName") {
|
if (var_name == "ShortName") {
|
||||||
@ -564,4 +325,3 @@ void EQEmuConfig::Dump() const
|
|||||||
std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl;
|
std::cout << "DefaultStatus = " << (int)DefaultStatus << std::endl;
|
||||||
// std::cout << "DynamicCount = " << DynamicCount << std::endl;
|
// std::cout << "DynamicCount = " << DynamicCount << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -18,8 +18,9 @@
|
|||||||
#ifndef __EQEmuConfig_H
|
#ifndef __EQEmuConfig_H
|
||||||
#define __EQEmuConfig_H
|
#define __EQEmuConfig_H
|
||||||
|
|
||||||
#include "xml_parser.h"
|
#include "json/json.h"
|
||||||
#include "linked_list.h"
|
#include "linked_list.h"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
struct LoginConfig {
|
struct LoginConfig {
|
||||||
std::string LoginHost;
|
std::string LoginHost;
|
||||||
@ -29,7 +30,7 @@ struct LoginConfig {
|
|||||||
bool LoginLegacy;
|
bool LoginLegacy;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EQEmuConfig : public XMLParser
|
class EQEmuConfig
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual std::string GetByName(const std::string &var_name) const;
|
virtual std::string GetByName(const std::string &var_name) const;
|
||||||
@ -115,88 +116,14 @@ class EQEmuConfig : public XMLParser
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
static EQEmuConfig *_config;
|
static EQEmuConfig *_config;
|
||||||
|
Json::Value _root;
|
||||||
static std::string ConfigFile;
|
static std::string ConfigFile;
|
||||||
|
|
||||||
#define ELEMENT(name) \
|
void parse_config();
|
||||||
void do_##name(TiXmlElement *ele);
|
|
||||||
#include "eqemu_config_elements.h"
|
|
||||||
|
|
||||||
|
|
||||||
EQEmuConfig()
|
EQEmuConfig()
|
||||||
{
|
{
|
||||||
// import the needed handler prototypes
|
|
||||||
#define ELEMENT(name) \
|
|
||||||
Handlers[#name]=(ElementHandler)&EQEmuConfig::do_##name;
|
|
||||||
#include "eqemu_config_elements.h"
|
|
||||||
// Set sane defaults
|
|
||||||
// Login server
|
|
||||||
LoginHost = "login.eqemulator.net";
|
|
||||||
LoginPort = 5998;
|
|
||||||
LoginLegacy = false;
|
|
||||||
// World
|
|
||||||
Locked = false;
|
|
||||||
WorldTCPPort = 9000;
|
|
||||||
TelnetTCPPort = 9001;
|
|
||||||
TelnetEnabled = false;
|
|
||||||
WorldHTTPEnabled = false;
|
|
||||||
WorldHTTPPort = 9080;
|
|
||||||
WorldHTTPMimeFile = "mime.types";
|
|
||||||
SharedKey = ""; //blank disables authentication
|
|
||||||
// Mail
|
|
||||||
ChatHost = "eqchat.eqemulator.net";
|
|
||||||
ChatPort = 7778;
|
|
||||||
// Mail
|
|
||||||
MailHost = "eqmail.eqemulator.net";
|
|
||||||
MailPort = 7779;
|
|
||||||
// Mysql
|
|
||||||
DatabaseHost = "localhost";
|
|
||||||
DatabasePort = 3306;
|
|
||||||
DatabaseUsername = "eq";
|
|
||||||
DatabasePassword = "eq";
|
|
||||||
DatabaseDB = "eq";
|
|
||||||
// QueryServ Database
|
|
||||||
QSDatabaseHost = "localhost";
|
|
||||||
QSDatabasePort = 3306;
|
|
||||||
QSDatabaseUsername = "eq";
|
|
||||||
QSDatabasePassword = "eq";
|
|
||||||
QSDatabaseDB = "eq";
|
|
||||||
// Files
|
|
||||||
SpellsFile = "spells_us.txt";
|
|
||||||
OpCodesFile = "opcodes.conf";
|
|
||||||
PluginPlFile = "plugin.pl";
|
|
||||||
// Dirs
|
|
||||||
MapDir = "Maps/";
|
|
||||||
QuestDir = "quests/";
|
|
||||||
PluginDir = "plugins/";
|
|
||||||
LuaModuleDir = "lua_modules/";
|
|
||||||
PatchDir = "./";
|
|
||||||
SharedMemDir = "shared/";
|
|
||||||
LogDir = "logs/";
|
|
||||||
|
|
||||||
// Launcher
|
|
||||||
LogPrefix = "logs/zone-";
|
|
||||||
LogSuffix = ".log";
|
|
||||||
RestartWait = 10000; //milliseconds
|
|
||||||
TerminateWait = 10000; //milliseconds
|
|
||||||
InitialBootWait = 20000; //milliseconds
|
|
||||||
ZoneBootInterval = 2000; //milliseconds
|
|
||||||
#ifdef WIN32
|
|
||||||
ZoneExe = "zone.exe";
|
|
||||||
#else
|
|
||||||
ZoneExe = "./zone";
|
|
||||||
#endif
|
|
||||||
// Zones
|
|
||||||
ZonePortLow = 7000;
|
|
||||||
ZonePortHigh = 7999;
|
|
||||||
DefaultStatus = 0;
|
|
||||||
// For where zones need to connect to.
|
|
||||||
WorldIP = "127.0.0.1";
|
|
||||||
TelnetIP = "127.0.0.1";
|
|
||||||
// Dynamics to start
|
|
||||||
//DynamicCount=5;
|
|
||||||
MaxClients = -1;
|
|
||||||
LoginCount = 0;
|
|
||||||
}
|
}
|
||||||
virtual ~EQEmuConfig() {}
|
virtual ~EQEmuConfig() {}
|
||||||
|
|
||||||
@ -205,9 +132,7 @@ class EQEmuConfig : public XMLParser
|
|||||||
// Produce a const singleton
|
// Produce a const singleton
|
||||||
static const EQEmuConfig *get()
|
static const EQEmuConfig *get()
|
||||||
{
|
{
|
||||||
if (_config == nullptr) {
|
|
||||||
LoadConfig();
|
LoadConfig();
|
||||||
}
|
|
||||||
return (_config);
|
return (_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,10 +146,28 @@ class EQEmuConfig : public XMLParser
|
|||||||
static bool LoadConfig()
|
static bool LoadConfig()
|
||||||
{
|
{
|
||||||
if (_config != nullptr) {
|
if (_config != nullptr) {
|
||||||
delete _config;
|
return true;
|
||||||
}
|
}
|
||||||
_config = new EQEmuConfig;
|
_config = new EQEmuConfig;
|
||||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(), "server");
|
|
||||||
|
return parseFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load config file and parse data
|
||||||
|
static bool parseFile() {
|
||||||
|
if (_config == nullptr) {
|
||||||
|
return LoadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ifstream fconfig(EQEmuConfig::ConfigFile, std::ifstream::binary);
|
||||||
|
try {
|
||||||
|
fconfig >> _config->_root;
|
||||||
|
_config->parse_config();
|
||||||
|
}
|
||||||
|
catch (std::exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dump() const;
|
void Dump() const;
|
||||||
|
|||||||
@ -3850,6 +3850,9 @@ namespace RoF
|
|||||||
OUT(zone_reason);
|
OUT(zone_reason);
|
||||||
OUT(success);
|
OUT(success);
|
||||||
|
|
||||||
|
if (eq->success < 0)
|
||||||
|
eq->success -= 1;
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3994,6 +3994,9 @@ namespace RoF2
|
|||||||
OUT(zone_reason);
|
OUT(zone_reason);
|
||||||
OUT(success);
|
OUT(success);
|
||||||
|
|
||||||
|
if (eq->success < 0)
|
||||||
|
eq->success -= 1;
|
||||||
|
|
||||||
FINISH_ENCODE();
|
FINISH_ENCODE();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -164,7 +164,7 @@ namespace RoF2
|
|||||||
ItemPacket11 = 111,
|
ItemPacket11 = 111,
|
||||||
ItemPacket12 = 112,
|
ItemPacket12 = 112,
|
||||||
ItemPacketRecovery = 113,
|
ItemPacketRecovery = 113,
|
||||||
ItemPacket14 = 115
|
ItemPacket14 = 115 // Parcel? adds to merchant window too
|
||||||
};
|
};
|
||||||
|
|
||||||
} /*item*/
|
} /*item*/
|
||||||
|
|||||||
@ -198,6 +198,7 @@ RULE_CATEGORY(Pets)
|
|||||||
RULE_REAL(Pets, AttackCommandRange, 150)
|
RULE_REAL(Pets, AttackCommandRange, 150)
|
||||||
RULE_BOOL(Pets, UnTargetableSwarmPet, false)
|
RULE_BOOL(Pets, UnTargetableSwarmPet, false)
|
||||||
RULE_REAL(Pets, PetPowerLevelCap, 10) // Max number of levels your pet can go up with pet power
|
RULE_REAL(Pets, PetPowerLevelCap, 10) // Max number of levels your pet can go up with pet power
|
||||||
|
RULE_BOOL(Pets, CanTakeNoDrop, false) // Can everyone trade nodrop gear to pets
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(GM)
|
RULE_CATEGORY(GM)
|
||||||
@ -508,6 +509,7 @@ RULE_INT(Combat, NPCAssistCapTimer, 6000) // Time in milliseconds a NPC will tak
|
|||||||
RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF
|
RULE_BOOL(Combat, UseRevampHandToHand, false) // use h2h revamped dmg/delays I believe this was implemented during SoF
|
||||||
RULE_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't
|
RULE_BOOL(Combat, ClassicMasterWu, false) // classic master wu uses a random special, modern doesn't
|
||||||
RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system
|
RULE_INT(Combat, LevelToStopDamageCaps, 0) // 1 will effectively disable them, 20 should give basically same results as old incorrect system
|
||||||
|
RULE_BOOL(Combat, ClassicNPCBackstab, false) // true disables npc facestab - npcs get normal attack if not behind
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(NPC)
|
RULE_CATEGORY(NPC)
|
||||||
@ -674,6 +676,12 @@ RULE_CATEGORY_END()
|
|||||||
RULE_CATEGORY(AA)
|
RULE_CATEGORY(AA)
|
||||||
RULE_INT(AA, ExpPerPoint, 23976503) //Amount of exp per AA. Is the same as the amount of exp to go from level 51 to level 52.
|
RULE_INT(AA, ExpPerPoint, 23976503) //Amount of exp per AA. Is the same as the amount of exp to go from level 51 to level 52.
|
||||||
RULE_BOOL(AA, Stacking, true) //Allow AA that belong to the same group to stack on SOF+ clients.
|
RULE_BOOL(AA, Stacking, true) //Allow AA that belong to the same group to stack on SOF+ clients.
|
||||||
|
RULE_BOOL(AA, NormalizedAAEnabled, false) // TSS+ change to AA that normalizes AA XP to a fixed # of white con kills independent of level.
|
||||||
|
RULE_INT(AA, NormalizedAANumberOfWhiteConPerAA, 25) // The number of white con kills per AA point.
|
||||||
|
RULE_BOOL(AA, ModernAAScalingEnabled, false) // Are we linearly scaling AA XP based on total # of earned AA?
|
||||||
|
RULE_REAL(AA, ModernAAScalingStartPercent, 1000) // 1000% or 10x AA XP at the start of the scaling range
|
||||||
|
RULE_INT(AA, ModernAAScalingAAMinimum, 0) // The minimum number of earned AA before AA XP scaling begins.
|
||||||
|
RULE_INT(AA, ModernAAScalingAALimit, 4000) // The number of earned AA when AA XP scaling ends
|
||||||
RULE_CATEGORY_END()
|
RULE_CATEGORY_END()
|
||||||
|
|
||||||
RULE_CATEGORY(Console)
|
RULE_CATEGORY(Console)
|
||||||
|
|||||||
@ -1719,6 +1719,8 @@ FMT_DEFINE_INT_FORMATTERS(unsigned long)
|
|||||||
FMT_DEFINE_INT_FORMATTERS(LongLong)
|
FMT_DEFINE_INT_FORMATTERS(LongLong)
|
||||||
FMT_DEFINE_INT_FORMATTERS(ULongLong)
|
FMT_DEFINE_INT_FORMATTERS(ULongLong)
|
||||||
|
|
||||||
|
#define CHAR_WIDTH 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Returns a string formatter that pads the formatted argument with the fill
|
Returns a string formatter that pads the formatted argument with the fill
|
||||||
@ -1823,7 +1825,7 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> {
|
|||||||
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
typedef typename BasicWriter<Char>::CharPtr CharPtr;
|
||||||
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
|
Char fill = internal::CharTraits<Char>::cast(spec_.fill());
|
||||||
CharPtr out = CharPtr();
|
CharPtr out = CharPtr();
|
||||||
const unsigned CHAR_WIDTH = 1;
|
|
||||||
if (spec_.width_ > CHAR_WIDTH) {
|
if (spec_.width_ > CHAR_WIDTH) {
|
||||||
out = writer_.grow_buffer(spec_.width_);
|
out = writer_.grow_buffer(spec_.width_);
|
||||||
if (spec_.align_ == ALIGN_RIGHT) {
|
if (spec_.align_ == ALIGN_RIGHT) {
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public:
|
|||||||
_chat_config=new queryservconfig;
|
_chat_config=new queryservconfig;
|
||||||
_config=_chat_config;
|
_config=_chat_config;
|
||||||
|
|
||||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
|
return _config->parseFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -46,7 +46,7 @@ public:
|
|||||||
_chat_config=new ucsconfig;
|
_chat_config=new ucsconfig;
|
||||||
_config=_chat_config;
|
_config=_chat_config;
|
||||||
|
|
||||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
|
return _config->parseFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
8
utils/defaults/eqemu_config.json
Executable file
8
utils/defaults/eqemu_config.json
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"world": {
|
||||||
|
"shortname": "setme",
|
||||||
|
"longname": "I Forgot To Edit My Config"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
utils/defaults/eqemu_config.json.full
Executable file
54
utils/defaults/eqemu_config.json.full
Executable file
@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"zones": {
|
||||||
|
"defaultstatus": "20",
|
||||||
|
"ports": {
|
||||||
|
"low": "7000",
|
||||||
|
"high": "7100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"database": {
|
||||||
|
"password": "eq",
|
||||||
|
"db": "eq",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": "3306",
|
||||||
|
"username": "eq"
|
||||||
|
},
|
||||||
|
"world": {
|
||||||
|
"shortname": "setme",
|
||||||
|
"longname": "I Forgot To Edit My Config",
|
||||||
|
"loginserver": {
|
||||||
|
"password": "",
|
||||||
|
"host": "login.eqemulator.net",
|
||||||
|
"port": "5998",
|
||||||
|
"account": ""
|
||||||
|
},
|
||||||
|
"tcp": {
|
||||||
|
"port": "9000",
|
||||||
|
"telnet": "disable",
|
||||||
|
"ip": "127.0.0.1"
|
||||||
|
},
|
||||||
|
"key": "some long random string",
|
||||||
|
"http": {
|
||||||
|
"mimefile": "mime.types",
|
||||||
|
"port": "9080",
|
||||||
|
"enabled": "false"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mailserver": {
|
||||||
|
"host": "channels.eqemulator.net",
|
||||||
|
"port": "7778"
|
||||||
|
},
|
||||||
|
"chatserver": {
|
||||||
|
"host": "channels.eqemulator.net",
|
||||||
|
"port": "7778"
|
||||||
|
},
|
||||||
|
"qsdatabase": {
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": "3306",
|
||||||
|
"username": "eq",
|
||||||
|
"password": "eq",
|
||||||
|
"db": "eq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
355
utils/doc_scripts/perlparse/main.go
Normal file
355
utils/doc_scripts/perlparse/main.go
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
//Parses perl scripts
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
path := "../../../zone/embparser_api.cpp"
|
||||||
|
err := readFile(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Panicf("Failed to read file: %s", err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type API struct {
|
||||||
|
Function string
|
||||||
|
Arguments []*Argument
|
||||||
|
}
|
||||||
|
|
||||||
|
type Argument struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
API *API
|
||||||
|
}
|
||||||
|
|
||||||
|
func readFile(path string) (err error) {
|
||||||
|
inFile, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "Failed to open file")
|
||||||
|
}
|
||||||
|
defer inFile.Close()
|
||||||
|
scanner := bufio.NewScanner(inFile)
|
||||||
|
scanner.Split(bufio.ScanLines)
|
||||||
|
|
||||||
|
arguments := map[string][]*Argument{}
|
||||||
|
functions := []*API{}
|
||||||
|
reg, err := regexp.Compile(`\]+|\[+|\?+|[...]+`)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "Failed to compile regex")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
regType, err := regexp.Compile(`(unsigned long|long|int32|bool|uint[0-9]+|int|auto|float|unsigned int|char[ \*]).+([. a-zA-Z]+=)`)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.Wrap(err, "Failed to compile type regex")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
lastArguments := []*Argument{}
|
||||||
|
lastAPI := &API{}
|
||||||
|
lineNum := 0
|
||||||
|
for scanner.Scan() {
|
||||||
|
lineNum++
|
||||||
|
key := ""
|
||||||
|
line := scanner.Text()
|
||||||
|
if len(line) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(lastArguments) > 0 { //existing args to parse
|
||||||
|
for i, argument := range lastArguments {
|
||||||
|
key = fmt.Sprintf("ST(%d)", i)
|
||||||
|
if strings.Contains(line, key) {
|
||||||
|
//We found a definition argument line
|
||||||
|
if argument.Type != "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
match := regType.FindStringSubmatch(line)
|
||||||
|
if len(match) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
//key = `int`
|
||||||
|
//function = line[strings.Index(line, key)+len(key):]
|
||||||
|
newType := ""
|
||||||
|
|
||||||
|
switch v := strings.TrimSpace(match[1]); v {
|
||||||
|
case "int":
|
||||||
|
newType = "int"
|
||||||
|
case "int32":
|
||||||
|
newType = "int"
|
||||||
|
case "float":
|
||||||
|
newType = "float"
|
||||||
|
case "unsigned int":
|
||||||
|
newType = "uint"
|
||||||
|
case "uint32":
|
||||||
|
newType = "uint"
|
||||||
|
case "uint8":
|
||||||
|
newType = "uint"
|
||||||
|
case "uint":
|
||||||
|
newType = "uint"
|
||||||
|
case "bool":
|
||||||
|
newType = "bool"
|
||||||
|
case "uint16":
|
||||||
|
newType = "uint"
|
||||||
|
case "long":
|
||||||
|
newType = "long"
|
||||||
|
case "unsigned long":
|
||||||
|
newType = "unsigned long"
|
||||||
|
case "char":
|
||||||
|
newType = "string"
|
||||||
|
case "auto":
|
||||||
|
//Auto is tricky
|
||||||
|
if strings.Contains(line, "glm::vec4") {
|
||||||
|
newType = "float"
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Printf(`Unknown type: "%s" on line %d`, v, lineNum)
|
||||||
|
}
|
||||||
|
//log.Println("Found arg type", newType, "on index", i, argument.Name)
|
||||||
|
lastArguments[i].Type = newType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function := ""
|
||||||
|
|
||||||
|
argLine := ""
|
||||||
|
args := []string{}
|
||||||
|
//Find line
|
||||||
|
key = `Perl_croak(aTHX_ "Usage:`
|
||||||
|
if strings.Contains(line, key) {
|
||||||
|
function = line[strings.Index(line, key)+len(key):]
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, argument := range lastArguments {
|
||||||
|
arguments[argument.Name] = append(arguments[argument.Name], argument)
|
||||||
|
}
|
||||||
|
|
||||||
|
lastArguments = []*Argument{}
|
||||||
|
|
||||||
|
//Trim off the endings
|
||||||
|
key = `");`
|
||||||
|
if strings.Contains(function, key) {
|
||||||
|
function = function[0:strings.Index(function, key)]
|
||||||
|
}
|
||||||
|
//Strip out the arguments
|
||||||
|
key = `(`
|
||||||
|
if strings.Contains(function, key) {
|
||||||
|
argLine = function[strings.Index(function, key)+len(key):]
|
||||||
|
function = function[0:strings.Index(function, key)]
|
||||||
|
key = `)`
|
||||||
|
if strings.Contains(argLine, key) {
|
||||||
|
argLine = argLine[:strings.Index(argLine, key)]
|
||||||
|
}
|
||||||
|
key = `=`
|
||||||
|
if strings.Contains(argLine, key) {
|
||||||
|
argLine = argLine[:strings.Index(argLine, key)]
|
||||||
|
}
|
||||||
|
argLine = reg.ReplaceAllString(argLine, "")
|
||||||
|
}
|
||||||
|
key = `,`
|
||||||
|
argLine = strings.TrimSpace(argLine)
|
||||||
|
|
||||||
|
if strings.Contains(argLine, key) {
|
||||||
|
args = strings.Split(argLine, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(function) < 1 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
newArgs := []string{}
|
||||||
|
for j, _ := range args {
|
||||||
|
args[j] = strings.TrimSpace(args[j])
|
||||||
|
if len(args[j]) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newArgs = append(newArgs, args[j])
|
||||||
|
}
|
||||||
|
|
||||||
|
lastAPI = &API{
|
||||||
|
Function: function,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, arg := range newArgs {
|
||||||
|
argType, _ := knownTypes[arg]
|
||||||
|
argument := &Argument{
|
||||||
|
Name: arg,
|
||||||
|
Type: argType,
|
||||||
|
API: lastAPI,
|
||||||
|
}
|
||||||
|
lastArguments = append(lastArguments, argument)
|
||||||
|
}
|
||||||
|
lastAPI.Arguments = lastArguments
|
||||||
|
|
||||||
|
functions = append(functions, lastAPI)
|
||||||
|
}
|
||||||
|
|
||||||
|
foundCount := 0
|
||||||
|
failCount := 0
|
||||||
|
for key, val := range arguments {
|
||||||
|
isMissing := false
|
||||||
|
line := ""
|
||||||
|
line = fmt.Sprintf("%s used by %d functions:", key, len(val))
|
||||||
|
for _, fnc := range val {
|
||||||
|
line += fmt.Sprintf("%s(%s %s), ", fnc.API.Function, fnc.Type, key)
|
||||||
|
if fnc.Type == "" {
|
||||||
|
isMissing = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isMissing {
|
||||||
|
fmt.Println(line)
|
||||||
|
failCount++
|
||||||
|
} else {
|
||||||
|
foundCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Println(foundCount, "functions properly identified,", failCount, "have errors")
|
||||||
|
|
||||||
|
line := ""
|
||||||
|
for _, api := range functions {
|
||||||
|
line += fmt.Sprintf("void %s(", strings.TrimSpace(api.Function))
|
||||||
|
for _, argument := range api.Arguments {
|
||||||
|
line += fmt.Sprintf("%s %s, ", argument.Type, argument.Name)
|
||||||
|
}
|
||||||
|
if len(api.Arguments) > 0 {
|
||||||
|
line = line[0 : len(line)-2]
|
||||||
|
}
|
||||||
|
line += ")\n"
|
||||||
|
}
|
||||||
|
fmt.Println(line)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var knownTypes = map[string]string{
|
||||||
|
"activity_id": "uint",
|
||||||
|
"alt_mode": "bool",
|
||||||
|
"anim_num": "int",
|
||||||
|
"best_z": "float",
|
||||||
|
"buttons": "int",
|
||||||
|
"channel_id": "int",
|
||||||
|
"char_id": "int",
|
||||||
|
"charges": "int",
|
||||||
|
"class_id": "int",
|
||||||
|
"client_name": "string",
|
||||||
|
"color": "int",
|
||||||
|
"color_id": "int",
|
||||||
|
"condition_id": "int",
|
||||||
|
"copper": "int",
|
||||||
|
"count": "int",
|
||||||
|
"debug_level": "int",
|
||||||
|
"decay_time": "int",
|
||||||
|
"dest_heading": "float",
|
||||||
|
"dest_x": "float",
|
||||||
|
"dest_y": "float",
|
||||||
|
"dest_z": "float",
|
||||||
|
"distance": "int",
|
||||||
|
"door_id": "int",
|
||||||
|
"doorid": "uint",
|
||||||
|
"duration": "int",
|
||||||
|
"effect_id": "int",
|
||||||
|
"elite_material_id": "int",
|
||||||
|
"enforce_level_requirement": "bool",
|
||||||
|
"explore_id": "uint",
|
||||||
|
"faction_value": "int",
|
||||||
|
"fade_in": "int",
|
||||||
|
"fade_out": "int",
|
||||||
|
"fadeout": "uint",
|
||||||
|
"firstname": "string",
|
||||||
|
"from": "string",
|
||||||
|
"gender_id": "int",
|
||||||
|
"gold": "int",
|
||||||
|
"grid_id": "int",
|
||||||
|
"guild_rank_id": "int",
|
||||||
|
"heading": "float",
|
||||||
|
"hero_forge_model_id": "int",
|
||||||
|
"ignore_quest_update": "bool",
|
||||||
|
"instance_id": "int",
|
||||||
|
"int_unused": "int",
|
||||||
|
"int_value": "int",
|
||||||
|
"is_enabled": "bool",
|
||||||
|
"is_strict": "bool",
|
||||||
|
"item_id": "int",
|
||||||
|
"key": "string",
|
||||||
|
"language_id": "int",
|
||||||
|
"lastname": "string",
|
||||||
|
"leader_name": "string",
|
||||||
|
"level": "int",
|
||||||
|
"link_name": "string",
|
||||||
|
"macro_id": "int",
|
||||||
|
"max_level": "int",
|
||||||
|
"max_x": "float",
|
||||||
|
"max_y": "float",
|
||||||
|
"max_z": "float",
|
||||||
|
"message": "string",
|
||||||
|
"milliseconds": "int",
|
||||||
|
"min_level": "int",
|
||||||
|
"min_x": "float",
|
||||||
|
"min_y": "float",
|
||||||
|
"min_z": "float",
|
||||||
|
"name": "string",
|
||||||
|
"new_hour": "int",
|
||||||
|
"new_min": "int",
|
||||||
|
"node1": "int",
|
||||||
|
"node2": "int",
|
||||||
|
"npc_id": "int",
|
||||||
|
"npc_type_id": "int",
|
||||||
|
"object_type": "int",
|
||||||
|
"options": "int",
|
||||||
|
"platinum": "int",
|
||||||
|
"popup_id": "int",
|
||||||
|
"priority": "int",
|
||||||
|
"quantity": "int",
|
||||||
|
"race_id": "int",
|
||||||
|
"remove_item": "bool",
|
||||||
|
"requested_id": "int",
|
||||||
|
"reset_base": "bool",
|
||||||
|
"saveguard": "bool",
|
||||||
|
"seconds": "int",
|
||||||
|
"send_to_world": "bool",
|
||||||
|
"signal_id": "int",
|
||||||
|
"silent": "bool",
|
||||||
|
"silver": "int",
|
||||||
|
"size": "int",
|
||||||
|
"stat_id": "int",
|
||||||
|
"str_value": "string",
|
||||||
|
"subject": "string",
|
||||||
|
"target_enum": "string",
|
||||||
|
"target_id": "int",
|
||||||
|
"task": "int",
|
||||||
|
"task_id": "uint",
|
||||||
|
"task_id1": "int",
|
||||||
|
"task_id10": "int",
|
||||||
|
"task_id2": "int",
|
||||||
|
"task_set": "int",
|
||||||
|
"taskid": "int",
|
||||||
|
"taskid1": "int",
|
||||||
|
"taskid2": "int",
|
||||||
|
"taskid3": "int",
|
||||||
|
"taskid4": "int",
|
||||||
|
"teleport": "int",
|
||||||
|
"temp": "int",
|
||||||
|
"texture_id": "int",
|
||||||
|
"theme_id": "int",
|
||||||
|
"update_world": "int",
|
||||||
|
"updated_time_till_repop": "uint",
|
||||||
|
"version": "int",
|
||||||
|
"wait_ms": "int",
|
||||||
|
"window_title": "string",
|
||||||
|
"x": "float",
|
||||||
|
"y": "float",
|
||||||
|
"z": "float",
|
||||||
|
"zone_id": "int",
|
||||||
|
"zone_short": "string",
|
||||||
|
`task_id%i`: "int",
|
||||||
|
}
|
||||||
252
utils/scripts/database_dumper.pl
Normal file
252
utils/scripts/database_dumper.pl
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
#::: Script: db_dumper.pl
|
||||||
|
#::: Purpose: Utility to easily manage database backups and compress.
|
||||||
|
#::: Export Individual DB Tables...
|
||||||
|
#::: Export specific databases...
|
||||||
|
#::: Built for both Windows and Linux
|
||||||
|
#::: Windows uses WinRar or 7-Zip for compression
|
||||||
|
#::: Linux uses tar for compression
|
||||||
|
#::: Author: Akkadius
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
$localdrive = "C:"; #::: Where Windows and all Install Programs are...
|
||||||
|
$linesep = "---------------------------------------";
|
||||||
|
|
||||||
|
use POSIX qw(strftime);
|
||||||
|
my $date = strftime "%m_%d_%Y", localtime;
|
||||||
|
print "\nTodays Date: " . $date . "\n";
|
||||||
|
|
||||||
|
use Config;
|
||||||
|
print "Operating System is: $Config{osname}\n";
|
||||||
|
if($Config{osname}=~/linux/i){ $OS = "Linux"; }
|
||||||
|
if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
|
||||||
|
|
||||||
|
if(!$ARGV[0]){
|
||||||
|
print "\nERROR! Need arguments\n";
|
||||||
|
print "#::: Help :::#\n";
|
||||||
|
print "######################################################\n";
|
||||||
|
print "Arguments\n";
|
||||||
|
print " loc=\"C:\\File Location\" - File path location to backup...\n";
|
||||||
|
print " database=\"dbname\" - Manually specify databasename, default is database in eqemu_config.xml\n";
|
||||||
|
print " tables=\"table1,table2,table3\" - Manually specify tables, default is to dump all tables from database\n";
|
||||||
|
print " compress - Compress Database with 7-ZIP, will fallback to WinRAR depending on what is installed (Must be installed to default program dir)...\n";
|
||||||
|
print " nolock - Does not lock tables, meant for backuping while the server is running..\n";
|
||||||
|
print " backup_name=\"name\" - Sets database backup prefix name\n";
|
||||||
|
print ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n";
|
||||||
|
print "######################################################\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub read_eqemu_config_json {
|
||||||
|
use JSON;
|
||||||
|
my $json = new JSON();
|
||||||
|
|
||||||
|
my $content;
|
||||||
|
open(my $fh, '<', "eqemu_config.json") or die "Unable to open config: eqemu_config.json - This must be in your EQEmu Server Folder\n"; {
|
||||||
|
local $/;
|
||||||
|
$content = <$fh>;
|
||||||
|
}
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
$config = $json->decode($content);
|
||||||
|
|
||||||
|
$db = $config->{"server"}{"database"}{"db"};
|
||||||
|
$host = $config->{"server"}{"database"}{"host"};
|
||||||
|
$user = $config->{"server"}{"database"}{"username"};
|
||||||
|
$pass = $config->{"server"}{"database"}{"password"};
|
||||||
|
$long_name = $config->{"server"}{"world"}{"longname"};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
read_eqemu_config_json();
|
||||||
|
|
||||||
|
$Debug = 0;
|
||||||
|
print "[db_dumper.pl] Arguments\n" if $Debug;
|
||||||
|
$n = 0;
|
||||||
|
while($ARGV[$n]){
|
||||||
|
print $n . ': ' . $ARGV[$n] . "\n" if $Debug;
|
||||||
|
if($ARGV[$n]=~/nolock/i){
|
||||||
|
$no_lock = 1;
|
||||||
|
}
|
||||||
|
if($ARGV[$n]=~/compress/i){
|
||||||
|
print "[db_dumper.pl] Compression SET\n";
|
||||||
|
$Compress = 1;
|
||||||
|
}
|
||||||
|
if($ARGV[$n]=~/database=/i){
|
||||||
|
@DB_NAME = split('=', $ARGV[$n]);
|
||||||
|
print "[db_dumper.pl] Database is " . $DB_NAME[1] . "\n";
|
||||||
|
$db = $DB_NAME[1];
|
||||||
|
}
|
||||||
|
if($ARGV[$n]=~/backup_name=/i){
|
||||||
|
@data = split('=', $ARGV[$n]);
|
||||||
|
print "[db_dumper.pl] Backup Name is " . $data[1] . "\n";
|
||||||
|
$backup_name = $data[1];
|
||||||
|
}
|
||||||
|
if($ARGV[$n]=~/loc=/i){
|
||||||
|
@backup_location = split('=', $ARGV[$n]);
|
||||||
|
print "[db_dumper.pl] Backup Directory: " . $backup_location[1] . "\n";
|
||||||
|
}
|
||||||
|
if($ARGV[$n]=~/tables=/i){
|
||||||
|
@Tables = split('=', $ARGV[$n]); @TList = split(',', $Tables[1]);
|
||||||
|
foreach my $tables (@TList){
|
||||||
|
$t_tables .= $tables . " ";
|
||||||
|
$t_tables_l .= $tables . "_";
|
||||||
|
$t_tables_p .= $tables . "\n";
|
||||||
|
}
|
||||||
|
print "[db_dumper.pl] Backing up tables: \n############################\n" . $t_tables_p . "############################\n";
|
||||||
|
}
|
||||||
|
$n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#::: Check for Backup Directory existence, if doesn't exist then create...
|
||||||
|
if (-d $backup_location[1]) {
|
||||||
|
print "[db_dumper.pl] Directory currently exists... Adding files to it...\n";
|
||||||
|
}
|
||||||
|
elsif($backup_location[1] ne ""){
|
||||||
|
print "[db_dumper.pl] Directory does NOT exist! Creating...\n";
|
||||||
|
mkdir($backup_location[1]) or die 'Failed to create folder, maybe created the folder manually at "' . $backup_location[1]. '" ?';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print "[db_dumper.pl] No save location specified... Saving to folder script is running in...\n";
|
||||||
|
}
|
||||||
|
if($backup_location[1] ne ""){
|
||||||
|
if($OS eq "Windows"){ $file_app = "\\"; }
|
||||||
|
if($OS eq "Linux"){ $file_app = "/"; }
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$file_app = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if($t_tables ne ""){
|
||||||
|
$tables_f_l = substr($t_tables_l, 0, 20) . '-';
|
||||||
|
if($backup_name){
|
||||||
|
$target_file = $backup_name . '_' . $date . '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$target_file = '' . $tables_f_l . '_' . $date . '';
|
||||||
|
}
|
||||||
|
|
||||||
|
print "[db_dumper.pl] Performing table based backup...\n";
|
||||||
|
#::: Backup Database...
|
||||||
|
print "[db_dumper.pl] Backing up Database " . $db . "... \n";
|
||||||
|
if($no_lock == 1){
|
||||||
|
$added_parameters .= " --skip-lock-tables ";
|
||||||
|
}
|
||||||
|
$cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' ' . $t_tables . ' > "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql"';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
}
|
||||||
|
else{ #::: Entire DB Backup
|
||||||
|
|
||||||
|
if($backup_name){
|
||||||
|
$target_file = $backup_name . '_' . $db . '_' . $date . '';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$target_file = '' . $db . '_' . $date . '';
|
||||||
|
}
|
||||||
|
|
||||||
|
#::: Backup Database...
|
||||||
|
print "[db_dumper.pl] Backing up Database " . $db . "... \n";
|
||||||
|
if($no_lock == 1){
|
||||||
|
$added_parameters .= " --skip-lock-tables ";
|
||||||
|
}
|
||||||
|
$cmd = 'mysqldump -u' . $user . ' --host ' . $host . ' ' . $added_parameters . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql"';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#::: Get File Size
|
||||||
|
$fileloc = '' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql';
|
||||||
|
$filesize = -s $fileloc;
|
||||||
|
if($filesize < 1000){ print "[db_dumper.pl] " . 'Error occurred... exiting...' . "\n"; exit; }
|
||||||
|
print "[db_dumper.pl] Backup DONE... DB Backup File Size '" . $filesize . "' (" . get_filesize_str($fileloc) . ")\n";
|
||||||
|
|
||||||
|
#::: WinRar Get, check compression flag
|
||||||
|
if($Compress == 1){
|
||||||
|
if($OS eq "Windows"){
|
||||||
|
if(-d $localdrive . "\\Program Files\\7-Zip"){
|
||||||
|
print "[db_dumper.pl] ::: You have 7-Zip installed as 64 Bit...\n";
|
||||||
|
$S_ZIP = $localdrive . "\\Program Files\\7-Zip";
|
||||||
|
}
|
||||||
|
elsif(-d $localdrive . "\\Program Files (x86)\\7-Zip"){
|
||||||
|
print "[db_dumper.pl] ::: You have 7-Zip installed as 32 Bit...\n";
|
||||||
|
$S_ZIP = $localdrive . "\\Program Files (x86)\\7-Zip";
|
||||||
|
}
|
||||||
|
elsif(-d $localdrive . "\\Program Files (x86)\\WinRAR"){
|
||||||
|
print "[db_dumper.pl] ::: You have WinRAR installed as 32 Bit...\n";
|
||||||
|
$WinRar = $localdrive . "\\Program Files (x86)\\WinRAR";
|
||||||
|
}
|
||||||
|
elsif(-d $localdrive . "\\Program Files\\WinRAR"){
|
||||||
|
print "[db_dumper.pl] ::: You have WinRAR installed as 64 Bit...\n";
|
||||||
|
$WinRar = $localdrive . "\\Program Files\\WinRAR";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
print "[db_dumper.pl] No WinRAR installed... Will not compress...\n";
|
||||||
|
}
|
||||||
|
if($S_ZIP ne ""){
|
||||||
|
print "[db_dumper.pl] Compressing Database with 7-ZIP... \n";
|
||||||
|
$cmd = '"' . $S_ZIP . '\\7z" a -t7z -m0=lzma -mx=9 "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.7z" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n";
|
||||||
|
$cmd = 'del "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
$final_file = $target_file . ".7z";
|
||||||
|
}
|
||||||
|
elsif($WinRar ne ""){
|
||||||
|
print "[db_dumper.pl] Compressing Database with WinRAR... \n";
|
||||||
|
$cmd = '"' . $WinRar . '\\rar" a "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.rar" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n";
|
||||||
|
$cmd = 'del "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
$final_file = $target_file . ".rar";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($OS eq "Linux"){
|
||||||
|
print "[db_dumper.pl] Compressing Database with Tarball... \n";
|
||||||
|
$cmd = 'tar -zcvf "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.tar.gz" "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
print "[db_dumper.pl] \nDeleting RAW .sql Dump... \n";
|
||||||
|
$cmd = 'rm "' . $backup_location[1] . '' . $file_app . '' . $target_file . '.sql" ';
|
||||||
|
printcmd($cmd);
|
||||||
|
system($cmd);
|
||||||
|
$final_file = $target_file . ".tar.gz";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$final_file = $target_file . ".sql";
|
||||||
|
}
|
||||||
|
|
||||||
|
#::: Get Final File Location for display
|
||||||
|
if($backup_location[1] ne ""){ $final_loc = $backup_location[1] . '' . $file_app . ""; }
|
||||||
|
else{
|
||||||
|
if($OS eq "Windows"){
|
||||||
|
$final_loc = `echo %cd%`;
|
||||||
|
}
|
||||||
|
elsif($OS eq "Linux"){
|
||||||
|
$final_loc = `pwd`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print "[db_dumper.pl] Final file located: " . $final_loc . "" . $final_file . "\n";
|
||||||
|
|
||||||
|
sub printcmd{
|
||||||
|
print "[db_dumper.pl] Command [" . $_[0] . "]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_filesize_str{
|
||||||
|
my $file = shift();
|
||||||
|
my $size = (stat($file))[7] || die "stat($file): $!\n";
|
||||||
|
if ($size > 1099511627776) { return sprintf("%.2f TiB", $size / 1099511627776); }
|
||||||
|
elsif ($size > 1073741824) { return sprintf("%.2f GiB", $size / 1073741824); }
|
||||||
|
elsif ($size > 1048576) { return sprintf("%.2f MiB", $size / 1048576); }
|
||||||
|
elsif ($size > 1024) { return sprintf("%.2f KiB", $size / 1024); }
|
||||||
|
else { return "$size byte" . ($size == 1 ? "" : "s"); }
|
||||||
|
}
|
||||||
@ -48,10 +48,18 @@ if(-e "eqemu_server_skip_update.txt"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
#::: Check for script self update
|
#::: Check for script self update
|
||||||
|
check_xml_to_json_conversion() if $ARGV[0] eq "convert_xml";
|
||||||
do_self_update_check_routine() if !$skip_self_update_check;
|
do_self_update_check_routine() if !$skip_self_update_check;
|
||||||
get_windows_wget();
|
get_windows_wget();
|
||||||
get_perl_version();
|
get_perl_version();
|
||||||
read_eqemu_config_xml();
|
if(-e "eqemu_config.json") {
|
||||||
|
read_eqemu_config_json();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#::: This will need to stay for servers who simply haven't updated yet
|
||||||
|
# This script can still update without the server bins being updated
|
||||||
|
read_eqemu_config_xml();
|
||||||
|
}
|
||||||
get_mysql_path();
|
get_mysql_path();
|
||||||
|
|
||||||
#::: Remove old eqemu_update.pl
|
#::: Remove old eqemu_update.pl
|
||||||
@ -265,7 +273,7 @@ sub new_server {
|
|||||||
analytics_insertion("new_server::install", $database_name);
|
analytics_insertion("new_server::install", $database_name);
|
||||||
|
|
||||||
if($OS eq "Linux"){
|
if($OS eq "Linux"){
|
||||||
build_linux_source();
|
build_linux_source("login");
|
||||||
}
|
}
|
||||||
|
|
||||||
do_installer_routines();
|
do_installer_routines();
|
||||||
@ -281,6 +289,10 @@ sub new_server {
|
|||||||
|
|
||||||
show_install_summary_info();
|
show_install_summary_info();
|
||||||
|
|
||||||
|
if($OS eq "Linux") {
|
||||||
|
unlink('/home/eqemu/install_variables.txt');
|
||||||
|
}
|
||||||
|
|
||||||
rmtree('updates_staged');
|
rmtree('updates_staged');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -291,6 +303,61 @@ sub new_server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub check_xml_to_json_conversion {
|
||||||
|
if(-e "eqemu_config.xml" && !-e "eqemu_config.json") {
|
||||||
|
|
||||||
|
if($OS eq "Windows"){
|
||||||
|
get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/xmltojson/xmltojson-windows-x86.exe", "xmltojson.exe");
|
||||||
|
print "Converting eqemu_config.xml to eqemu_config.json\n";
|
||||||
|
print `xmltojson eqemu_config.xml`;
|
||||||
|
}
|
||||||
|
if($OS eq "Linux"){
|
||||||
|
get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/xmltojson/xmltojson-linux-x86", "xmltojson");
|
||||||
|
print "Converting eqemu_config.xml to eqemu_config.json\n";
|
||||||
|
print `chmod 755 xmltojson`;
|
||||||
|
print `./xmltojson eqemu_config.xml`;
|
||||||
|
}
|
||||||
|
|
||||||
|
#::: Prettify and alpha order the config
|
||||||
|
use JSON;
|
||||||
|
my $json = new JSON();
|
||||||
|
|
||||||
|
my $content;
|
||||||
|
open(my $fh, '<', "eqemu_config.json") or die "cannot open file $filename"; {
|
||||||
|
local $/;
|
||||||
|
$content = <$fh>;
|
||||||
|
}
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
$result = $json->decode($content);
|
||||||
|
$json->canonical(1);
|
||||||
|
|
||||||
|
print $json->pretty->indent_length(5)->utf8->encode($result),"\n";
|
||||||
|
|
||||||
|
open(my $fh, '>', 'eqemu_config.json');
|
||||||
|
print $fh $json->pretty->indent_length(5)->utf8->encode($result);
|
||||||
|
close $fh;
|
||||||
|
|
||||||
|
mkdir('backups');
|
||||||
|
copy_file("eqemu_config.xml", "backups/eqemu_config.xml");
|
||||||
|
unlink('eqemu_config.xml');
|
||||||
|
unlink('db_dumper.pl');
|
||||||
|
|
||||||
|
print "[Server Maintenance] eqemu_config.xml is now DEPRECATED \n";
|
||||||
|
print "[Server Maintenance] eqemu_config.json is now the new Server config format \n";
|
||||||
|
print " A backup of this old config is located in the backups folder of your server directory\n";
|
||||||
|
print " --- \n";
|
||||||
|
print " You may have some plugins and/or applications that still require reference of this config file\n";
|
||||||
|
print " Please update these plugins/applications to use the new configuration format if needed\n";
|
||||||
|
print " --- \n";
|
||||||
|
print " Thanks for your understanding\n";
|
||||||
|
print " The EQEmulator Team\n\n";
|
||||||
|
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
sub build_linux_source {
|
sub build_linux_source {
|
||||||
|
|
||||||
$build_options = $_[0];
|
$build_options = $_[0];
|
||||||
@ -330,10 +397,10 @@ sub build_linux_source {
|
|||||||
|
|
||||||
print "Generating CMake build files...\n";
|
print "Generating CMake build files...\n";
|
||||||
if($os_flavor eq "fedora_core"){
|
if($os_flavor eq "fedora_core"){
|
||||||
print `cmake $cmake_options -DEQEMU_BUILD_LUA=ON -DLUA_INCLUDE_DIR=/usr/include/lua-5.1/ -G "Unix Makefiles" ..`;
|
print `cmake $cmake_options -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -DLUA_INCLUDE_DIR=/usr/include/lua-5.1/ -G "Unix Makefiles" ..`;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
print `cmake $cmake_options -DEQEMU_BUILD_LUA=ON -G "Unix Makefiles" ..`;
|
print `cmake $cmake_options -DEQEMU_BUILD_LOGIN=ON -DEQEMU_BUILD_LUA=ON -G "Unix Makefiles" ..`;
|
||||||
}
|
}
|
||||||
print "Building EQEmu Server code. This will take a while.";
|
print "Building EQEmu Server code. This will take a while.";
|
||||||
|
|
||||||
@ -352,6 +419,7 @@ sub build_linux_source {
|
|||||||
print `ln -s -f $source_dir/Server/build/bin/ucs .`;
|
print `ln -s -f $source_dir/Server/build/bin/ucs .`;
|
||||||
print `ln -s -f $source_dir/Server/build/bin/world .`;
|
print `ln -s -f $source_dir/Server/build/bin/world .`;
|
||||||
print `ln -s -f $source_dir/Server/build/bin/zone .`;
|
print `ln -s -f $source_dir/Server/build/bin/zone .`;
|
||||||
|
print `ln -s -f $source_dir/Server/build/bin/loginserver .`;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_installer_routines {
|
sub do_installer_routines {
|
||||||
@ -362,8 +430,8 @@ sub do_installer_routines {
|
|||||||
mkdir('updates_staged');
|
mkdir('updates_staged');
|
||||||
mkdir('shared');
|
mkdir('shared');
|
||||||
|
|
||||||
do_install_config_xml();
|
do_install_config_json();
|
||||||
read_eqemu_config_xml();
|
read_eqemu_config_json();
|
||||||
get_installation_variables();
|
get_installation_variables();
|
||||||
|
|
||||||
$db_name = "peq";
|
$db_name = "peq";
|
||||||
@ -579,8 +647,13 @@ sub do_self_update_check_routine {
|
|||||||
sub get_installation_variables{
|
sub get_installation_variables{
|
||||||
#::: Fetch installation variables before building the config
|
#::: Fetch installation variables before building the config
|
||||||
if($OS eq "Linux"){
|
if($OS eq "Linux"){
|
||||||
|
if(-e "../install_variables.txt") {
|
||||||
open (INSTALL_VARS, "../install_variables.txt");
|
open (INSTALL_VARS, "../install_variables.txt");
|
||||||
}
|
}
|
||||||
|
elsif(-e "install_variables.txt") {
|
||||||
|
open (INSTALL_VARS, "./install_variables.txt");
|
||||||
|
}
|
||||||
|
}
|
||||||
if($OS eq "Windows"){
|
if($OS eq "Windows"){
|
||||||
open (INSTALL_VARS, "install_variables.txt");
|
open (INSTALL_VARS, "install_variables.txt");
|
||||||
}
|
}
|
||||||
@ -593,58 +666,28 @@ sub get_installation_variables{
|
|||||||
close (INSTALL_VARS);
|
close (INSTALL_VARS);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_install_config_xml {
|
sub do_install_config_json {
|
||||||
get_installation_variables();
|
get_installation_variables();
|
||||||
|
|
||||||
#::: Fetch XML template
|
#::: Fetch json template
|
||||||
get_remote_file($install_repository_request_url . "eqemu_config.xml", "eqemu_config_template.xml");
|
get_remote_file($install_repository_request_url . "eqemu_config.json", "eqemu_config_template.json");
|
||||||
|
|
||||||
#::: Open new config file
|
use JSON;
|
||||||
open (NEW_CONFIG, '>', 'eqemu_config.xml');
|
my $json = new JSON();
|
||||||
|
|
||||||
$in_database_tag = 0;
|
my $content;
|
||||||
|
open(my $fh, '<', "eqemu_config_template.json") or die "cannot open file $filename"; {
|
||||||
#::: Iterate through template and replace variables...
|
local $/;
|
||||||
open (FILE_TEMPLATE, "eqemu_config_template.xml");
|
$content = <$fh>;
|
||||||
while (<FILE_TEMPLATE>){
|
|
||||||
chomp;
|
|
||||||
$o = $_;
|
|
||||||
|
|
||||||
#::: Find replace variables
|
|
||||||
|
|
||||||
if($o=~/\<\!--/i){
|
|
||||||
next;
|
|
||||||
}
|
}
|
||||||
|
close($fh);
|
||||||
|
|
||||||
if($o=~/database/i && $o=~/\<\//i){
|
$config = $json->decode($content);
|
||||||
$in_database_tag = 0;
|
|
||||||
}
|
|
||||||
if($o=~/database/i){
|
|
||||||
$in_database_tag = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($o=~/key/i){
|
$long_name = "Akkas " . $OS . " PEQ Installer (" . generate_random_password(5) . ')';
|
||||||
my($replace_key) = $o =~ />(\w+)</;
|
$config->{"server"}{"world"}{"longname"} = $long_name;
|
||||||
$new_key = generate_random_password(30);
|
$config->{"server"}{"world"}{"key"} = generate_random_password(30);
|
||||||
$o =~ s/$replace_key/$new_key/g;
|
|
||||||
}
|
|
||||||
if($o=~/\<longname\>/i){
|
|
||||||
my($replace_name) = $o =~ /<longname>(.*)<\/longname>/;
|
|
||||||
$append = '(' . generate_random_password(5) . ')';
|
|
||||||
$o =~ s/$replace_name/Akkas $OS PEQ Installer $append/g;
|
|
||||||
}
|
|
||||||
if($o=~/\<username\>/i && $in_database_tag){
|
|
||||||
my($replace_username) = $o =~ />(\w+)</;
|
|
||||||
$o =~ s/$replace_username/$installation_variables{"mysql_eqemu_user"}/g;
|
|
||||||
}
|
|
||||||
if($o=~/\<password\>/i && $in_database_tag){
|
|
||||||
my($replace_password) = $o =~ />(\w+)</;
|
|
||||||
$o =~ s/$replace_password/$installation_variables{"mysql_eqemu_password"}/g;
|
|
||||||
}
|
|
||||||
if($o=~/\<db\>/i){
|
|
||||||
my($replace_db_name) = $o =~ />(\w+)</;
|
|
||||||
|
|
||||||
#::: There is really no reason why this shouldn't be set
|
|
||||||
if($installation_variables{"mysql_eqemu_db_name"}){
|
if($installation_variables{"mysql_eqemu_db_name"}){
|
||||||
$db_name = $installation_variables{"mysql_eqemu_db_name"};
|
$db_name = $installation_variables{"mysql_eqemu_db_name"};
|
||||||
}
|
}
|
||||||
@ -652,14 +695,22 @@ sub do_install_config_xml {
|
|||||||
$db_name = "peq";
|
$db_name = "peq";
|
||||||
}
|
}
|
||||||
|
|
||||||
$o =~ s/$replace_db_name/$db_name/g;
|
$config->{"server"}{"database"}{"username"} = $installation_variables{"mysql_eqemu_user"};
|
||||||
}
|
$config->{"server"}{"database"}{"password"} = $installation_variables{"mysql_eqemu_password"};
|
||||||
print NEW_CONFIG $o . "\n";
|
$config->{"server"}{"database"}{"db"} = $db_name;
|
||||||
}
|
|
||||||
|
|
||||||
close(FILE_TEMPLATE);
|
$config->{"server"}{"qsdatabase"}{"username"} = $installation_variables{"mysql_eqemu_user"};
|
||||||
close(NEW_CONFIG);
|
$config->{"server"}{"qsdatabase"}{"password"} = $installation_variables{"mysql_eqemu_password"};
|
||||||
unlink("eqemu_config_template.xml");
|
$config->{"server"}{"qsdatabase"}{"db"} = $db_name;
|
||||||
|
|
||||||
|
$json->canonical(1);
|
||||||
|
$json->indent_length(5);
|
||||||
|
|
||||||
|
open(my $fh, '>', 'eqemu_config.json');
|
||||||
|
print $fh $json->pretty->indent_length(5)->utf8->encode($config);
|
||||||
|
close $fh;
|
||||||
|
|
||||||
|
unlink("eqemu_config_template.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
sub fetch_utility_scripts {
|
sub fetch_utility_scripts {
|
||||||
@ -766,6 +817,7 @@ sub show_menu_prompt {
|
|||||||
elsif($input eq "setup_loginserver"){ do_windows_login_server_setup(); $dc = 1; }
|
elsif($input eq "setup_loginserver"){ do_windows_login_server_setup(); $dc = 1; }
|
||||||
elsif($input eq "new_server"){ new_server(); $dc = 1; }
|
elsif($input eq "new_server"){ new_server(); $dc = 1; }
|
||||||
elsif($input eq "setup_bots"){ setup_bots(); $dc = 1; }
|
elsif($input eq "setup_bots"){ setup_bots(); $dc = 1; }
|
||||||
|
elsif($input eq "linux_login_server_setup"){ do_linux_login_server_setup(); $dc = 1; }
|
||||||
elsif($input eq "exit"){
|
elsif($input eq "exit"){
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
@ -858,13 +910,13 @@ sub check_for_database_dump_script{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#::: Check for script changes :: db_dumper.pl
|
#::: Check for script changes :: database_dumper.pl
|
||||||
get_remote_file($eqemu_repository_request_url . "utils/scripts/db_dumper.pl", "updates_staged/db_dumper.pl", 0, 1, 1);
|
get_remote_file($eqemu_repository_request_url . "utils/scripts/database_dumper.pl", "updates_staged/database_dumper.pl", 0, 1, 1);
|
||||||
|
|
||||||
if(-e "updates_staged/db_dumper.pl") {
|
if(-e "updates_staged/database_dumper.pl") {
|
||||||
|
|
||||||
my $remote_script_size = -s "updates_staged/db_dumper.pl";
|
my $remote_script_size = -s "updates_staged/database_dumper.pl";
|
||||||
my $local_script_size = -s "db_dumper.pl";
|
my $local_script_size = -s "database_dumper.pl";
|
||||||
|
|
||||||
if($remote_script_size != $local_script_size){
|
if($remote_script_size != $local_script_size){
|
||||||
print "[Update] Script has been updated, updating...\n";
|
print "[Update] Script has been updated, updating...\n";
|
||||||
@ -876,14 +928,14 @@ sub check_for_database_dump_script{
|
|||||||
$start_dir
|
$start_dir
|
||||||
);
|
);
|
||||||
for my $file (@files) {
|
for my $file (@files) {
|
||||||
if($file=~/db_dumper/i){
|
if($file=~/database_dumper/i){
|
||||||
$destination_file = $file;
|
$destination_file = $file;
|
||||||
$destination_file =~s/updates_staged\///g;
|
$destination_file =~s/updates_staged\///g;
|
||||||
print "[Install] Installing :: " . $destination_file . "\n";
|
print "[Install] Installing :: " . $destination_file . "\n";
|
||||||
unlink($destination_file);
|
unlink($destination_file);
|
||||||
copy_file($file, $destination_file);
|
copy_file($file, $destination_file);
|
||||||
if($OS eq "Linux"){
|
if($OS eq "Linux"){
|
||||||
system("chmod 755 db_dumper.pl");
|
system("chmod 755 database_dumper.pl");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -893,7 +945,7 @@ sub check_for_database_dump_script{
|
|||||||
print "[Update] No script update necessary...\n";
|
print "[Update] No script update necessary...\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink("updates_staged/db_dumper.pl");
|
unlink("updates_staged/database_dumper.pl");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -903,7 +955,7 @@ sub check_for_database_dump_script{
|
|||||||
sub database_dump {
|
sub database_dump {
|
||||||
check_for_database_dump_script();
|
check_for_database_dump_script();
|
||||||
print "[Database] Performing database backup....\n";
|
print "[Database] Performing database backup....\n";
|
||||||
print `perl db_dumper.pl database="$db" loc="backups"`;
|
print `perl database_dumper.pl database="$db" loc="backups"`;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub database_dump_player_tables {
|
sub database_dump_player_tables {
|
||||||
@ -921,7 +973,7 @@ sub database_dump_player_tables {
|
|||||||
}
|
}
|
||||||
$tables = substr($tables, 0, -1);
|
$tables = substr($tables, 0, -1);
|
||||||
|
|
||||||
print `perl db_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`;
|
print `perl database_dumper.pl database="$db" loc="backups" tables="$tables" backup_name="player_tables_export" nolock`;
|
||||||
|
|
||||||
print "[Database] Press any key to continue...\n";
|
print "[Database] Press any key to continue...\n";
|
||||||
|
|
||||||
@ -932,7 +984,7 @@ sub database_dump_player_tables {
|
|||||||
sub database_dump_compress {
|
sub database_dump_compress {
|
||||||
check_for_database_dump_script();
|
check_for_database_dump_script();
|
||||||
print "[Database] Performing database backup....\n";
|
print "[Database] Performing database backup....\n";
|
||||||
print `perl db_dumper.pl database="$db" loc="backups" compress`;
|
print `perl database_dumper.pl database="$db" loc="backups" compress`;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub script_exit{
|
sub script_exit{
|
||||||
@ -1008,7 +1060,7 @@ sub get_remote_file{
|
|||||||
}
|
}
|
||||||
|
|
||||||
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
|
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
|
||||||
$wget = `wget -N --no-check-certificate --quiet -O $destination_file $request_url`;
|
$wget = `wget -N --cache=no --no-check-certificate --quiet -O $destination_file $request_url`;
|
||||||
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
|
print "[Download] Saved: (" . $destination_file . ") from " . $request_url . "\n" if !$silent_download;
|
||||||
if($wget=~/unable to resolve/i){
|
if($wget=~/unable to resolve/i){
|
||||||
print "Error, no connection or failed request...\n\n";
|
print "Error, no connection or failed request...\n\n";
|
||||||
@ -1072,6 +1124,26 @@ sub read_eqemu_config_xml {
|
|||||||
close(CONFIG);
|
close(CONFIG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub read_eqemu_config_json {
|
||||||
|
use JSON;
|
||||||
|
my $json = new JSON();
|
||||||
|
|
||||||
|
my $content;
|
||||||
|
open(my $fh, '<', "eqemu_config.json") or die "cannot open file $filename"; {
|
||||||
|
local $/;
|
||||||
|
$content = <$fh>;
|
||||||
|
}
|
||||||
|
close($fh);
|
||||||
|
|
||||||
|
$config = $json->decode($content);
|
||||||
|
|
||||||
|
$db = $config->{"server"}{"database"}{"db"};
|
||||||
|
$host = $config->{"server"}{"database"}{"host"};
|
||||||
|
$user = $config->{"server"}{"database"}{"username"};
|
||||||
|
$pass = $config->{"server"}{"database"}{"password"};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#::: Fetch Latest PEQ AA's
|
#::: Fetch Latest PEQ AA's
|
||||||
sub aa_fetch{
|
sub aa_fetch{
|
||||||
if(!$db){
|
if(!$db){
|
||||||
@ -1277,6 +1349,8 @@ sub do_windows_login_server_setup {
|
|||||||
|
|
||||||
sub do_linux_login_server_setup {
|
sub do_linux_login_server_setup {
|
||||||
|
|
||||||
|
build_linux_source();
|
||||||
|
|
||||||
for my $file (@files) {
|
for my $file (@files) {
|
||||||
$destination_file = $file;
|
$destination_file = $file;
|
||||||
$destination_file =~s/updates_staged\/login_server\///g;
|
$destination_file =~s/updates_staged\/login_server\///g;
|
||||||
@ -1297,6 +1371,8 @@ sub do_linux_login_server_setup {
|
|||||||
get_remote_file($install_repository_request_url . "linux/login.ini", "login_template.ini");
|
get_remote_file($install_repository_request_url . "linux/login.ini", "login_template.ini");
|
||||||
get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf");
|
get_remote_file($install_repository_request_url . "linux/login_opcodes.conf", "login_opcodes.conf");
|
||||||
get_remote_file($install_repository_request_url . "linux/login_opcodes_sod.conf", "login_opcodes_sod.conf");
|
get_remote_file($install_repository_request_url . "linux/login_opcodes_sod.conf", "login_opcodes_sod.conf");
|
||||||
|
get_remote_file($install_repository_request_url . "linux/server_start_with_login.sh", "server_start_with_login.sh");
|
||||||
|
system("chmod 755 *.sh");
|
||||||
|
|
||||||
get_installation_variables();
|
get_installation_variables();
|
||||||
my $db_name = $installation_variables{"mysql_eqemu_db_name"};
|
my $db_name = $installation_variables{"mysql_eqemu_db_name"};
|
||||||
|
|||||||
@ -119,6 +119,7 @@ if [[ "$OS" == "Debian" ]]; then
|
|||||||
apt-get $apt_options install zlibc
|
apt-get $apt_options install zlibc
|
||||||
apt-get $apt_options install libsodium-dev
|
apt-get $apt_options install libsodium-dev
|
||||||
apt-get $apt_options install libsodium18
|
apt-get $apt_options install libsodium18
|
||||||
|
apt-get $apt_options install libjson-perl
|
||||||
|
|
||||||
# If libsodium18 isn't installed (Debian), let's download both that and the dev package and install them.
|
# If libsodium18 isn't installed (Debian), let's download both that and the dev package and install them.
|
||||||
if dpkg-query -s "libsodium18" 1>/dev/null 2>&1; then
|
if dpkg-query -s "libsodium18" 1>/dev/null 2>&1; then
|
||||||
@ -159,7 +160,7 @@ EOF
|
|||||||
# Install prereqs
|
# Install prereqs
|
||||||
yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
|
||||||
yum -y install deltarpm
|
yum -y install deltarpm
|
||||||
yum -y install open-vm-tools vim cmake boost-* zlib-devel mariadb-server mariadb-client mariadb-devel mariadb-libs mariadb-compat perl-* lua* dos2unix php-mysql proftpd
|
yum -y install open-vm-tools vim cmake boost-* zlib-devel mariadb-server mariadb-client mariadb-devel mariadb-libs mariadb-compat perl-* lua* dos2unix php-mysql proftpd libuuid-devel
|
||||||
yum -y groupinstall "Development Tools" "Basic Web Server" "Compatibility Libraries"
|
yum -y groupinstall "Development Tools" "Basic Web Server" "Compatibility Libraries"
|
||||||
|
|
||||||
elif [[ "$OS" == "fedora_core" ]]; then
|
elif [[ "$OS" == "fedora_core" ]]; then
|
||||||
|
|||||||
@ -17,7 +17,6 @@ character_bind
|
|||||||
character_corpses
|
character_corpses
|
||||||
character_corpse_items
|
character_corpse_items
|
||||||
character_languages
|
character_languages
|
||||||
character_lookup
|
|
||||||
character_skills
|
character_skills
|
||||||
character_spells
|
character_spells
|
||||||
character_memmed_spells
|
character_memmed_spells
|
||||||
|
|||||||
2
utils/xmltojson/.gitignore
vendored
Normal file
2
utils/xmltojson/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
eqemu_config.xml
|
||||||
|
eqemu_config.json
|
||||||
1
utils/xmltojson/README.md
Normal file
1
utils/xmltojson/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
Converts the old eqemu_config.xml to eqemu_config.json
|
||||||
21
utils/xmltojson/build.bat
Normal file
21
utils/xmltojson/build.bat
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
set name="xmltojson"
|
||||||
|
|
||||||
|
echo Building Linux
|
||||||
|
set GOOS=linux
|
||||||
|
set GOARCH=amd64
|
||||||
|
go build -o %name%-linux-x64 main.go
|
||||||
|
set GOARCH=386
|
||||||
|
go build -o %name%-linux-x86 main.go
|
||||||
|
echo Building Windows
|
||||||
|
set GOOS=windows
|
||||||
|
set GOARCH=amd64
|
||||||
|
go build -o %name%-windows-x64.exe main.go
|
||||||
|
set GOARCH=386
|
||||||
|
go build -o %name%-windows-x86.exe main.go
|
||||||
|
echo Building OSX
|
||||||
|
REM set GOOS=darwin
|
||||||
|
REM set GOARCH=amd64
|
||||||
|
REM go build -o %name%-osx-x64 main.go
|
||||||
|
endlocal
|
||||||
11
utils/xmltojson/build.sh
Normal file
11
utils/xmltojson/build.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
export NAME="xmltojson"
|
||||||
|
echo Building Linux
|
||||||
|
GOOS=linux GOARCH=amd64 go build -o $NAME-linux-x64 main.go
|
||||||
|
GOOS=linux GOARCH=386 go build -o $NAME-linux-x86 main.go
|
||||||
|
echo Building Windows
|
||||||
|
GOOS=windows GOARCH=amd64 go build -o $NAME-windows-x64.exe main.go
|
||||||
|
GOOS=windows GOARCH=386 go build -o $NAME-windows-x86.exe main.go
|
||||||
|
#echo Building OSX
|
||||||
|
#GOOS=darwin GOARCH=amd64 go build -o $NAME-osx-x64 main.go
|
||||||
85
utils/xmltojson/main.go
Normal file
85
utils/xmltojson/main.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
xj "github.com/basgys/goxml2json"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
var err error
|
||||||
|
var data []byte
|
||||||
|
var sData string
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
var buf2 bytes.Buffer
|
||||||
|
|
||||||
|
if data, err = ioutil.ReadFile("eqemu_config.xml"); err != nil {
|
||||||
|
fmt.Println("Failed to open eqemu_config.xml:", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//detect malformed xml in eqemuconfig
|
||||||
|
sData = strings.Replace(string(data), "<?xml version=\"1.0\">", "<?xml version=\"1.0\"?>", 1)
|
||||||
|
r := strings.NewReader(sData)
|
||||||
|
dec := xj.NewDecoder(r)
|
||||||
|
root := &xj.Node{}
|
||||||
|
if err = dec.DecodeWithCustomPrefixes(root, "", ""); err != nil {
|
||||||
|
fmt.Println("Failed to decode eqemu_config.xml:", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if root.Children["server"] == nil || len(root.Children["server"]) < 1 {
|
||||||
|
fmt.Println("Server element not found")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
server := root.Children["server"][0]
|
||||||
|
|
||||||
|
//locked: "true" is only way to trigger locked
|
||||||
|
if server.Children["world"] != nil && len(server.Children["world"]) > 0 {
|
||||||
|
world := server.Children["world"][0]
|
||||||
|
|
||||||
|
if world.Children["locked"] != nil && len(world.Children["locked"]) > 0 {
|
||||||
|
fmt.Println("Locked!")
|
||||||
|
world.Children["locked"][0].Data = "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elements := []string{
|
||||||
|
"chatserver",
|
||||||
|
"directories",
|
||||||
|
"files",
|
||||||
|
"launcher",
|
||||||
|
"mailserver",
|
||||||
|
"webinterface",
|
||||||
|
"world",
|
||||||
|
"zones",
|
||||||
|
}
|
||||||
|
for _, ele := range elements {
|
||||||
|
if server.Children[ele] != nil && len(server.Children[ele]) > 0 && len(server.Children[ele][0].Children) == 0 {
|
||||||
|
delete(server.Children, ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enc := xj.NewEncoder(buf)
|
||||||
|
err = enc.EncodeWithCustomPrefixes(root, "", "")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println("Failed to encode eqemu_config.xml:", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//prettyprint
|
||||||
|
if err = json.Indent(&buf2, buf.Bytes(), "", "\t"); err != nil {
|
||||||
|
fmt.Println("Failed to encode json:", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile("eqemu_config.json", buf2.Bytes(), 0744); err != nil {
|
||||||
|
fmt.Println("Failed to write eqemu_config.json:", err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
utils/xmltojson/xmltojson-linux-x64
Normal file
BIN
utils/xmltojson/xmltojson-linux-x64
Normal file
Binary file not shown.
BIN
utils/xmltojson/xmltojson-linux-x86
Normal file
BIN
utils/xmltojson/xmltojson-linux-x86
Normal file
Binary file not shown.
BIN
utils/xmltojson/xmltojson-windows-x64
Normal file
BIN
utils/xmltojson/xmltojson-windows-x64
Normal file
Binary file not shown.
BIN
utils/xmltojson/xmltojson-windows-x64.exe
Normal file
BIN
utils/xmltojson/xmltojson-windows-x64.exe
Normal file
Binary file not shown.
BIN
utils/xmltojson/xmltojson-windows-x86
Normal file
BIN
utils/xmltojson/xmltojson-windows-x86
Normal file
Binary file not shown.
BIN
utils/xmltojson/xmltojson-windows-x86.exe
Normal file
BIN
utils/xmltojson/xmltojson-windows-x86.exe
Normal file
Binary file not shown.
@ -104,6 +104,7 @@ EQEmuLogSys LogSys;
|
|||||||
WebInterfaceList web_interface;
|
WebInterfaceList web_interface;
|
||||||
|
|
||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
|
void CheckForServerScript(bool force_download = false);
|
||||||
|
|
||||||
inline void UpdateWindowTitle(std::string new_title) {
|
inline void UpdateWindowTitle(std::string new_title) {
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
@ -116,6 +117,17 @@ int main(int argc, char** argv) {
|
|||||||
LogSys.LoadLogSettingsDefaults();
|
LogSys.LoadLogSettingsDefaults();
|
||||||
set_exception_handler();
|
set_exception_handler();
|
||||||
|
|
||||||
|
/* If eqemu_config.json does not exist - create it from conversion... */
|
||||||
|
if (!std::ifstream("eqemu_config.json")) {
|
||||||
|
CheckForServerScript(true);
|
||||||
|
/* Run EQEmu Server script (Checks for database updates) */
|
||||||
|
system("perl eqemu_server.pl convert_xml");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Download EQEmu Server Maintenance Script if doesn't exist */
|
||||||
|
CheckForServerScript();
|
||||||
|
}
|
||||||
|
|
||||||
/* Database Version Check */
|
/* Database Version Check */
|
||||||
uint32 Database_Version = CURRENT_BINARY_DATABASE_VERSION;
|
uint32 Database_Version = CURRENT_BINARY_DATABASE_VERSION;
|
||||||
uint32 Bots_Database_Version = CURRENT_BINARY_BOTS_DATABASE_VERSION;
|
uint32 Bots_Database_Version = CURRENT_BINARY_BOTS_DATABASE_VERSION;
|
||||||
@ -173,7 +185,7 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Log(Logs::General, Logs::World_Server, "Connecting to MySQL...");
|
Log(Logs::General, Logs::World_Server, "Connecting to MySQL %s@%s:%i...", Config->DatabaseUsername.c_str(), Config->DatabaseHost.c_str(), Config->DatabasePort);
|
||||||
if (!database.Connect(
|
if (!database.Connect(
|
||||||
Config->DatabaseHost.c_str(),
|
Config->DatabaseHost.c_str(),
|
||||||
Config->DatabaseUsername.c_str(),
|
Config->DatabaseUsername.c_str(),
|
||||||
@ -578,3 +590,32 @@ void CatchSignal(int sig_num) {
|
|||||||
Log(Logs::General, Logs::World_Server, "Caught signal %d", sig_num);
|
Log(Logs::General, Logs::World_Server, "Caught signal %d", sig_num);
|
||||||
RunLoops = false;
|
RunLoops = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateWindowTitle(char* iNewTitle) {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
char tmp[500];
|
||||||
|
if (iNewTitle) {
|
||||||
|
snprintf(tmp, sizeof(tmp), "World: %s", iNewTitle);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
snprintf(tmp, sizeof(tmp), "World");
|
||||||
|
}
|
||||||
|
SetConsoleTitle(tmp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckForServerScript(bool force_download) {
|
||||||
|
/* Fetch EQEmu Server script */
|
||||||
|
if (!std::ifstream("eqemu_server.pl") || force_download) {
|
||||||
|
|
||||||
|
if(force_download)
|
||||||
|
std::remove("eqemu_server.pl"); /* Delete local before fetch */
|
||||||
|
|
||||||
|
std::cout << "Pulling down EQEmu Server Maintenance Script (eqemu_server.pl)..." << std::endl;
|
||||||
|
#ifdef _WIN32
|
||||||
|
system("perl -MLWP::UserAgent -e \"require LWP::UserAgent; my $ua = LWP::UserAgent->new; $ua->timeout(10); $ua->env_proxy; my $response = $ua->get('https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl'); if ($response->is_success){ open(FILE, '> eqemu_server.pl'); print FILE $response->decoded_content; close(FILE); }\"");
|
||||||
|
#else
|
||||||
|
system("wget -N --no-check-certificate --quiet -O eqemu_server.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -52,7 +52,7 @@ public:
|
|||||||
_world_config=new WorldConfig;
|
_world_config=new WorldConfig;
|
||||||
_config=_world_config;
|
_config=_world_config;
|
||||||
|
|
||||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
|
return _config->parseFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors for the static private object
|
// Accessors for the static private object
|
||||||
|
|||||||
@ -253,7 +253,7 @@ bool Mob::CheckWillAggro(Mob *mob) {
|
|||||||
//sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM
|
//sometimes if a client has some lag while zoning into a dangerous place while either invis or a GM
|
||||||
//they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting
|
//they will aggro mobs even though it's supposed to be impossible, to lets make sure we've finished connecting
|
||||||
if (mob->IsClient()) {
|
if (mob->IsClient()) {
|
||||||
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->zoning)
|
if (!mob->CastToClient()->ClientFinishedLoading() || mob->CastToClient()->IsHoveringForRespawn() || mob->CastToClient()->bZoning)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1729,6 +1729,15 @@ bool Client::Death(Mob* killerMob, int32 damage, uint16 spell, EQEmu::skills::Sk
|
|||||||
exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
exploss = (int)(GetLevel() * (GetLevel() / 18.0) * 12000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||||
|
// Death in levels with xp_mod (such as hell levels) was resulting
|
||||||
|
// in losing more that appropriate since the loss was the same but
|
||||||
|
// getting it back would take way longer. This makes the death the
|
||||||
|
// same amount of time to recover. Will also lose more if level is
|
||||||
|
// granting a bonus.
|
||||||
|
exploss *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||||
|
}
|
||||||
|
|
||||||
if ((GetLevel() < RuleI(Character, DeathExpLossLevel)) || (GetLevel() > RuleI(Character, DeathExpLossMaxLevel)) || IsBecomeNPC())
|
if ((GetLevel() < RuleI(Character, DeathExpLossLevel)) || (GetLevel() > RuleI(Character, DeathExpLossMaxLevel)) || IsBecomeNPC())
|
||||||
{
|
{
|
||||||
exploss = 0;
|
exploss = 0;
|
||||||
@ -2675,7 +2684,7 @@ void Mob::AddToHateList(Mob* other, uint32 hate /*= 0*/, int32 damage /*= 0*/, b
|
|||||||
|
|
||||||
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
hate_list.AddEntToHateList(other, hate, damage, bFrenzy, !iBuffTic);
|
||||||
|
|
||||||
if (other->IsClient() && !on_hatelist)
|
if (other->IsClient() && !on_hatelist && !IsOnFeignMemory(other->CastToClient()))
|
||||||
other->CastToClient()->AddAutoXTarget(this);
|
other->CastToClient()->AddAutoXTarget(this);
|
||||||
|
|
||||||
#ifdef BOTS
|
#ifdef BOTS
|
||||||
|
|||||||
@ -215,7 +215,7 @@ Client::Client(EQStreamInterface* ieqs)
|
|||||||
linkdead_timer.Disable();
|
linkdead_timer.Disable();
|
||||||
zonesummon_id = 0;
|
zonesummon_id = 0;
|
||||||
zonesummon_ignorerestrictions = 0;
|
zonesummon_ignorerestrictions = 0;
|
||||||
zoning = false;
|
bZoning = false;
|
||||||
zone_mode = ZoneUnsolicited;
|
zone_mode = ZoneUnsolicited;
|
||||||
casting_spell_id = 0;
|
casting_spell_id = 0;
|
||||||
npcflag = false;
|
npcflag = false;
|
||||||
@ -395,7 +395,7 @@ Client::~Client() {
|
|||||||
GetTarget()->IsTargeted(-1);
|
GetTarget()->IsTargeted(-1);
|
||||||
|
|
||||||
//if we are in a group and we are not zoning, force leave the group
|
//if we are in a group and we are not zoning, force leave the group
|
||||||
if(isgrouped && !zoning && is_zone_loaded)
|
if(isgrouped && !bZoning && is_zone_loaded)
|
||||||
LeaveGroup();
|
LeaveGroup();
|
||||||
|
|
||||||
UpdateWho(2);
|
UpdateWho(2);
|
||||||
|
|||||||
@ -606,6 +606,10 @@ public:
|
|||||||
uint32 GetExperienceForKill(Mob *against);
|
uint32 GetExperienceForKill(Mob *against);
|
||||||
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
void AddEXP(uint32 in_add_exp, uint8 conlevel = 0xFF, bool resexp = false);
|
||||||
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
uint32 CalcEXP(uint8 conlevel = 0xFF);
|
||||||
|
void CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp);
|
||||||
|
void CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp);
|
||||||
|
void CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel);
|
||||||
|
void CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp);
|
||||||
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
void SetEXP(uint32 set_exp, uint32 set_aaxp, bool resexp=false);
|
||||||
void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
|
void AddLevelBasedExp(uint8 exp_percentage, uint8 max_level=0);
|
||||||
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);
|
void SetLeadershipEXP(uint32 group_exp, uint32 raid_exp);
|
||||||
@ -651,6 +655,7 @@ public:
|
|||||||
void Sacrifice(Client* caster);
|
void Sacrifice(Client* caster);
|
||||||
void GoToDeath();
|
void GoToDeath();
|
||||||
inline const int32 GetInstanceID() const { return zone->GetInstanceID(); }
|
inline const int32 GetInstanceID() const { return zone->GetInstanceID(); }
|
||||||
|
void SetZoning(bool in) { bZoning = in; }
|
||||||
|
|
||||||
FACTION_VALUE GetReverseFactionCon(Mob* iOther);
|
FACTION_VALUE GetReverseFactionCon(Mob* iOther);
|
||||||
FACTION_VALUE GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_race, uint32 p_class, uint32 p_deity, int32 pFaction, Mob* tnpc);
|
FACTION_VALUE GetFactionLevel(uint32 char_id, uint32 npc_id, uint32 p_race, uint32 p_class, uint32 p_deity, int32 pFaction, Mob* tnpc);
|
||||||
@ -1542,7 +1547,7 @@ private:
|
|||||||
bool npcflag;
|
bool npcflag;
|
||||||
uint8 npclevel;
|
uint8 npclevel;
|
||||||
bool feigned;
|
bool feigned;
|
||||||
bool zoning;
|
bool bZoning;
|
||||||
bool tgb;
|
bool tgb;
|
||||||
bool instalog;
|
bool instalog;
|
||||||
int32 last_reported_mana;
|
int32 last_reported_mana;
|
||||||
|
|||||||
@ -264,7 +264,7 @@ bool Client::Process() {
|
|||||||
if (distance <= scan_range) {
|
if (distance <= scan_range) {
|
||||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||||
}
|
}
|
||||||
else if (mob->GetAggroRange() > scan_range) {
|
else if ((mob->GetAggroRange() * mob->GetAggroRange()) > scan_range) {
|
||||||
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
close_mobs.insert(std::pair<Mob *, float>(mob, distance));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -655,17 +655,17 @@ bool Client::Process() {
|
|||||||
{
|
{
|
||||||
//client logged out or errored out
|
//client logged out or errored out
|
||||||
//ResetTrade();
|
//ResetTrade();
|
||||||
if (client_state != CLIENT_KICKED && !zoning && !instalog) {
|
if (client_state != CLIENT_KICKED && !bZoning && !instalog) {
|
||||||
Save();
|
Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
client_state = CLIENT_LINKDEAD;
|
client_state = CLIENT_LINKDEAD;
|
||||||
if (zoning || instalog || GetGM())
|
if (bZoning || instalog || GetGM())
|
||||||
{
|
{
|
||||||
Group *mygroup = GetGroup();
|
Group *mygroup = GetGroup();
|
||||||
if (mygroup)
|
if (mygroup)
|
||||||
{
|
{
|
||||||
if (!zoning)
|
if (!bZoning)
|
||||||
{
|
{
|
||||||
entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName());
|
entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName());
|
||||||
LeaveGroup();
|
LeaveGroup();
|
||||||
@ -684,7 +684,7 @@ bool Client::Process() {
|
|||||||
Raid *myraid = entity_list.GetRaidByClient(this);
|
Raid *myraid = entity_list.GetRaidByClient(this);
|
||||||
if (myraid)
|
if (myraid)
|
||||||
{
|
{
|
||||||
if (!zoning)
|
if (!bZoning)
|
||||||
{
|
{
|
||||||
//entity_list.MessageGroup(this,true,15,"%s logged out.",GetName());
|
//entity_list.MessageGroup(this,true,15,"%s logged out.",GetName());
|
||||||
myraid->MemberZoned(this);
|
myraid->MemberZoned(this);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -3257,7 +3257,7 @@ void EntityList::AddHealAggro(Mob *target, Mob *caster, uint16 hate)
|
|||||||
|
|
||||||
for (auto &e : npc_list) {
|
for (auto &e : npc_list) {
|
||||||
auto &npc = e.second;
|
auto &npc = e.second;
|
||||||
if (!npc->CheckAggro(target) || npc->IsFeared())
|
if (!npc->CheckAggro(target) || npc->IsFeared() || npc->IsPet())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (zone->random.Roll(50)) // witness check -- place holder
|
if (zone->random.Roll(50)) // witness check -- place holder
|
||||||
|
|||||||
435
zone/exp.cpp
435
zone/exp.cpp
@ -37,6 +37,49 @@
|
|||||||
|
|
||||||
extern QueryServ* QServ;
|
extern QueryServ* QServ;
|
||||||
|
|
||||||
|
static uint32 ScaleAAXPBasedOnCurrentAATotal(int earnedAA, uint32 add_aaxp)
|
||||||
|
{
|
||||||
|
float baseModifier = RuleR(AA, ModernAAScalingStartPercent);
|
||||||
|
int aaMinimum = RuleI(AA, ModernAAScalingAAMinimum);
|
||||||
|
int aaLimit = RuleI(AA, ModernAAScalingAALimit);
|
||||||
|
|
||||||
|
// Are we within the scaling window?
|
||||||
|
if (earnedAA >= aaLimit || earnedAA < aaMinimum)
|
||||||
|
{
|
||||||
|
Log(Logs::Detail, Logs::None, "Not within AA scaling window.");
|
||||||
|
|
||||||
|
// At or past the limit. We're done.
|
||||||
|
return add_aaxp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're not at the limit yet. How close are we?
|
||||||
|
int remainingAA = aaLimit - earnedAA;
|
||||||
|
|
||||||
|
// We might not always be X - 0
|
||||||
|
int scaleRange = aaLimit - aaMinimum;
|
||||||
|
|
||||||
|
// Normalize and get the effectiveness based on the range and the character's
|
||||||
|
// current spent AA.
|
||||||
|
float normalizedScale = (float)remainingAA / scaleRange;
|
||||||
|
|
||||||
|
// Scale.
|
||||||
|
uint32 totalWithExpMod = add_aaxp * (baseModifier / 100) * normalizedScale;
|
||||||
|
|
||||||
|
// Are we so close to the scale limit that we're earning more XP without scaling? This
|
||||||
|
// will happen when we get very close to the limit. In this case, just grant the unscaled
|
||||||
|
// amount.
|
||||||
|
if (totalWithExpMod < add_aaxp)
|
||||||
|
{
|
||||||
|
return add_aaxp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(Logs::Detail,
|
||||||
|
Logs::None,
|
||||||
|
"Total before the modifier %d :: NewTotal %d :: ScaleRange: %d, SpentAA: %d, RemainingAA: %d, normalizedScale: %0.3f",
|
||||||
|
add_aaxp, totalWithExpMod, scaleRange, earnedAA, remainingAA, normalizedScale);
|
||||||
|
|
||||||
|
return totalWithExpMod;
|
||||||
|
}
|
||||||
|
|
||||||
static uint32 MaxBankedGroupLeadershipPoints(int Level)
|
static uint32 MaxBankedGroupLeadershipPoints(int Level)
|
||||||
{
|
{
|
||||||
@ -174,192 +217,302 @@ uint32 Client::GetExperienceForKill(Mob *against)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
float static GetConLevelModifierPercent(uint8 conlevel)
|
||||||
|
{
|
||||||
|
switch (conlevel)
|
||||||
|
{
|
||||||
|
case CON_GREEN:
|
||||||
|
return (float)RuleI(Character, GreenModifier) / 100;
|
||||||
|
break;
|
||||||
|
case CON_LIGHTBLUE:
|
||||||
|
return (float)RuleI(Character, LightBlueModifier) / 100;
|
||||||
|
break;
|
||||||
|
case CON_BLUE:
|
||||||
|
return (float)RuleI(Character, BlueModifier) / 100;
|
||||||
|
break;
|
||||||
|
case CON_WHITE:
|
||||||
|
return (float)RuleI(Character, WhiteModifier) / 100;
|
||||||
|
break;
|
||||||
|
case CON_YELLOW:
|
||||||
|
return (float)RuleI(Character, YellowModifier) / 100;
|
||||||
|
break;
|
||||||
|
case CON_RED:
|
||||||
|
return (float)RuleI(Character, RedModifier) / 100;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this->EVENT_ITEM_ScriptStopReturn();
|
void Client::CalculateNormalizedAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
|
||||||
|
{
|
||||||
uint32 add_exp = in_add_exp;
|
// Functionally this is the same as having the case in the switch, but this is
|
||||||
|
// cleaner to read.
|
||||||
if(!resexp && (XPRate != 0))
|
if (CON_GRAY == conlevel || resexp)
|
||||||
add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
|
{
|
||||||
|
|
||||||
if (m_epp.perAA<0 || m_epp.perAA>100)
|
|
||||||
m_epp.perAA=0; // stop exploit with sanity check
|
|
||||||
|
|
||||||
uint32 add_aaxp;
|
|
||||||
if(resexp) {
|
|
||||||
add_aaxp = 0;
|
add_aaxp = 0;
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For this, we ignore the provided value of add_aaxp because it doesn't
|
||||||
|
// apply. XP per AA is normalized such that there are X white con kills
|
||||||
|
// per AA.
|
||||||
|
|
||||||
|
uint32 whiteConKillsPerAA = RuleI(AA, NormalizedAANumberOfWhiteConPerAA);
|
||||||
|
uint32 xpPerAA = RuleI(AA, ExpPerPoint);
|
||||||
|
|
||||||
|
float colorModifier = GetConLevelModifierPercent(conlevel);
|
||||||
|
float percentToAAXp = (float)m_epp.perAA / 100;
|
||||||
|
|
||||||
|
// Normalize the amount of AA XP we earned for this kill.
|
||||||
|
add_aaxp = percentToAAXp * (xpPerAA / (whiteConKillsPerAA / colorModifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::CalculateStandardAAExp(uint32 &add_aaxp, uint8 conlevel, bool resexp)
|
||||||
|
{
|
||||||
|
if (!resexp)
|
||||||
|
{
|
||||||
|
//if XP scaling is based on the con of a monster, do that now.
|
||||||
|
if (RuleB(Character, UseXPConScaling))
|
||||||
|
{
|
||||||
|
if (conlevel != 0xFF && !resexp)
|
||||||
|
{
|
||||||
|
add_aaxp *= GetConLevelModifierPercent(conlevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} //end !resexp
|
||||||
|
|
||||||
|
float aatotalmod = 1.0;
|
||||||
|
if (zone->newzone_data.zone_exp_multiplier >= 0) {
|
||||||
|
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shouldn't race not affect AA XP?
|
||||||
|
if (RuleB(Character, UseRaceClassExpBonuses))
|
||||||
|
{
|
||||||
|
if (GetBaseRace() == HALFLING) {
|
||||||
|
aatotalmod *= 1.05;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
|
||||||
|
aatotalmod *= 1.05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// why wasn't this here? Where should it be?
|
||||||
|
if (zone->IsHotzone())
|
||||||
|
{
|
||||||
|
aatotalmod += RuleR(Zone, HotZoneBonus);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||||
|
if (zone->level_exp_mod[GetLevel()].ExpMod) {
|
||||||
|
add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add_aaxp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::CalculateLeadershipExp(uint32 &add_exp, uint8 conlevel)
|
||||||
|
{
|
||||||
|
if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED))
|
||||||
|
{
|
||||||
|
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f);
|
||||||
|
|
||||||
|
if (GetGroup())
|
||||||
|
{
|
||||||
|
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
|
||||||
|
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0)
|
||||||
|
{
|
||||||
|
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
||||||
|
Client *mentoree = GetGroup()->GetMentoree();
|
||||||
|
if (GetGroup()->GetMentorPercent() && mentoree &&
|
||||||
|
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel()))
|
||||||
|
{
|
||||||
|
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
|
||||||
|
exp -= mentor_exp;
|
||||||
|
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
|
||||||
|
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||||
|
}
|
||||||
|
if (exp > 0)
|
||||||
|
{
|
||||||
|
// possible if you mentor 100% to the other client
|
||||||
|
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
|
||||||
|
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Raid *raid = GetRaid();
|
||||||
|
// Raid leaders CAN NOT gain group AA XP, other group leaders can though!
|
||||||
|
if (raid->IsLeader(this))
|
||||||
|
{
|
||||||
|
if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel())
|
||||||
|
&& RuleI(Character, KillsPerRaidLeadershipAA) > 0)
|
||||||
|
{
|
||||||
|
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
|
||||||
|
Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
|
||||||
|
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0)
|
||||||
|
{
|
||||||
|
uint32 group_id = raid->GetGroup(this);
|
||||||
|
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
||||||
|
Client *mentoree = raid->GetMentoree(group_id);
|
||||||
|
if (raid->GetMentorPercent(group_id) && mentoree &&
|
||||||
|
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel()))
|
||||||
|
{
|
||||||
|
uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f);
|
||||||
|
exp -= mentor_exp;
|
||||||
|
mentoree->AddLeadershipEXP(mentor_exp, 0);
|
||||||
|
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||||
|
}
|
||||||
|
if (exp > 0)
|
||||||
|
{
|
||||||
|
AddLeadershipEXP(exp, 0);
|
||||||
|
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::CalculateExp(uint32 in_add_exp, uint32 &add_exp, uint32 &add_aaxp, uint8 conlevel, bool resexp)
|
||||||
|
{
|
||||||
|
add_exp = in_add_exp;
|
||||||
|
|
||||||
|
if (!resexp && (XPRate != 0))
|
||||||
|
{
|
||||||
|
add_exp = static_cast<uint32>(in_add_exp * (static_cast<float>(XPRate) / 100.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure it was initialized.
|
||||||
|
add_aaxp = 0;
|
||||||
|
|
||||||
|
if (!resexp)
|
||||||
|
{
|
||||||
//figure out how much of this goes to AAs
|
//figure out how much of this goes to AAs
|
||||||
add_aaxp = add_exp * m_epp.perAA / 100;
|
add_aaxp = add_exp * m_epp.perAA / 100;
|
||||||
|
|
||||||
//take that amount away from regular exp
|
//take that amount away from regular exp
|
||||||
add_exp -= add_aaxp;
|
add_exp -= add_aaxp;
|
||||||
|
|
||||||
float totalmod = 1.0;
|
float totalmod = 1.0;
|
||||||
float zemmod = 1.0;
|
float zemmod = 1.0;
|
||||||
|
|
||||||
//get modifiers
|
//get modifiers
|
||||||
if(RuleR(Character, ExpMultiplier) >= 0){
|
if (RuleR(Character, ExpMultiplier) >= 0) {
|
||||||
totalmod *= RuleR(Character, ExpMultiplier);
|
totalmod *= RuleR(Character, ExpMultiplier);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
//add the zone exp modifier.
|
||||||
|
if (zone->newzone_data.zone_exp_multiplier >= 0) {
|
||||||
zemmod *= zone->newzone_data.zone_exp_multiplier;
|
zemmod *= zone->newzone_data.zone_exp_multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
if (RuleB(Character, UseRaceClassExpBonuses))
|
||||||
{
|
{
|
||||||
if(GetBaseRace() == HALFLING){
|
if (GetBaseRace() == HALFLING) {
|
||||||
totalmod *= 1.05;
|
totalmod *= 1.05;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
if (GetClass() == ROGUE || GetClass() == WARRIOR) {
|
||||||
totalmod *= 1.05;
|
totalmod *= 1.05;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(zone->IsHotzone())
|
//add hotzone modifier if one has been set.
|
||||||
|
if (zone->IsHotzone())
|
||||||
{
|
{
|
||||||
totalmod += RuleR(Zone, HotZoneBonus);
|
totalmod += RuleR(Zone, HotZoneBonus);
|
||||||
}
|
}
|
||||||
|
|
||||||
add_exp = uint32(float(add_exp) * totalmod * zemmod);
|
add_exp = uint32(float(add_exp) * totalmod * zemmod);
|
||||||
|
|
||||||
if(RuleB(Character,UseXPConScaling))
|
//if XP scaling is based on the con of a monster, do that now.
|
||||||
|
if (RuleB(Character, UseXPConScaling))
|
||||||
{
|
{
|
||||||
if (conlevel != 0xFF && !resexp) {
|
if (conlevel != 0xFF && !resexp)
|
||||||
switch (conlevel)
|
|
||||||
{
|
{
|
||||||
case CON_GRAY:
|
add_exp = add_exp * GetConLevelModifierPercent(conlevel);
|
||||||
add_exp = 0;
|
|
||||||
add_aaxp = 0;
|
|
||||||
return;
|
|
||||||
case CON_GREEN:
|
|
||||||
add_exp = add_exp * RuleI(Character, GreenModifier) / 100;
|
|
||||||
add_aaxp = add_aaxp * RuleI(Character, GreenModifier) / 100;
|
|
||||||
break;
|
|
||||||
case CON_LIGHTBLUE:
|
|
||||||
add_exp = add_exp * RuleI(Character, LightBlueModifier)/100;
|
|
||||||
add_aaxp = add_aaxp * RuleI(Character, LightBlueModifier)/100;
|
|
||||||
break;
|
|
||||||
case CON_BLUE:
|
|
||||||
add_exp = add_exp * RuleI(Character, BlueModifier)/100;
|
|
||||||
add_aaxp = add_aaxp * RuleI(Character, BlueModifier)/100;
|
|
||||||
break;
|
|
||||||
case CON_WHITE:
|
|
||||||
add_exp = add_exp * RuleI(Character, WhiteModifier)/100;
|
|
||||||
add_aaxp = add_aaxp * RuleI(Character, WhiteModifier)/100;
|
|
||||||
break;
|
|
||||||
case CON_YELLOW:
|
|
||||||
add_exp = add_exp * RuleI(Character, YellowModifier)/100;
|
|
||||||
add_aaxp = add_aaxp * RuleI(Character, YellowModifier)/100;
|
|
||||||
break;
|
|
||||||
case CON_RED:
|
|
||||||
add_exp = add_exp * RuleI(Character, RedModifier)/100;
|
|
||||||
add_aaxp = add_aaxp * RuleI(Character, RedModifier)/100;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsLeadershipEXPOn() && (conlevel == CON_BLUE || conlevel == CON_WHITE || conlevel == CON_YELLOW || conlevel == CON_RED)) {
|
// Calculate any changes to leadership experience.
|
||||||
add_exp = static_cast<uint32>(static_cast<float>(add_exp) * 0.8f);
|
CalculateLeadershipExp(add_exp, conlevel);
|
||||||
|
|
||||||
if (GetGroup()) {
|
|
||||||
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
|
|
||||||
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0) {
|
|
||||||
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
|
||||||
Client *mentoree = GetGroup()->GetMentoree();
|
|
||||||
if (GetGroup()->GetMentorPercent() && mentoree &&
|
|
||||||
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
|
|
||||||
uint32 mentor_exp = exp * (GetGroup()->GetMentorPercent() / 100.0f);
|
|
||||||
exp -= mentor_exp;
|
|
||||||
mentoree->AddLeadershipEXP(mentor_exp, 0); // ends up rounded down
|
|
||||||
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
|
||||||
}
|
|
||||||
if (exp > 0) { // possible if you mentor 100% to the other client
|
|
||||||
AddLeadershipEXP(exp, 0); // ends up rounded up if mentored, no idea how live actually does it
|
|
||||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Raid *raid = GetRaid();
|
|
||||||
// Raid leaders CAN NOT gain group AA XP, other group leaders can though!
|
|
||||||
if (raid->IsLeader(this)) {
|
|
||||||
if (m_pp.raid_leadership_points < MaxBankedRaidLeadershipPoints(GetLevel())
|
|
||||||
&& RuleI(Character, KillsPerRaidLeadershipAA) > 0) {
|
|
||||||
AddLeadershipEXP(0, RAID_EXP_PER_POINT / RuleI(Character, KillsPerRaidLeadershipAA));
|
|
||||||
Message_StringID(MT_Leadership, GAIN_RAID_LEADERSHIP_EXP);
|
|
||||||
} else {
|
|
||||||
Message_StringID(MT_Leadership, MAX_RAID_LEADERSHIP_POINTS);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (m_pp.group_leadership_points < MaxBankedGroupLeadershipPoints(GetLevel())
|
|
||||||
&& RuleI(Character, KillsPerGroupLeadershipAA) > 0) {
|
|
||||||
uint32 group_id = raid->GetGroup(this);
|
|
||||||
uint32 exp = GROUP_EXP_PER_POINT / RuleI(Character, KillsPerGroupLeadershipAA);
|
|
||||||
Client *mentoree = raid->GetMentoree(group_id);
|
|
||||||
if (raid->GetMentorPercent(group_id) && mentoree &&
|
|
||||||
mentoree->GetGroupPoints() < MaxBankedGroupLeadershipPoints(mentoree->GetLevel())) {
|
|
||||||
uint32 mentor_exp = exp * (raid->GetMentorPercent(group_id) / 100.0f);
|
|
||||||
exp -= mentor_exp;
|
|
||||||
mentoree->AddLeadershipEXP(mentor_exp, 0);
|
|
||||||
mentoree->Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
|
||||||
}
|
|
||||||
if (exp > 0) {
|
|
||||||
AddLeadershipEXP(exp, 0);
|
|
||||||
Message_StringID(MT_Leadership, GAIN_GROUP_LEADERSHIP_EXP);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Message_StringID(MT_Leadership, MAX_GROUP_LEADERSHIP_POINTS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
} //end !resexp
|
} //end !resexp
|
||||||
|
|
||||||
float aatotalmod = 1.0;
|
if (RuleB(Zone, LevelBasedEXPMods)) {
|
||||||
if(zone->newzone_data.zone_exp_multiplier >= 0){
|
if (zone->level_exp_mod[GetLevel()].ExpMod) {
|
||||||
aatotalmod *= zone->newzone_data.zone_exp_multiplier;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shouldn't race not affect AA XP?
|
|
||||||
if(RuleB(Character,UseRaceClassExpBonuses))
|
|
||||||
{
|
|
||||||
if(GetBaseRace() == HALFLING){
|
|
||||||
aatotalmod *= 1.05;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(GetClass() == ROGUE || GetClass() == WARRIOR){
|
|
||||||
aatotalmod *= 1.05;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// why wasn't this here? Where should it be?
|
|
||||||
if(zone->IsHotzone())
|
|
||||||
{
|
|
||||||
aatotalmod += RuleR(Zone, HotZoneBonus);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(RuleB(Zone, LevelBasedEXPMods)){
|
|
||||||
if(zone->level_exp_mod[GetLevel()].ExpMod){
|
|
||||||
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
add_exp *= zone->level_exp_mod[GetLevel()].ExpMod;
|
||||||
add_aaxp *= zone->level_exp_mod[GetLevel()].AAExpMod;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 exp = GetEXP() + add_exp;
|
add_exp = GetEXP() + add_exp;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 aaexp = (uint32)(RuleR(Character, AAExpMultiplier) * add_aaxp * aatotalmod);
|
void Client::AddEXP(uint32 in_add_exp, uint8 conlevel, bool resexp) {
|
||||||
|
|
||||||
|
this->EVENT_ITEM_ScriptStopReturn();
|
||||||
|
|
||||||
|
uint32 exp = 0;
|
||||||
|
uint32 aaexp = 0;
|
||||||
|
|
||||||
|
if (m_epp.perAA<0 || m_epp.perAA>100)
|
||||||
|
m_epp.perAA=0; // stop exploit with sanity check
|
||||||
|
|
||||||
|
// Calculate regular XP
|
||||||
|
CalculateExp(in_add_exp, exp, aaexp, conlevel, resexp);
|
||||||
|
|
||||||
|
// Calculate regular AA XP
|
||||||
|
if (!RuleB(AA, NormalizedAAEnabled))
|
||||||
|
{
|
||||||
|
CalculateStandardAAExp(aaexp, conlevel, resexp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CalculateNormalizedAAExp(aaexp, conlevel, resexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Are we also doing linear AA acceleration?
|
||||||
|
if (RuleB(AA, ModernAAScalingEnabled) && aaexp > 0)
|
||||||
|
{
|
||||||
|
aaexp = ScaleAAXPBasedOnCurrentAATotal(GetAAPoints(), aaexp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current AA XP total
|
||||||
uint32 had_aaexp = GetAAXP();
|
uint32 had_aaexp = GetAAXP();
|
||||||
aaexp += had_aaexp;
|
|
||||||
if(aaexp < had_aaexp)
|
|
||||||
aaexp = had_aaexp; //watch for wrap
|
|
||||||
|
|
||||||
|
// Add it to the XP we just earned.
|
||||||
|
aaexp += had_aaexp;
|
||||||
|
|
||||||
|
// Make sure our new total (existing + just earned) isn't lower than the
|
||||||
|
// existing total. If it is, we overflowed the bounds of uint32 and wrapped.
|
||||||
|
// Reset to the existing total.
|
||||||
|
if (aaexp < had_aaexp)
|
||||||
|
{
|
||||||
|
aaexp = had_aaexp; //watch for wrap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now update our character's normal and AA xp
|
||||||
SetEXP(exp, aaexp, resexp);
|
SetEXP(exp, aaexp, resexp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -336,6 +336,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
|
|||||||
eslot = EQEmu::textures::weaponPrimary;
|
eslot = EQEmu::textures::weaponPrimary;
|
||||||
if (item2->Damage > 0) {
|
if (item2->Damage > 0) {
|
||||||
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
SendAddPlayerState(PlayerState::PrimaryWeaponEquipped);
|
||||||
|
if (!RuleB(Combat, ClassicNPCBackstab))
|
||||||
SetFacestab(true);
|
SetFacestab(true);
|
||||||
}
|
}
|
||||||
if (item2->IsType2HWeapon())
|
if (item2->IsType2HWeapon())
|
||||||
|
|||||||
@ -127,7 +127,7 @@ bool NPC::AICastSpell(Mob* tar, uint8 iChance, uint32 iSpellTypes) {
|
|||||||
}
|
}
|
||||||
case SpellType_Root: {
|
case SpellType_Root: {
|
||||||
Mob *rootee = GetHateRandom();
|
Mob *rootee = GetHateRandom();
|
||||||
if (rootee && !rootee->IsRooted() && zone->random.Roll(50)
|
if (rootee && !rootee->IsRooted() && !rootee->IsFeared() && zone->random.Roll(50)
|
||||||
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
&& rootee->DontRootMeBefore() < Timer::GetCurrentTime()
|
||||||
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
&& rootee->CanBuffStack(AIspells[i].spellid, GetLevel(), true) >= 0
|
||||||
) {
|
) {
|
||||||
@ -1391,19 +1391,33 @@ void Mob::AI_Process() {
|
|||||||
//if(owner->IsClient())
|
//if(owner->IsClient())
|
||||||
// printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
|
// printf("Pet start pos: (%f, %f, %f)\n", GetX(), GetY(), GetZ());
|
||||||
|
|
||||||
float dist = DistanceSquared(m_Position, owner->GetPosition());
|
glm::vec4 ownerPos = owner->GetPosition();
|
||||||
if (dist >= 400)
|
float dist = DistanceSquared(m_Position, ownerPos);
|
||||||
|
float distz = ownerPos.z - m_Position.z;
|
||||||
|
|
||||||
|
if (dist >= 400 || distz > 100)
|
||||||
{
|
{
|
||||||
int speed = GetWalkspeed();
|
int speed = GetWalkspeed();
|
||||||
if (dist >= 5625)
|
if (dist >= 5625)
|
||||||
speed = GetRunspeed();
|
speed = GetRunspeed();
|
||||||
|
|
||||||
CalculateNewPosition2(owner->GetX(), owner->GetY(), owner->GetZ(), speed);
|
if (distz > 100)
|
||||||
|
{
|
||||||
|
m_Position = ownerPos;
|
||||||
|
SendPositionUpdate();
|
||||||
|
moved = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CalculateNewPosition2(owner->GetX(),
|
||||||
|
owner->GetY(), owner->GetZ(), speed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(moved)
|
if(moved)
|
||||||
{
|
{
|
||||||
|
this->FixZ();
|
||||||
SetCurrentSpeed(0);
|
SetCurrentSpeed(0);
|
||||||
moved = false;
|
moved = false;
|
||||||
}
|
}
|
||||||
@ -1748,6 +1762,12 @@ void Mob::AI_Event_Engaged(Mob* attacker, bool iYellForHelp) {
|
|||||||
|
|
||||||
SetAppearance(eaStanding);
|
SetAppearance(eaStanding);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Kick off auto cast timer
|
||||||
|
*/
|
||||||
|
if (this->IsNPC())
|
||||||
|
this->CastToNPC()->AIautocastspell_timer->Start(300, false);
|
||||||
|
|
||||||
if (iYellForHelp) {
|
if (iYellForHelp) {
|
||||||
if(IsPet()) {
|
if(IsPet()) {
|
||||||
GetOwner()->AI_Event_Engaged(attacker, iYellForHelp);
|
GetOwner()->AI_Event_Engaged(attacker, iYellForHelp);
|
||||||
|
|||||||
@ -420,6 +420,8 @@ public:
|
|||||||
|
|
||||||
bool IgnoreDespawn() { return ignore_despawn; }
|
bool IgnoreDespawn() { return ignore_despawn; }
|
||||||
|
|
||||||
|
std::unique_ptr<Timer> AIautocastspell_timer;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
const NPCType* NPCTypedata;
|
const NPCType* NPCTypedata;
|
||||||
@ -453,7 +455,7 @@ protected:
|
|||||||
|
|
||||||
uint32 npc_spells_id;
|
uint32 npc_spells_id;
|
||||||
uint8 casting_spell_AIindex;
|
uint8 casting_spell_AIindex;
|
||||||
std::unique_ptr<Timer> AIautocastspell_timer;
|
|
||||||
uint32* pDontCastBefore_casting_spell;
|
uint32* pDontCastBefore_casting_spell;
|
||||||
std::vector<AISpells_Struct> AIspells;
|
std::vector<AISpells_Struct> AIspells;
|
||||||
bool HasAISpell;
|
bool HasAISpell;
|
||||||
|
|||||||
@ -655,12 +655,17 @@ void NPC::SetPetState(SpellBuff_Struct *pet_buffs, uint32 *items) {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const EQEmu::ItemData* item2 = database.GetItem(items[i]);
|
const EQEmu::ItemData* item2 = database.GetItem(items[i]);
|
||||||
if (item2 && item2->NoDrop != 0) {
|
|
||||||
//dont bother saving item charges for now, NPCs never use them
|
if (item2) {
|
||||||
//and nobody should be able to get them off the corpse..?
|
bool noDrop=(item2->NoDrop == 0); // Field is reverse logic
|
||||||
|
bool petCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) &&
|
||||||
|
_CLIENTPET(this) && GetPetType() <= petOther);
|
||||||
|
|
||||||
|
if (!noDrop || petCanHaveNoDrop) {
|
||||||
AddLootDrop(item2, &itemlist, 0, 1, 255, true, true);
|
AddLootDrop(item2, &itemlist, 0, 1, 255, true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the equipmentset from the DB. Might be worthwhile to load these into
|
// Load the equipmentset from the DB. Might be worthwhile to load these into
|
||||||
|
|||||||
@ -1796,8 +1796,12 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
|
|||||||
Message_StringID(4, CORPSE_CANT_SENSE);
|
Message_StringID(4, CORPSE_CANT_SENSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (caster)
|
else if (caster) {
|
||||||
caster->Message_StringID(MT_SpellFailure, SPELL_LEVEL_REQ);
|
char level[4];
|
||||||
|
ConvertArray(effect_value, level);
|
||||||
|
caster->Message_StringID(MT_SpellFailure,
|
||||||
|
SPELL_LEVEL_REQ, level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Message_StringID(4, TARGET_NOT_FOUND);
|
Message_StringID(4, TARGET_NOT_FOUND);
|
||||||
|
|||||||
@ -523,7 +523,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
else
|
else
|
||||||
qs_audit->char1_count += detail->charges;
|
qs_audit->char1_count += detail->charges;
|
||||||
|
|
||||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
|
||||||
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
||||||
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
||||||
|
|
||||||
@ -743,7 +742,6 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
qs_audit->char1_count += detail->charges;
|
qs_audit->char1_count += detail->charges;
|
||||||
|
|
||||||
// 'step 3' should never really see containers..but, just in case...
|
// 'step 3' should never really see containers..but, just in case...
|
||||||
//for (uint8 sub_slot = SUB_BEGIN; ((sub_slot < inst->GetItem()->BagSlots) && (sub_slot < EmuConstants::ITEM_CONTAINER_SIZE)); ++sub_slot) {
|
|
||||||
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
for (uint8 sub_slot = EQEmu::inventory::containerBegin; (sub_slot < EQEmu::inventory::ContainerCount); ++sub_slot) { // this is to catch ALL items
|
||||||
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
const EQEmu::ItemInstance* bag_inst = inst->GetItem(sub_slot);
|
||||||
|
|
||||||
@ -888,8 +886,12 @@ void Client::FinishTrade(Mob* tradingWith, bool finalizer, void* event_entry, st
|
|||||||
|
|
||||||
const EQEmu::ItemData* item = inst->GetItem();
|
const EQEmu::ItemData* item = inst->GetItem();
|
||||||
if(item && quest_npc == false) {
|
if(item && quest_npc == false) {
|
||||||
|
bool isPetAndCanHaveNoDrop = (RuleB(Pets, CanTakeNoDrop) &&
|
||||||
|
_CLIENTPET(tradingWith) &&
|
||||||
|
tradingWith->GetPetType()<=petOther);
|
||||||
// if it was not a NO DROP or Attuned item (or if a GM is trading), let the NPC have it
|
// if it was not a NO DROP or Attuned item (or if a GM is trading), let the NPC have it
|
||||||
if(GetGM() || (item->NoDrop != 0 && inst->IsAttuned() == false)) {
|
if(GetGM() || (inst->IsAttuned() == false &&
|
||||||
|
(item->NoDrop != 0 || isPetAndCanHaveNoDrop))) {
|
||||||
// pets need to look inside bags and try to equip items found there
|
// pets need to look inside bags and try to equip items found there
|
||||||
if (item->IsClassBag() && item->BagSlots > 0) {
|
if (item->IsClassBag() && item->BagSlots > 0) {
|
||||||
for (int16 bslot = EQEmu::inventory::containerBegin; bslot < item->BagSlots; bslot++) {
|
for (int16 bslot = EQEmu::inventory::containerBegin; bslot < item->BagSlots; bslot++) {
|
||||||
|
|||||||
@ -884,7 +884,7 @@ void Mob::FixZ(int32 z_find_offset /*= 5*/)
|
|||||||
glm::vec3 current_loc(m_Position);
|
glm::vec3 current_loc(m_Position);
|
||||||
float new_z = GetFixedZ(current_loc, z_find_offset);
|
float new_z = GetFixedZ(current_loc, z_find_offset);
|
||||||
|
|
||||||
if (new_z != m_Position.z)
|
if (!IsClient() && new_z != m_Position.z)
|
||||||
{
|
{
|
||||||
if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
|
if ((new_z > -2000) && new_z != BEST_Z_INVALID) {
|
||||||
if (RuleB(Map, MobZVisualDebug))
|
if (RuleB(Map, MobZVisualDebug))
|
||||||
|
|||||||
@ -338,6 +338,7 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p)
|
|||||||
if (ztz->response <= 0) {
|
if (ztz->response <= 0) {
|
||||||
zc2->success = ZONE_ERROR_NOTREADY;
|
zc2->success = ZONE_ERROR_NOTREADY;
|
||||||
entity->CastToMob()->SetZone(ztz->current_zone_id, ztz->current_instance_id);
|
entity->CastToMob()->SetZone(ztz->current_zone_id, ztz->current_instance_id);
|
||||||
|
entity->CastToClient()->SetZoning(false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
entity->CastToClient()->UpdateWho(1);
|
entity->CastToClient()->UpdateWho(1);
|
||||||
|
|||||||
@ -1515,7 +1515,7 @@ void Zone::Repop(uint32 delay) {
|
|||||||
void Zone::GetTimeSync()
|
void Zone::GetTimeSync()
|
||||||
{
|
{
|
||||||
if (worldserver.Connected() && !zone_has_current_time) {
|
if (worldserver.Connected() && !zone_has_current_time) {
|
||||||
auto pack = new ServerPacket(ServerOP_GetWorldTime, 0);
|
auto pack = new ServerPacket(ServerOP_GetWorldTime, 1);
|
||||||
worldserver.SendPacket(pack);
|
worldserver.SendPacket(pack);
|
||||||
safe_delete(pack);
|
safe_delete(pack);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class ZoneConfig : public EQEmuConfig {
|
|||||||
_zone_config=new ZoneConfig;
|
_zone_config=new ZoneConfig;
|
||||||
_config=_zone_config;
|
_config=_zone_config;
|
||||||
|
|
||||||
return _config->ParseFile(EQEmuConfig::ConfigFile.c_str(),"server");
|
return _config->parseFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accessors for the static private object
|
// Accessors for the static private object
|
||||||
|
|||||||
@ -42,7 +42,7 @@ void Client::Handle_OP_ZoneChange(const EQApplicationPacket *app) {
|
|||||||
Bot::ProcessClientZoneChange(this);
|
Bot::ProcessClientZoneChange(this);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
zoning = true;
|
bZoning = true;
|
||||||
if (app->size != sizeof(ZoneChange_Struct)) {
|
if (app->size != sizeof(ZoneChange_Struct)) {
|
||||||
Log(Logs::General, Logs::None, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct));
|
Log(Logs::General, Logs::None, "Wrong size: OP_ZoneChange, size=%d, expected %d", app->size, sizeof(ZoneChange_Struct));
|
||||||
return;
|
return;
|
||||||
@ -308,6 +308,8 @@ void Client::SendZoneCancel(ZoneChange_Struct *zc) {
|
|||||||
|
|
||||||
//reset to unsolicited.
|
//reset to unsolicited.
|
||||||
zone_mode = ZoneUnsolicited;
|
zone_mode = ZoneUnsolicited;
|
||||||
|
// reset since we're not zoning anymore
|
||||||
|
bZoning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::SendZoneError(ZoneChange_Struct *zc, int8 err)
|
void Client::SendZoneError(ZoneChange_Struct *zc, int8 err)
|
||||||
@ -327,6 +329,8 @@ void Client::SendZoneError(ZoneChange_Struct *zc, int8 err)
|
|||||||
|
|
||||||
//reset to unsolicited.
|
//reset to unsolicited.
|
||||||
zone_mode = ZoneUnsolicited;
|
zone_mode = ZoneUnsolicited;
|
||||||
|
// reset since we're not zoning anymore
|
||||||
|
bZoning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instance_id, float dest_x, float dest_y, float dest_z, float dest_h, int8 ignore_r) {
|
void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instance_id, float dest_x, float dest_y, float dest_z, float dest_h, int8 ignore_r) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user