Merge git://github.com/EQEmu/Server into Development

This commit is contained in:
KayenEQ 2014-11-18 04:46:14 -05:00
commit 1e13d43b71
33 changed files with 3686 additions and 2800 deletions

View File

@ -1,5 +1,69 @@
EQEMu Changelog (Started on Sept 24, 2003 15:50)
-------------------------------------------------------
== 11/18/2014 ==
Trevius: Mercenaries can now zone once again.
== 11/17/2014 ==
demonstar55: Correct OP_AugmentInfo reply. This fixes RoF display issue with Adventurer's Stone. Still issues with UF/SoF/SoD though.
== 11/16/2014 ==
demonstar55: fix size issue with ControlBoat_Struct and exploit fix in OP_BoardBoat
Akkadius: Implemented Automatic Database update and versioning system
Akkadius: Created database revision define, this is located in version.h in common #define CURRENT_BINARY_DATABASE_VERSION 9057
- This revision define will need to be incremented each time a database update is made
- Along with a revision define increment, you will need to update the db_update manifest located in:
- https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
- An entry needs to be made at the bottom of the manifest, the entry is quite simple
- Example: 9057|2014_11_13_spells_new_updates.sql|SHOW COLUMNS FROM `spells_new` LIKE 'disallow_sit'|empty|
- This latest example is checking to see if the spells_new table contains the column 'disallow_sit', if its empty, the update needs to be ran
- More examples of match types below:
# Example: Version|Filename.sql|Query_to_Check_Condition_For_Needed_Update|match type|text to match
# 0 = Database Version
# 1 = Filename.sql
# 2 = Query_to_Check_Condition_For_Needed_Update
# 3 = Match Type - If condition from match type to Value 4 is true, update will flag for needing to be ran
# contains = If query results contains text from 4th value
# match = If query results matches text from 4th value
# missing = If query result is missing text from 4th value
# empty = If the query results in no results
# not_empty = If the query is not empty
# 4 = Text to match
- The manifest contains all database updates 'Required' to be made to the schema, and it will contain a working backport all the way back to SVN -
currently it is tested and backported through the beginning of our Github repo
- On world bootup or standalone run of db_update.pl, users will be prompted with a simple menu that we will expand upon later:
============================================================
EQEmu: Automatic Database Upgrade Check
============================================================
Operating System is: MSWin32
(Windows) MySQL is in system path
Path = C:\Program Files\MariaDB 10.0\bin/mysql
============================================================
Binary Database Version: (9057)
Local Database Version: (9057)
Database up to Date: Continuing World Bootup...
============================================================
Retrieving latest database manifest...
URL: https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
Saved: db_update/db_update_manifest.txt
Database Management Menu (Please Select):
1) Backup Database - (Saves to Backups folder)
Ideal to perform before performing updates
2) Backup Database Compressed - (Saves to Backups folder)
Ideal to perform before performing updates
3) Check for pending Database updates
Stages updates for automatic upgrade...
0) Exit
Akkadius: Created db_update.pl, placed in utils/scripts folder, used for the automatic database update routine (Linux/Windows)
- db_update.pl script created db_version table if not created, if old one is present it will remove it
Akkadius: Created db_dumper.pl, placed in utils/scripts folder, used for the automatic database update routine backups and standalone backups (Linux/Windows)
Akkadius: World will now check the db_update.pl script on bootup, if the db_update.pl script is not present, it will fetch it remotely before running -
when db_update.pl is done running, world will continue with bootup
== 11/15/2014 ==
Uleat(Natedog): A better fix for OP_ShopPlayerBuy - doesn't cause the issues that I introduced
Kayen: Implemented NPC Special Ability 41 'Allow To Tank', gives NPC opportunity to take aggro over a client in melee range.

View File

@ -2084,6 +2084,19 @@ bool Database::CheckDatabaseConversions() {
#endif
/* Fetch Automatic Database Upgrade Script */
if (!std::ifstream("db_update.pl")){
std::cout << "Pulling down automatic database upgrade script...\n" << 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/db_update.pl'); if ($response->is_success){ open(FILE, '> db_update.pl'); print FILE $response->decoded_content; close(FILE); }\"");
#else
system("wget -O db_update.pl https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/db_update.pl");
#endif
}
/* Run Automatic Database Upgrade Script */
system("perl db_update.pl ran_from_world");
return true;
}

View File

@ -4383,14 +4383,14 @@ typedef struct {
struct ControlBoat_Struct {
/*000*/ uint32 boatId; // entitylist id of the boat
/*004*/ bool TakeControl; // 01 if taking control, 00 if releasing it
/*007*/ // no idea what these last three bytes represent
/*007*/ char unknown[3]; // no idea what these last three bytes represent
};
struct AugmentInfo_Struct
{
/*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[67]; // total packet length 72, all the rest were always 00
/*004*/ uint32 window; // window to display the information in
/*008*/ char augment_info[64]; // the reply has the text here
/*072*/
};

View File

@ -235,6 +235,18 @@ namespace RoF
FINISH_ENCODE();
}
ENCODE(OP_AugmentInfo)
{
ENCODE_LENGTH_EXACT(AugmentInfo_Struct);
SETUP_DIRECT_ENCODE(AugmentInfo_Struct, structs::AugmentInfo_Struct);
OUT(itemid);
OUT(window);
strn0cpy(eq->augment_info, emu->augment_info, 64);
FINISH_ENCODE();
}
ENCODE(OP_Barter)
{
EQApplicationPacket *in = *p;

View File

@ -5,6 +5,7 @@ E(OP_AltCurrency)
E(OP_AltCurrencySell)
E(OP_Animation)
E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_BeginCast)

View File

@ -4692,9 +4692,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct
{
/*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/
/*004*/ uint32 window; // window to display the information in
/*008*/ char augment_info[64]; // total packet length 76, all the rest were always 00
/*072*/ uint32 unknown072;
};
struct VeteranRewardItem

View File

@ -174,6 +174,18 @@ namespace SoD
FINISH_ENCODE();
}
ENCODE(OP_AugmentInfo)
{
ENCODE_LENGTH_EXACT(AugmentInfo_Struct);
SETUP_DIRECT_ENCODE(AugmentInfo_Struct, structs::AugmentInfo_Struct);
OUT(itemid);
OUT(window);
strn0cpy(eq->augment_info, emu->augment_info, 64);
FINISH_ENCODE();
}
ENCODE(OP_Barter)
{
EQApplicationPacket *in = *p;

View File

@ -3,6 +3,7 @@ E(OP_Action)
E(OP_AdventureMerchantSell)
E(OP_AltCurrencySell)
E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_Buff)

View File

@ -4173,9 +4173,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct
{
/*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/
/*004*/ uint32 window; // window to display the information in
/*008*/ char augment_info[64]; // total packet length 76, all the rest were always 00
/*072*/ uint32 unknown072;
};
struct VeteranRewardItem

View File

@ -174,6 +174,18 @@ namespace SoF
FINISH_ENCODE();
}
ENCODE(OP_AugmentInfo)
{
ENCODE_LENGTH_EXACT(AugmentInfo_Struct);
SETUP_DIRECT_ENCODE(AugmentInfo_Struct, structs::AugmentInfo_Struct);
OUT(itemid);
OUT(window);
strn0cpy(eq->augment_info, emu->augment_info, 64);
FINISH_ENCODE();
}
ENCODE(OP_BazaarSearch)
{
if (((*p)->size == sizeof(BazaarReturnDone_Struct)) || ((*p)->size == sizeof(BazaarWelcome_Struct))) {

View File

@ -3,6 +3,7 @@ E(OP_Action)
E(OP_AdventureMerchantSell)
E(OP_AltCurrencySell)
E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_BazaarSearch)
E(OP_BecomeTrader)
E(OP_Buff)

View File

@ -4027,9 +4027,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct
{
/*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/
/*004*/ uint32 window; // window to display the information in
/*008*/ char augment_info[64]; // total packet length 76, all the rest were always 00
/*072*/ uint32 unknown072;
};
struct VeteranRewardItem

View File

@ -226,6 +226,18 @@ namespace Underfoot
FINISH_ENCODE();
}
ENCODE(OP_AugmentInfo)
{
ENCODE_LENGTH_EXACT(AugmentInfo_Struct);
SETUP_DIRECT_ENCODE(AugmentInfo_Struct, structs::AugmentInfo_Struct);
OUT(itemid);
OUT(window);
strn0cpy(eq->augment_info, emu->augment_info, 64);
FINISH_ENCODE();
}
ENCODE(OP_Barter)
{
EQApplicationPacket *in = *p;

View File

@ -4,6 +4,7 @@ E(OP_AdventureMerchantSell)
E(OP_AltCurrency)
E(OP_AltCurrencySell)
E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_Barter)
E(OP_BazaarSearch)
E(OP_Buff)

View File

@ -4272,9 +4272,9 @@ struct ItemQuaternaryBodyStruct
struct AugmentInfo_Struct
{
/*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint8 window; // window to display the information in
/*005*/ uint8 unknown005[71]; // total packet length 76, all the rest were always 00
/*076*/
/*004*/ uint32 window; // window to display the information in
/*008*/ char augment_info[64]; // total packet length 76, all the rest were always 00
/*072*/ uint32 unknown072;
};
struct VeteranRewardItem

View File

@ -23,6 +23,14 @@
#define EQEMU_PROTOCOL_VERSION "0.3.10"
#define CURRENT_VERSION "1.0.0"
/*
Everytime a Database SQL is added to Github,
increment CURRENT_BINARY_DATABASE_VERSION number and make sure you update the manifest
Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9057
#define COMPILE_DATE __DATE__
#define COMPILE_TIME __TIME__
#ifndef WIN32

214
utils/scripts/db_dumper.pl Normal file
View File

@ -0,0 +1,214 @@
#!/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\n";
print "#::: Help :::#\n";
print "######################################################\n\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 ' Example: perl DB_Dumper.pl Loc="E:\Backups"' . "\n\n";
print "######################################################\n";
exit;
}
#::: CONFIG VARIABLES - Parsed from eqemu_config.xml
my $confile = "eqemu_config.xml"; #default
open(F, "<$confile") or die "Unable to open config: $confile - This must be in your EQEmu Server Folder with your XML config\n";
my $indb = 0;
while(<F>) {
s/\r//g;
if(/<database>/i) { $indb = 1; }
next unless($indb == 1);
if(/<\/database>/i) { $indb = 0; last; }
if(/<host>(.*)<\/host>/i) { $host = $1; }
elsif(/<username>(.*)<\/username>/i) { $user = $1; }
elsif(/<password>(.*)<\/password>/i) { $pass = $1; }
elsif(/<db>(.*)<\/db>/i) { $db = $1; }
}
$Debug = 0;
print "Arguments\n" if $Debug;
$n = 0;
while($ARGV[$n]){
print $n . ': ' . $ARGV[$n] . "\n" if $Debug;
if($ARGV[$n]=~/compress/i){
print "Compression SET\n";
$Compress = 1;
}
if($ARGV[$n]=~/database=/i){
@DB_NAME = split('=', $ARGV[$n]);
print "Database is " . $DB_NAME[1] . "\n";
$db = $DB_NAME[1];
}
if($ARGV[$n]=~/loc=/i){
@B_LOC = split('=', $ARGV[$n]);
print "Backup Directory: " . $B_LOC[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 "Backing up tables: \n\n############################\n" . $t_tables_p . "############################\n\n";
}
$n++;
}
#::: Check for Backup Directory existence, if doesn't exist then create...
if (-d $B_LOC[1]) {
print "Directory currently exists... Adding files to it...\n\n";
}
elsif($B_LOC[1] ne ""){
print "Directory does NOT exist! Creating...\n\n";
mkdir($B_LOC[1]) or die 'Failed to create folder, maybe created the folder manually at "' . $B_LOC[1]. '" ?';
}
else{
print "No save location specified... Saving to folder script is running in...\n";
}
if($B_LOC[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) . '...';
$target_file = '' . $tables_f_l . ' ' . $date . '';
print "Performing table based backup...\n";
#::: Backup Database...
print "Backing up Database " . $db . "... \n\n";
$cmd = 'mysqldump -u' . $user . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' ' . $t_tables . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"';
printcmd($cmd);
system($cmd);
}
else{ #::: Entire DB Backup
$target_file = '' . $db . ' ' . $date . '';
#::: Backup Database...
print "Backing up Database " . $db . "... \n\n";
$cmd = 'mysqldump -u' . $user . ' --max_allowed_packet=512M --password="' . $pass . '" ' . $db . ' > "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql"';
printcmd($cmd);
system($cmd);
}
#::: Get File Size
$fileloc = '' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql';
$filesize = -s $fileloc;
if($filesize < 1000){ print "\n" . 'Error occurred... exiting...' . "\n\n"; exit; }
print "Backup DONE... DB Backup File Size '" . $filesize . "' (" . get_filesize_str($fileloc) . ")\n\n";
#::: WinRar Get, check compression flag
if($Compress == 1){
if($OS eq "Windows"){
if(-d $localdrive . "\\Program Files\\7-Zip"){
print " ::: You have 7-Zip installed as 64 Bit...\n\n";
$S_ZIP = $localdrive . "\\Program Files\\7-Zip";
}
elsif(-d $localdrive . "\\Program Files (x86)\\7-Zip"){
print " ::: You have 7-Zip installed as 32 Bit...\n\n";
$S_ZIP = $localdrive . "\\Program Files (x86)\\7-Zip";
}
elsif(-d $localdrive . "\\Program Files (x86)\\WinRAR"){
print " ::: You have WinRAR installed as 32 Bit...\n\n";
$WinRar = $localdrive . "\\Program Files (x86)\\WinRAR";
}
elsif(-d $localdrive . "\\Program Files\\WinRAR"){
print " ::: You have WinRAR installed as 64 Bit...\n\n";
$WinRar = $localdrive . "\\Program Files\\WinRAR";
}
else{
print "No WinRAR installed... Will not compress...\n";
}
if($S_ZIP ne ""){
print "Compressing Database with 7-ZIP... \n\n";
$cmd = '"' . $S_ZIP . '\\7z" a -t7z -m0=lzma -mx=9 "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.7z" "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
print "\nDeleting RAW .sql Dump... \n\n";
$cmd = 'del "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
$final_file = $target_file . ".7z";
}
elsif($WinRar ne ""){
print "Compressing Database with WinRAR... \n";
$cmd = '"' . $WinRar . '\\rar" a "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.rar" "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
print "\nDeleting RAW .sql Dump... \n\n";
$cmd = 'del "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
$final_file = $target_file . ".rar";
}
}
if($OS eq "Linux"){
print "Compressing Database with Tarball... \n";
$cmd = 'tar -zcvf "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.tar.gz" "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
print "\nDeleting RAW .sql Dump... \n\n";
$cmd = 'rm "' . $B_LOC[1] . '' . $file_app . '' . $target_file . '.sql" ';
printcmd($cmd);
system($cmd);
$final_file = $target_file . ".tar.gz";
}
}
#::: Get Final File Location for display
if($B_LOC[1] ne ""){ $final_loc = $B_LOC[1] . '' . $file_app . ""; }
else{
if($OS eq "Windows"){
$final_loc = `echo %cd%`;
}
elsif($OS eq "Linux"){
$final_loc = `pwd`;
}
}
print "Final file located: " . $final_loc . "" . $final_file . "\n\n";
sub printcmd{
print "--- CMD --- \n" . $_[0] . "\n" . $linesep . "\n\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"); }
}

383
utils/scripts/db_update.pl Normal file
View File

@ -0,0 +1,383 @@
#!/usr/bin/perl
###########################################################
#::: Automatic Database Upgrade Script
#::: Author: Akkadius
#::: Purpose: To upgrade databases with ease and maintain versioning
###########################################################
$perl_version = $^V;
$perl_version =~s/v//g;
print "Perl Version is " . $perl_version . "\n";
if($perl_version > 5.12){ no warnings 'uninitialized'; }
no warnings;
my $confile = "eqemu_config.xml"; #default
open(F, "<$confile") or die "Unable to open config: $confile\n";
my $indb = 0;
while(<F>) {
s/\r//g;
if(/<database>/i) { $indb = 1; }
next unless($indb == 1);
if(/<\/database>/i) { $indb = 0; last; }
if(/<host>(.*)<\/host>/i) { $host = $1; }
elsif(/<username>(.*)<\/username>/i) { $user = $1; }
elsif(/<password>(.*)<\/password>/i) { $pass = $1; }
elsif(/<db>(.*)<\/db>/i) { $db = $1; }
}
print
"============================================================
EQEmu: Automatic Database Upgrade Check
============================================================
";
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($OS eq "Windows"){
$has_mysql_path = `echo %PATH%`;
if($has_mysql_path=~/MySQL|MariaDB/i){
@mysql = split(';', $has_mysql_path);
foreach my $v (@mysql){
if($v=~/MySQL|MariaDB/i){
$path = $v . "/mysql";
last;
}
}
print " (Windows) MySQL is in system path \n";
print " Path = " . $path . "\n";
print "============================================================\n";
}
}
#::: Linux Check
if($OS eq "Linux"){
$path = `which mysql`;
if ($path eq "") {
$path = `which mariadb`;
}
$path =~s/\n//g;
print " (Linux) MySQL is in system path \n";
print " Path = " . $path . "\n";
print "============================================================\n";
}
#::: Path not found, error and exit
if($path eq ""){
print "MySQL path not found, please add the path for automatic database upgrading to continue... \n\n";
print "Exiting...\n";
exit;
}
#::: Create db_update working directory if not created
mkdir('db_update');
#::: Check if db_version table exists...
if(trim(GetMySQLResult("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne ""){
print GetMySQLResult("DROP TABLE db_version");
print "Old db_version table present, dropping...\n\n";
}
if(GetMySQLResult("SHOW TABLES LIKE 'db_version'") eq ""){
print GetMySQLResult("
CREATE TABLE db_version (
version int(11) DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO db_version (version) VALUES ('1000');");
print "Table 'db_version' does not exists.... Creating...\n\n";
}
if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
$bin_db_ver = trim($db_version[1]);
$local_db_ver = trim(GetMySQLResult("SELECT version FROM db_version LIMIT 1"));
print " Binary Database Version: (" . $bin_db_ver . ")\n";
print " Local Database Version: (" . $local_db_ver . ")\n\n";
#::: If World ran this script, and our version is up to date, continue...
if($bin_db_ver == $local_db_ver && $ARGV[0] eq "ran_from_world"){
print " Database up to Date: Continuing World Bootup...\n";
print "============================================================\n";
exit;
}
if(!$bin_db_ver){ $bin_db_ver = 9100; }
print "Retrieving latest database manifest...\n";
GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
# GetRemoteFile("https://dl.dropboxusercontent.com/u/50023467/dl/db_update_manifest.txt", "db_update/db_update_manifest.txt");
if($local_db_ver < $bin_db_ver && $ARGV[0] eq "ran_from_world"){
print "You have missing database updates, type 1 or 2 to backup your database before running them as recommended...\n\n";
#::: Display Menu
ShowMenuPrompt();
}
else{
#::: Most likely ran standalone
print "\n";
ShowMenuPrompt();
}
sub ShowMenuPrompt {
my %dispatch = (
1 => \&database_dump,
2 => \&database_dump_compress,
3 => \&Run_Database_Check,
0 => \&Exit,
);
while (1) {
{
local $| = 1;
if(!$menu_show && $ARGV[0] eq "ran_from_world"){
$menu_show++;
next;
}
print MenuOptions(), '> ';
}
my $choice = <>;
$choice =~ s/\A\s+//;
$choice =~ s/\s+\z//;
if (defined(my $handler = $dispatch{$choice})) {
my $result = $handler->();
unless (defined $result) {
exit 0;
}
}
else {
if($ARGV[0] ne "ran_from_world"){
# warn "\n\nInvalid selection\n\n";
}
}
}
}
sub MenuOptions {
if(@total_updates){
$option[3] = "Run pending updates... (" . scalar (@total_updates) . ")";
}
else{
$option[3] = "Check for pending Database updates
Stages updates for automatic upgrade...";
}
return <<EO_MENU;
Database Management Menu (Please Select):
1) Backup Database - (Saves to Backups folder)
Ideal to perform before performing updates
2) Backup Database Compressed - (Saves to Backups folder)
Ideal to perform before performing updates
3) $option[3]
0) Exit
EO_MENU
}
sub CheckForDatabaseDumpScript{
if(`perl db_dumper.pl`=~/Need arguments/i){
return;
}
else{
print "db_dumper.pl not found... retrieving...\n\n";
GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/db_dumper.pl", "db_dumper.pl");
}
}
sub ran_from_world {
print "Running from world...\n";
}
sub database_dump {
CheckForDatabaseDumpScript();
print "Performing database backup....\n";
print `perl db_dumper.pl database="$db" loc="backups"`;
}
sub database_dump_compress {
CheckForDatabaseDumpScript();
print "Performing database backup....\n";
print `perl db_dumper.pl database="$db" loc="backups" compress`;
}
sub Exit{ }
#::: Returns Tab Delimited MySQL Result from Command Line
sub GetMySQLResult{
my $run_query = $_[0];
if($OS eq "Windows"){ return `"$path" --user $user --password="$pass" $db -N -B -e "$run_query"`; }
if($OS eq "Linux"){
$run_query =~s/`//g;
return `$path --user="$user" --password="$pass" $db -N -B -e "$run_query"`;
}
}
sub GetMySQLResultFromFile{
my $update_file = $_[0];
if($OS eq "Windows"){ return `"$path" --user $user --password="$pass" --force $db < $update_file`; }
if($OS eq "Linux"){ return `"$path" --user $user --password="$pass" --force $db < $update_file`; }
}
#::: Gets Remote File based on URL (1st Arg), and saves to destination file (2nd Arg)
#::: Example: GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
sub GetRemoteFile{
my $URL = $_[0];
my $Dest_File = $_[1];
if($OS eq "Windows"){
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->timeout(10);
$ua->env_proxy;
my $response = $ua->get($URL);
if ($response->is_success){
open (FILE, '> ' . $Dest_File . '');
print FILE $response->decoded_content;
close (FILE);
print " URL: " . $URL . "\n";
print " Saved: " . $Dest_File . " \n";
}
else {
print "Error, no connection to the internet...\n\n";
die $response->status_line;
}
}
if($OS eq "Linux"){
#::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
$wget = `wget --quiet -O $Dest_File $URL`;
print " URL: " . $URL . "\n";
print " Saved: " . $Dest_File . " \n";
if($wget=~/unable to resolve/i){
print "Error, no connection to the internet...\n\n";
die;
}
}
}
#::: Trim Whitespaces
sub trim {
my $string = $_[0];
$string =~ s/^\s+//;
$string =~ s/\s+$//;
return $string;
}
#::: Responsible for Database Upgrade Routines
sub Run_Database_Check{
#::: Run 2 - Running pending updates...
if(defined(@total_updates)){
@total_updates = sort @total_updates;
foreach my $val (@total_updates){
$file_name = trim($m_d{$val}[1]);
print "Running Update: " . $val . " - " . $file_name . "\n";
print GetMySQLResultFromFile("db_update/$file_name");
print GetMySQLResult("UPDATE db_version SET version = $val WHERE version < $val");
}
}
#::: Run 1 - Initial checking of needed updates...
print "Reading manifest...\n\n";
use Data::Dumper;
open (FILE, "db_update/db_update_manifest.txt");
while (<FILE>) {
chomp;
$o = $_;
if($o=~/#/i){ next; }
@manifest = split('\|', $o);
$m_d{$manifest[0]} = [@manifest];
}
@total_updates = ();
#::: Iterate through Manifest backwards from binary version down to local version...
for($i = $bin_db_ver; $i > 1000; $i--){
if(!defined($m_d{$i}[0])){ next; }
$file_name = trim($m_d{$i}[1]);
$query_check = trim($m_d{$i}[2]);
$match_type = trim($m_d{$i}[3]);
$match_text = trim($m_d{$i}[4]);
#::: Match type update
if($match_type eq "contains"){
if(trim(GetMySQLResult($query_check))=~/$match_text/i){
print "Missing DB Update " . $i . " '" . $file_name . "' \n";
FetchMissingUpdate($i, $file_name);
push(@total_updates, $i);
}
else{
print "DB up to date with: " . $i . " '" . $file_name . "' \n";
}
print_match_debug();
print_break();
}
if($match_type eq "missing"){
if(GetMySQLResult($query_check)=~/$match_text/i){
print "DB up to date with: " . $i . " '" . $file_name . "' \n";
next;
}
else{
print "Missing DB Update " . $i . " '" . $file_name . "' \n";
FetchMissingUpdate($i, $file_name);
push(@total_updates, $i);
}
print_match_debug();
print_break();
}
if($match_type eq "empty"){
if(GetMySQLResult($query_check) eq ""){
print "Missing DB Update " . $i . " '" . $file_name . "' \n";
FetchMissingUpdate($i, $file_name);
push(@total_updates, $i);
}
else{
print "DB up to date with: " . $i . " '" . $file_name . "' \n";
}
print_match_debug();
print_break();
}
if($match_type eq "not_empty"){
if(GetMySQLResult($query_check) ne ""){
print "Missing DB Update " . $i . " '" . $file_name . "' \n";
FetchMissingUpdate($i, $file_name);
push(@total_updates, $i);
}
else{
print "DB up to date with: " . $i . " '" . $file_name . "' \n";
}
print_match_debug();
print_break();
}
}
print "\n\n";
}
sub FetchMissingUpdate{
$db_update = $_[0];
$update_file = $_[1];
if($db_update >= 9000){
GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/required/" . $update_file, "db_update/" . $update_file . "");
}
elsif($db_update >= 5000 && $db_update <= 9000){
GetRemoteFile("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/svn/" . $update_file, "db_update/" . $update_file . "");
}
}
sub print_match_debug{
if(!$debug){ return; }
print " Match Type: '" . $match_type . "'\n";
print " Match Text: '" . $match_text . "'\n";
print " Query Check: '" . $query_check . "'\n";
print " Result: '" . trim(GetMySQLResult($query_check)) . "'\n";
}
sub print_break{
if(!$debug){ return; }
print "\n==============================================\n";
}

View File

@ -1,316 +1,332 @@
5001, 1_task_system.sql
5002, 2_optional_maxclients.sql
5003, 14_optional_merchantlist.sql
5004, 35_task_stepped.sql
5005, 42_task_min_maxlevel.sql
5006, 55_zone_shutdowndeleay.sql
5007, 68_optional_character_maxexplevel.sql
5008, 103_optional_chat_rules.sql
5009, 104_traps.sql
5010, 106_optional_proc_rules.sql
5011, 120_damageshieldtypes.sql
5012, 125_aggrozone.sql
5013, 127_optional_spell_rules.sql
5014, 129_optional_shared_plat_rule.sql
5015, 131_optional_combat_rules.sql
5016, 133_task_repeatable.sql
5017, 142_deathpeace_and_lifetap_aas.sql
5018, 158_optional_death_exp_loss.sql
5019, 176_melody.sql
5020, 189_character_.sql
5021, 196_trader.sql
5022, 210_undyeme.sql
5023, 222_buyer.sql
5024, 226_account_limiting.sql
5025, 230_spells_table.sql
5026, 235_horses_table.sql
5027, 243_spawn_timers.sql
5028, 247_mail.sql
5029, 249_chatchannels.sql
5030, 250_bot_spell_update.sql
5031, 250_optional_bot_spell_update.sql
5032, 285_optional_bot_spell_update.sql
5033, 292_augslots.sql
5034, 294_merchant_logging.sql
5035, 304_faction_list.sql
5036, 326_aas.sql
5037, 328_bot_management.sql
5038, 328_optional_bot_management.sql
5039, 340_gm_ips.sql
5040, 356_combat.sql
5041, 360_peqzone.sql
5042, 364_ranged_dist_rule.sql
5043, 386_bot_save_raid.sql
5044, 434_optional_rest_state_rules.sql
5045, 447_sof_startzone_rule.sql
5046, 463_altadv_vars.sql
5047, 475_aa_actions.sql
5048, 500_spawn2_optimization.sql
5049, 503_bugs.sql
5050, 518_drakkin_npc_type_features.sql
5051, 524_rule_values_notes.sql
5052, 527_npc_armor_tint.sql
5053, 553_saylink_table.sql
5054, 564_nokeyring.sql
5055, 600_group_leadership.sql
5056, 612_instance_changes.sql
5057, 615_adventure_assassination.sql
5058, 619_Adventure_Recruiter_Flavor.sql
5059, 621_LDoNTraps.sql
5060, 633_ucs.sql
5061, 634_TrapTemplateDefaultValue.sql
5062, 643_BotsTable.sql
5063, 646_archery_penalty_rule.sql
5064, 665_heroic_resists.sql
5065, 667_titles.sql
5066, 687_aa_table_changes.sql
5067, 699_peqzone_rule.sql
5068, 702_aashieldblock_tint_table.sql
5069, 703_peqzone_rule.sql
5070, 704_rules.sql
5071, 710_tint_set_naming.sql
5072, 721_pathing_rules.sql
5073, 730_smart_delay_moving.sql
5074, 731_rule_assist_notarget_self.sql
5075, 732_sacrifice_rules.sql
5076, 745_slow_mitigation.sql
5077, 754_archery_base_damage_rule.sql
5078, 755_sof_altadv_vars_updates.sql
5079, 773_monk_rules.sql
5080, 853_optional_rule_aaexp.sql
5081, 858_optional_rule_ip_limit_by_status.sql
5082, 892_optional_bots_table_mod.sql
5083, 893_optional_bots_table_mod.sql
5084, 898_npc_maxlevel_scalerate.sql
5085, 902_optional_rule_snareflee.sql
5086, 923_spawn2_enabled.sql
5087, 962_hot_zone.sql
5088, 964_reports.sql
5089, 971_veteran_rewards.sql
5090, 977_raid_npc_private_corpses.sql
5091, 979_unique_spawn_by_name.sql
5092, 980_account_ip.sql
5093, 1022_botadventuring.sql
5094, 1027_botactives.sql
5095, 1030_botzoningsupport.sql
5096, 1036_botbuffs.sql
5097, 1038_botpetstatepersists.sql
5098, 1038_grouptablesuniquecolumndefinitions.sql
5099, 1039_botguilds.sql
5100, 1040_DeprecatedBotRaidsSystems.sql
5101, 1057_titles.sql
5102, 1077_botgroups.sql
5103, 1136_spell_globals.sql
5104, 1144_optional_rule_return_nodrop.sql
5105, 1195_account_suspendeduntil.sql
5106, 1259_npc_skill_types.sql
5107, 1280_bot_augs.sql
5108, 1290_optional_exp_loss_rule.sql
5109, 1293_guild_bank.sql
5110, 1379_loginserver_trusted_server.sql
5111, 1392_recipe_learning.sql
5112, 1394_optional_rule_sod_hp_mana_end.sql
5113, 1404_faction_list.sql
5114, 1410_optional_sod_aas_ht_and_loh.sql
5115, 1436_login_server_table_fix.sql
5116, 1446_allowrest_optional.sql
5117, 1446_allowrest_required.sql
5118, 1450_cvs.sql
5119, 1451_guilds.sql
5120, 1498_instance_adventure.sql
5121, 1510_global_instances.sql
5122, 1511_map_path_loading.sql
5123, 1513_zone_points.sql
5124, 1519_zone_primary_key_id.sql
5125, 1542_items_table_cleanup.sql
5126, 1548_nimbuseffect_required.sql
5127, 1562_instanced_spawnconditions.sql
5128, 1586_waypoints_optional.sql
5129, 1610_tradeskill_required.sql
5130, 1618_zone.sql
5131, 1625_optional_rule_class_race_exp_bonus.sql
5132, 1672_optional_rules_respawn_window.sql
5133, 1679_optional_rules_blocked_buffs.sql
5134, 1696_modify_zone_and_object_tables.sql
5135, 1711_account_restricted_aa.sql
5136, 1717_optional_rule_bash_stun_chance.sql
5137, 1718_optional_rules_mod3s.sql
5138, 1719_optional_triggerOnCastAAs.sql
5139, 1720_optional_sql_AAs.sql
5140, 1720_required_sql_AA_effects_update.sql
5141, 1721_optional_sql_drakkin_breath_update.sql
5142, 1721_required_sql_altadv_vars_update.sql
5143, 1723_optional_sql_new_stats_window_rule.sql
5144, 1723_required_sql_corruption.sql
5145, 1736_optional_sql_feral_swipe.sql
5146, 1737_required_sql_rule_and_aa_update.sql
5147, 1746_optional_sql_bot_manaregen.sql
5148, 1747_optional_HoT_zone_and_zonepoints.sql
5149, 1750_optional_sql_reflect_rule.sql
5150, 1753_optional_haste_cap_rule.sql
5151, 1753_required_sql_healing_adept_aa.sql
5152, 1754_required_sql_healing_adept_aa_fix.sql
5153, 1755_required_sql_fear_resist_aas.sql
5154, 1784_optional_corpsedrag_rules.sql
5155, 1786_required_update_to_aas.sql
5156, 1790_required_aa_required_level_cost.sql
5157, 1793_resist_adjust.sql
5158, 1799_optional_rest_regen_endurance_rule.sql
5159, 1802_required_doppelganger.sql
5160, 1803_required_tasks_xpreward_signed.sql
5161, 1804_required_ae_melee_updates.sql
5162, 1809_optional_rules.sql
5163, 1813_required_doppelganger_npcid_change.sql
5164, 1817_optional_npc_archery_bonus_rule.sql
5165, 1823_optional_delay_death.sql
5166, 1847_required_doors_dest_zone_size_32.sql
5167, 1859_optional_item_casts_use_focus_rule.sql
5168, 1884_optional_bot_spells_update.sql
5169, 1885_optional_rules_fv_pvp_expansions.sql
5170, 1889_optional_skill_cap_rule.sql
5171, 1908_required_npc_types_definitions.sql
5172, 1926_optional_stat_cap.sql
5173, 1944_spawn2.sql
5174, 1946_doors.sql
5175, 1960_optional_console_timeout_rule.sql
5176, 1962_optional_guild_creation_window_rules.sql
5177, 1963_optional_rule_live_like_focuses.sql
5178, 1968_optional_enrage_rules.sql
5179, 1972_optional_extradmg_item_cap.sql
5180, 1974_required_bot_spells_update.sql
5181, 1977_underwater.sql
5182, 1998_optional_intoxication_and_looting_rules.sql
5183, 2004_charges_alt_currency.sql
5184, 2015_optional_specialization_training_rule.sql
5185, 2016_optional_rule_bot_aa_expansion.sql
5186, 2023_optional_mysqlcli.sql
5187, 2024_optional_update_crystals.sql
5188, 2024_required_update.sql
5189, 2057_required_discovered_items.sql
5190, 2058_optional_rule_discovered_items.sql
5191, 2062_required_version_changes.sql
5192, 2069_required_pets.sql
5193, 2079_player_speech.sql
5194, 2087_required_bots_hp_and_mana_and_spell_updates.sql
5195, 2098_required_zonepoint_version_changes.sql
5196, 2099_required_discovered_items_account_status.sql
5197, 2104_required_group_roles.sql
5198, 2107_required_bot_stances.sql
5199, 2129_required_lfguild.sql
5200, 2133_required_faction_loot_despawn.sql
5201, 2136_extended_targets.sql
5202, 2142_emotes.sql
5203, 2154_optional_rule_spell_procs_resists_falloff.sql
5204, 2156_optional_charm_break_rule.sql
5205, 2159_optional_defensiveproc_rules.sql
5206, 2164_require_bots_bottimers.sql
5207, 2171_optional_SpecialAttackACBonus_rule.sql
5208, 2176_optional_aa_expansion_SOF_fix.sql
5209, 2176_optional_FrenzyBonus_rule.sql
5210, 2176_required_aa_updates.sql
5211, 2178_required_aa_updates.sql
5212, 2183_optional_bot_xp_rule.sql
5213, 2185_optional_NPCFlurryChacne_rule
5214, 2185_optional_NPCFlurryChacne_rule.sql
5215, 2185_optional_NPCFlurryChance_rule.sql
5216, 2185_required_aa_updates
5217, 2185_required_aa_updates.sql
5218, 2188_optional_miscspelleffect_rules
5219, 2188_optional_miscspelleffect_rules.sql
5220, 2188_required_aa_updates
5221, 2188_required_aa_updates.sql
5222, 2189_optional_taunt_rules
5223, 2189_optional_taunt_rules.sql
5224, 2195_required_sharedplatupdates.sql
5225, 2208_optional_aa_stacking_rule.sql
5226, 2208_optional_EnableSoulAbrasionAA.sql
5227, 2208_required_aa_updates.sql
5228, 2209_optional_additive_bonus_rule.sql
5229, 2213_loot_changes.sql
5230, 2214_faction_list_mod.sql
5231, 2215_required_aa_updates.sql
5232, 2243_optional_char_max_level_rule.sql
5233, 2260_probability.sql
5234, 2262_required_pet_discipline_update.sql
5235, 2264_required_aa_updates.sql
5236, 2268_QueryServ.sql
5237, 2268_required_updates.sql
5238, 2274_optional_rule_iplimitdisconnectall.sql
5239, 2278_optional_rule_targetableswarmpet.sql
5240, 2280_optional_rule_targetableswarmpet-rename.sql
5241, 2283_required_npc_changes.sql
5242, 2299_required_inspectmessage_fields.sql
5243, 2300_optional_loot_changes.sql
5244, 2304_QueryServ.sql
5245, 2340_required_maxbuffslotspet.sql
5246, 2361_QueryServ.sql
5247, 2361_required_qs_rule_values.sql
5248, 2370_required_aa_updates.sql
5249, 2376_required_aa_updates.sql
5250, 2380_optional_merc_data.sql
5251, 2380_optional_merc_merchant_npctypes_update.sql
5252, 2380_optional_merc_rules.sql
5253, 2383_required_group_ismerc.sql
5254, 2428_optional_levelbasedexpmods.sql
5255, 2448_optional_stun_proc_aggro_rule.sql
5256, 2471_required_aa_updates.sql
5257, 2482_required_start_zones.sql
5258, 2504_required_aa_updates.sql
9000, 2013_02_18_Merc_Rules_and_Tables.sql
9001, 2013_02_25_Impr_HT_LT.sql
9002, 2013_03_1_Merc_Rules_and_Equipment.sql
9003, 2013_03_23_Escape_FadingMemories.sql
9004, 2013_04_04_NaturesBounty.sql
9005, 2013_04_08_Salvage.sql
9006, 2013_05_05_Account_Flags.sql
9007, 2013_05_05_Item_Tick.sql
9008, 2013_07_11_NPC_Special_Abilities.sql
9009, 2013_10_12_Merc_Special_Abilities.sql
9010, 2013_10_12_Merc_vwMercNpcTypes.sql
9011, 2013_10_31_Recipe_disabling.sql
9012, 2013_11_07_BaseData.sql
9013, 2013_11_13_Instrument_Singing_Mastery.sql
9014, 2013_11_18_AssistRadius.sql
9015, 2013_12_26_MerchantList_Class_Required.sql
9016, 2014_01_04_SongModCapAAs.sql
9017, 2014_01_08_SpellsNewAdditions.sql
9018, 2014_01_09_PreservePetSize.sql
9019, 2014_01_20_MezMastery.sql
9020, 2014_01_20_Not_Extendable.sql
9021, 2014_01_20_SpellCastingReinforcement.sql
9022, 2014_01_20_Weather.sql
9023, 2014_01_27_CritcalMendAA.sql
9024, 2014_02_02_SpellCriticalsAA.sql
9025, 2014_02_13_Rename_instance_lockout_tables.sql
9026, 2014_02_13_spells_new_update.sql
9027, 2014_02_20_buff_update.sql
9028, 2014_02_26_roambox_update.sql
9029, 2014_02_26_virulentvenomAA.sql
9030, 2014_04_04_PhysicalResist.sql
9031, 2014_04_10_No_Target_With_Hotkey.sql
9032, 2014_04_12_SlowMitigation.sql
9033, 2014_04_18_Suppress_Command_Error.sql
9034, 2014_04_25_spawn_events.sql
9035, 2014_04_27_AISpellEffects.sql
9036, 2014_05_04_SlowMitigationFix.sql
9037, 2014_06_25_AA_Updates..sql
9038, 2014_06_25_AA_Updates.sql
9039, 2014_07_04_AA_Updates.sql
9040, 2014_07_10_npc_spells.sql
9041, 2014_08_02_spells_new.sql
9042, 2014_08_12_NPC_raid_targets.sql
9043, 2014_08_18_spells_new_update.sql
9044, 2014_08_20_merchantlist_probability.sql
9045, 2014_08_23_Complete_QueryServ_Table_Structures.sql
9046, 2014_08_23_player_events_and_player_aa_rate_hourly.sql
9047, 2014_08_24_character_lookup.sql
9048, 2014_09_09_attack_delay.sql
9049, 2014_09_18_tellqueuesclean.sql
9050, 2014_09_20_ban_messages.sql
9051, 2014_10_11_RaidMOTD.sql
9052, 2014_10_13_RaidLeadership.sql
9053, 2014_10_18_group_mentor.sql
9054, 2014_10_19_raid_group_mentor.sql
9055, 2014_10_30_special_abilities_null.sql
9056, 2014_11_08_RaidMembers.sql
9057, 2014_11_13_spells_new_updates.sql
5001|1_task_system.sql
# 5002|2_optional_maxclients.sql
# 5003|14_optional_merchantlist.sql
5004|35_task_stepped.sql
5005|42_task_min_maxlevel.sql
5006|55_zone_shutdowndeleay.sql
# 5007|68_optional_character_maxexplevel.sql
# 5008|103_optional_chat_rules.sql
5009|104_traps.sql
# 5010|106_optional_proc_rules.sql
5011|120_damageshieldtypes.sql
5012|125_aggrozone.sql
# 5013|127_optional_spell_rules.sql
# 5014|129_optional_shared_plat_rule.sql
# 5015|131_optional_combat_rules.sql
5016|133_task_repeatable.sql
5017|142_deathpeace_and_lifetap_aas.sql
# 5018|158_optional_death_exp_loss.sql
5019|176_melody.sql
5020|189_character_.sql
5021|196_trader.sql
5022|210_undyeme.sql
5023|222_buyer.sql
5024|226_account_limiting.sql
5025|230_spells_table.sql
5026|235_horses_table.sql
5027|243_spawn_timers.sql
5028|247_mail.sql
5029|249_chatchannels.sql
5030|250_bot_spell_update.sql
# 5031|250_optional_bot_spell_update.sql
# 5032|285_optional_bot_spell_update.sql
5033|292_augslots.sql
5034|294_merchant_logging.sql
5035|304_faction_list.sql
5036|326_aas.sql
5037|328_bot_management.sql
# 5038|328_optional_bot_management.sql
5039|340_gm_ips.sql
5040|356_combat.sql
5041|360_peqzone.sql
5042|364_ranged_dist_rule.sql
5043|386_bot_save_raid.sql
# 5044|434_optional_rest_state_rules.sql
5045|447_sof_startzone_rule.sql
5046|463_altadv_vars.sql
5047|475_aa_actions.sql
5048|500_spawn2_optimization.sql
5049|503_bugs.sql
5050|518_drakkin_npc_type_features.sql
5051|524_rule_values_notes.sql
5052|527_npc_armor_tint.sql
5053|553_saylink_table.sql
5054|564_nokeyring.sql
5055|600_group_leadership.sql
5056|612_instance_changes.sql
5057|615_adventure_assassination.sql
5058|619_Adventure_Recruiter_Flavor.sql
5059|621_LDoNTraps.sql
5060|633_ucs.sql
5061|634_TrapTemplateDefaultValue.sql
5062|643_BotsTable.sql
5063|646_archery_penalty_rule.sql
5064|665_heroic_resists.sql
5065|667_titles.sql
5066|687_aa_table_changes.sql
5067|699_peqzone_rule.sql
5068|702_aashieldblock_tint_table.sql
5069|703_peqzone_rule.sql
5070|704_rules.sql
5071|710_tint_set_naming.sql
5072|721_pathing_rules.sql
5073|730_smart_delay_moving.sql
5074|731_rule_assist_notarget_self.sql
5075|732_sacrifice_rules.sql
5076|745_slow_mitigation.sql
5077|754_archery_base_damage_rule.sql
5078|755_sof_altadv_vars_updates.sql
5079|773_monk_rules.sql
# 5080|853_optional_rule_aaexp.sql
# 5081|858_optional_rule_ip_limit_by_status.sql
# 5082|892_optional_bots_table_mod.sql
# 5083|893_optional_bots_table_mod.sql
5084|898_npc_maxlevel_scalerate.sql
# 5085|902_optional_rule_snareflee.sql
5086|923_spawn2_enabled.sql
5087|962_hot_zone.sql
5088|964_reports.sql
5089|971_veteran_rewards.sql
5090|977_raid_npc_private_corpses.sql
5091|979_unique_spawn_by_name.sql
5092|980_account_ip.sql
5093|1022_botadventuring.sql
5094|1027_botactives.sql
5095|1030_botzoningsupport.sql
5096|1036_botbuffs.sql
5097|1038_botpetstatepersists.sql
5098|1038_grouptablesuniquecolumndefinitions.sql
5099|1039_botguilds.sql
5100|1040_DeprecatedBotRaidsSystems.sql
5101|1057_titles.sql
5102|1077_botgroups.sql
5103|1136_spell_globals.sql
# 5104|1144_optional_rule_return_nodrop.sql
5105|1195_account_suspendeduntil.sql
5106|1259_npc_skill_types.sql
5107|1280_bot_augs.sql
# 5108|1290_optional_exp_loss_rule.sql
5109|1293_guild_bank.sql
5110|1379_loginserver_trusted_server.sql
5111|1392_recipe_learning.sql
# 5112|1394_optional_rule_sod_hp_mana_end.sql
5113|1404_faction_list.sql
# 5114|1410_optional_sod_aas_ht_and_loh.sql
5115|1436_login_server_table_fix.sql
5116|1446_allowrest_optional.sql
5117|1446_allowrest_required.sql
5118|1450_cvs.sql
5119|1451_guilds.sql
5120|1498_instance_adventure.sql
5121|1510_global_instances.sql
5122|1511_map_path_loading.sql
5123|1513_zone_points.sql
5124|1519_zone_primary_key_id.sql
5125|1542_items_table_cleanup.sql
5126|1548_nimbuseffect_required.sql
5127|1562_instanced_spawnconditions.sql
5128|1586_waypoints_optional.sql
5129|1610_tradeskill_required.sql
5130|1618_zone.sql
# 5131|1625_optional_rule_class_race_exp_bonus.sql
# 5132|1672_optional_rules_respawn_window.sql
# 5133|1679_optional_rules_blocked_buffs.sql
5134|1696_modify_zone_and_object_tables.sql
5135|1711_account_restricted_aa.sql
# 5136|1717_optional_rule_bash_stun_chance.sql
# 5137|1718_optional_rules_mod3s.sql
# 5138|1719_optional_triggerOnCastAAs.sql
# 5139|1720_optional_sql_AAs.sql
5140|1720_required_sql_AA_effects_update.sql
# 5141|1721_optional_sql_drakkin_breath_update.sql
5142|1721_required_sql_altadv_vars_update.sql
# 5143|1723_optional_sql_new_stats_window_rule.sql
5144|1723_required_sql_corruption.sql
# 5145|1736_optional_sql_feral_swipe.sql
5146|1737_required_sql_rule_and_aa_update.sql
# 5147|1746_optional_sql_bot_manaregen.sql
# 5148|1747_optional_HoT_zone_and_zonepoints.sql
# 5149|1750_optional_sql_reflect_rule.sql
# 5150|1753_optional_haste_cap_rule.sql
5151|1753_required_sql_healing_adept_aa.sql
5152|1754_required_sql_healing_adept_aa_fix.sql
5153|1755_required_sql_fear_resist_aas.sql
# 5154|1784_optional_corpsedrag_rules.sql
5155|1786_required_update_to_aas.sql
5156|1790_required_aa_required_level_cost.sql
5157|1793_resist_adjust.sql
# 5158|1799_optional_rest_regen_endurance_rule.sql
5159|1802_required_doppelganger.sql
5160|1803_required_tasks_xpreward_signed.sql
5161|1804_required_ae_melee_updates.sql
# 5162|1809_optional_rules.sql
5163|1813_required_doppelganger_npcid_change.sql
# 5164|1817_optional_npc_archery_bonus_rule.sql
# 5165|1823_optional_delay_death.sql
5166|1847_required_doors_dest_zone_size_32.sql
# 5167|1859_optional_item_casts_use_focus_rule.sql
# 5168|1884_optional_bot_spells_update.sql
# 5169|1885_optional_rules_fv_pvp_expansions.sql
# 5170|1889_optional_skill_cap_rule.sql
5171|1908_required_npc_types_definitions.sql
# 5172|1926_optional_stat_cap.sql
5173|1944_spawn2.sql
5174|1946_doors.sql
# 5175|1960_optional_console_timeout_rule.sql
# 5176|1962_optional_guild_creation_window_rules.sql
# 5177|1963_optional_rule_live_like_focuses.sql
# 5178|1968_optional_enrage_rules.sql
# 5179|1972_optional_extradmg_item_cap.sql
5180|1974_required_bot_spells_update.sql
5181|1977_underwater.sql
# 5182|1998_optional_intoxication_and_looting_rules.sql
5183|2004_charges_alt_currency.sql
# 5184|2015_optional_specialization_training_rule.sql
# 5185|2016_optional_rule_bot_aa_expansion.sql
# 5186|2023_optional_mysqlcli.sql
# 5187|2024_optional_update_crystals.sql
5188|2024_required_update.sql
5189|2057_required_discovered_items.sql
# 5190|2058_optional_rule_discovered_items.sql
5191|2062_required_version_changes.sql
5192|2069_required_pets.sql
5193|2079_player_speech.sql
5194|2087_required_bots_hp_and_mana_and_spell_updates.sql
5195|2098_required_zonepoint_version_changes.sql
5196|2099_required_discovered_items_account_status.sql
5197|2104_required_group_roles.sql
5198|2107_required_bot_stances.sql
5199|2129_required_lfguild.sql
5200|2133_required_faction_loot_despawn.sql
5201|2136_extended_targets.sql
5202|2142_emotes.sql
# 5203|2154_optional_rule_spell_procs_resists_falloff.sql
# 5204|2156_optional_charm_break_rule.sql
# 5205|2159_optional_defensiveproc_rules.sql
5206|2164_require_bots_bottimers.sql
# 5207|2171_optional_SpecialAttackACBonus_rule.sql
# 5208|2176_optional_aa_expansion_SOF_fix.sql
# 5209|2176_optional_FrenzyBonus_rule.sql
5210|2176_required_aa_updates.sql
5211|2178_required_aa_updates.sql
# 5212|2183_optional_bot_xp_rule.sql
# 5213|2185_optional_NPCFlurryChacne_rule
# 5214|2185_optional_NPCFlurryChacne_rule.sql
# 5215|2185_optional_NPCFlurryChance_rule.sql
5216|2185_required_aa_updates
5217|2185_required_aa_updates.sql
# 5218|2188_optional_miscspelleffect_rules
# 5219|2188_optional_miscspelleffect_rules.sql
5220|2188_required_aa_updates
5221|2188_required_aa_updates.sql
# 5222|2189_optional_taunt_rules
# 5223|2189_optional_taunt_rules.sql
5224|2195_required_sharedplatupdates.sql
# 5225|2208_optional_aa_stacking_rule.sql
# 5226|2208_optional_EnableSoulAbrasionAA.sql
5227|2208_required_aa_updates.sql
# 5228|2209_optional_additive_bonus_rule.sql
5229|2213_loot_changes.sql
5230|2214_faction_list_mod.sql
5231|2215_required_aa_updates.sql
# 5232|2243_optional_char_max_level_rule.sql
5233|2260_probability.sql
5234|2262_required_pet_discipline_update.sql
5235|2264_required_aa_updates.sql
5236|2268_QueryServ.sql
5237|2268_required_updates.sql
# 5238|2274_optional_rule_iplimitdisconnectall.sql
# 5239|2278_optional_rule_targetableswarmpet.sql
# 5240|2280_optional_rule_targetableswarmpet-rename.sql
5241|2283_required_npc_changes.sql
5242|2299_required_inspectmessage_fields.sql
# 5243|2300_optional_loot_changes.sql
5244|2304_QueryServ.sql
5245|2340_required_maxbuffslotspet.sql
5246|2361_QueryServ.sql
5247|2361_required_qs_rule_values.sql
5248|2370_required_aa_updates.sql
5249|2376_required_aa_updates.sql
# 5250|2380_optional_merc_data.sql
# 5251|2380_optional_merc_merchant_npctypes_update.sql
# 5252|2380_optional_merc_rules.sql
5253|2383_required_group_ismerc.sql
# 5254|2428_optional_levelbasedexpmods.sql
# 5255|2448_optional_stun_proc_aggro_rule.sql
5256|2471_required_aa_updates.sql
5257|2482_required_start_zones.sql
5258|2504_required_aa_updates.sql
8000|mercs.sql|SHOW TABLES LIKE 'merc_stats'|empty|
9000|2013_02_18_Merc_Rules_and_Tables.sql|SELECT * FROM `rule_values` WHERE `rule_name` LIKE '%Mercs:ResurrectRadius%'|empty|
9001|2013_02_25_Impr_HT_LT.sql|SHOW TABLES LIKE 'merc_inventory'|empty|
9002|2013_03_1_Merc_Rules_and_Equipment.sql|SHOW TABLES LIKE 'merc_inventory'|empty|
# 9003|2013_03_23_Escape_FadingMemories.sql
9004|2013_04_04_NaturesBounty.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '1230' AND `slot` = '1' AND `effectid` = '313' AND `base1` = '15' AND `base2` = '0'|empty|
9005|2013_04_08_Salvage.sql|SHOW COLUMNS FROM `tradeskill_recipe_entries` LIKE 'salvagecount'|empty|
9006|2013_05_05_Account_Flags.sql|SHOW TABLES LIKE 'account_flags'|empty|
9007|2013_05_05_Item_Tick.sql|SHOW TABLES LIKE 'item_tick'|empty|
9008|2013_07_11_NPC_Special_Abilities.sql|SHOW COLUMNS FROM `npc_types` LIKE 'special_abilities'|empty|
9009|2013_10_12_Merc_Special_Abilities.sql|SHOW COLUMNS FROM `merc_stats` LIKE 'special_abilities'|empty|
# 9010|2013_10_12_Merc_vwMercNpcTypes.sql
9011|2013_10_31_Recipe_disabling.sql|SHOW COLUMNS FROM `tradeskill_recipe` LIKE 'enabled'|empty|
9012|2013_11_07_BaseData.sql|SHOW TABLES LIKE 'base_data'|empty|
9013|2013_11_13_Instrument_Singing_Mastery.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '213' AND `slot` = '1' AND `effectid` = '260' AND `base1` = '2' AND `base2` = '23'|empty|
9014|2013_11_18_AssistRadius.sql|SHOW COLUMNS FROM `npc_types` LIKE 'assistradius'|empty|
9015|2013_12_26_MerchantList_Class_Required.sql|SHOW COLUMNS FROM `merchantlist` LIKE 'classes_required'|empty|
9016|2014_01_04_SongModCapAAs.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '571' AND `slot` = '1' AND `effectid` = '261'|empty|
9017|2014_01_08_SpellsNewAdditions.sql|SHOW COLUMNS FROM `spells_new` LIKE 'persistdeath'|empty|
9018|2014_01_09_PreservePetSize.sql|SHOW COLUMNS FROM `character_pet_info` LIKE 'size'|empty|
9019|2014_01_20_MezMastery.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '781' AND `slot` = '1' AND `effectid` = '287'|empty|
9020|2014_01_20_Not_Extendable.sql|SHOW COLUMNS FROM `spells_new` LIKE 'not_extendable'|empty|
9021|2014_01_20_SpellCastingReinforcement.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '86' AND `slot` = '1' AND `effectid` = '128'|empty|
9022|2014_01_20_Weather.sql|SHOW COLUMNS FROM `zone` LIKE 'rain_chance1'|empty|
9023|2014_01_27_CritcalMendAA.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '230' AND `slot` = '1' AND `effectid` = '275'|empty
9024|2014_02_02_SpellCriticalsAA.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '4755' AND `slot` = '1' AND `effectid` = '294'|empty
9025|2014_02_13_Rename_instance_lockout_tables.sql|SHOW TABLES LIKE 'instance_list'|empty|
9026|2014_02_13_spells_new_update.sql|SHOW COLUMNS FROM `spells_new` LIKE 'ConeStartAngle'|empty|
9027|2014_02_20_buff_update.sql|SHOW COLUMNS FROM `character_buffs` LIKE 'caston_y'|empty|
9028|2014_02_26_roambox_update.sql|SHOW COLUMNS FROM `spawngroup` LIKE 'mindelay'|empty|
9029|2014_02_26_virulentvenomAA.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '888' AND `slot` = '1' AND `effectid` = '250'|empty|
9030|2014_04_04_PhysicalResist.sql|SHOW COLUMNS FROM `npc_types` LIKE 'PhR'|empty|
9031|2014_04_10_No_Target_With_Hotkey.sql|SHOW COLUMNS FROM `npc_types` LIKE 'no_target_hotkey'|empty|
9032|2014_04_12_SlowMitigation.sql|SHOW COLUMNS FROM `npc_types` LIKE 'slow_mitigation'|contains|float
9034|2014_04_25_spawn_events.sql|SHOW COLUMNS FROM `spawn_events` LIKE 'strict'|empty|
9035|2014_04_27_AISpellEffects.sql|SHOW COLUMNS FROM `npc_types` LIKE 'npc_spells_effects_id'|empty|
9036|2014_05_04_SlowMitigationFix.sql|SHOW COLUMNS FROM `npc_types` LIKE 'slow_mitigation'|contains|float
9038|2014_06_25_AA_Updates.sql|SELECT * FROM `altadv_vars` WHERE `skill_id` = '1604'|empty
9039|2014_07_04_AA_Updates.sql|SELECT * FROM `aa_effects` WHERE `aaid` = '158' AND `slot` = '1' AND `effectid` = '238'|empty
9040|2014_07_10_npc_spells.sql|SHOW COLUMNS FROM `npc_spells` LIKE 'engaged_no_sp_recast_min'|empty|
9041|2014_08_02_spells_new.sql|SHOW COLUMNS FROM `spells_new` LIKE 'viral_range'|empty|
9042|2014_08_12_NPC_raid_targets.sql|SHOW COLUMNS FROM `npc_types` LIKE 'raid_target'|empty|
9043|2014_08_18_spells_new_update.sql|SHOW COLUMNS FROM `spells_new` LIKE 'viral_targets'|empty|
9044|2014_08_20_merchantlist_probability.sql|SHOW COLUMNS FROM `merchantlist` LIKE 'probability'|empty|
9045|2014_08_23_Complete_QueryServ_Table_Structures.sql|SHOW TABLES LIKE 'qs_player_aa_rate_hourly'|empty|
9046|2014_08_23_player_events_and_player_aa_rate_hourly.sql|SHOW TABLES LIKE 'qs_player_events'|empty|
9048|2014_09_09_attack_delay.sql|SHOW COLUMNS FROM `npc_types` LIKE 'attack_delay'|empty|
9050|2014_09_20_ban_messages.sql|SHOW COLUMNS FROM `account` LIKE 'ban_reason'|empty|
9051|2014_10_11_RaidMOTD.sql|SHOW COLUMNS FROM `raid_details` LIKE 'motd'|empty|
9052|2014_10_13_RaidLeadership.sql|SHOW TABLES LIKE 'raid_leaders'|empty|
9053|2014_10_18_group_mentor.sql|SHOW COLUMNS FROM `group_leaders` LIKE 'mentoree'|empty|
9054|2014_10_19_raid_group_mentor.sql|SHOW COLUMNS FROM `raid_leaders` LIKE 'mentoree'|empty|
9055|2014_10_30_special_abilities_null.sql|SHOW COLUMNS FROM `npc_types` LIKE 'special_abilities'|contains|NO
9056|2014_11_08_RaidMembers.sql|SHOW COLUMNS FROM `raid_members` LIKE 'groupid'|missing|unsigned
9057|2014_11_13_spells_new_updates.sql|SHOW COLUMNS FROM `spells_new` LIKE 'disallow_sit'|empty|
# Upgrade conditions:
# This won't be needed after this system is implemented, but it is used database that are not
# yet using the versioning system to figure out where the database is schema wise to determine
# which updates are necessary to run
#
# Example: Version|Filename.sql|Query_to_Check_Condition_For_Needed_Update|match type|text to match
# 0 = Database Version
# 1 = Filename.sql
# 2 = Query_to_Check_Condition_For_Needed_Update
# 3 = Match Type - If condition from match type to Value 4 is true, update will flag for needing to be ran
# contains = If query results contains text from 4th value
# match = If query results matches text from 4th value
# missing = If query result is missing text from 4th value
# empty = If the query results in no results
# not_empty = If the query is not empty
# 4 = Text to match
#
#

View File

@ -1,4 +1,5 @@
ALTER TABLE `npc_types` ADD COLUMN `special_abilities` TEXT NOT NULL DEFAULT '' AFTER `npcspecialattks`;
ALTER TABLE `npc_types` ADD COLUMN `special_abilities` TEXT NULL AFTER `npcspecialattks`;
ALTER TABLE `npc_types` MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL;
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "1,1^") WHERE npcspecialattks LIKE BINARY '%S%';
UPDATE npc_types SET special_abilities = CONCAT(special_abilities, "2,1^") WHERE npcspecialattks LIKE BINARY '%E%';

View File

@ -1,4 +1,5 @@
ALTER TABLE `merc_stats` ADD COLUMN `special_abilities` TEXT NOT NULL DEFAULT '' AFTER `specialattks`;
ALTER TABLE `merc_stats` ADD COLUMN `special_abilities` TEXT NULL AFTER `specialattks`;
ALTER TABLE `merc_stats` MODIFY COLUMN `special_abilities` text CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL;
UPDATE merc_stats SET special_abilities = CONCAT(special_abilities, "1,1^") WHERE specialattks LIKE BINARY '%S%';
UPDATE merc_stats SET special_abilities = CONCAT(special_abilities, "2,1^") WHERE specialattks LIKE BINARY '%E%';

View File

@ -1,34 +0,0 @@
-- AA MGB update
UPDATE altadv_vars SET spellid = 5228 WHERE skill_id = 128;
UPDATE aa_actions SET spell_id = 5228, nonspell_action = 0 WHERE aaid = 128;
-- AA Project Illusion update
UPDATE altadv_vars SET spellid = 5227 WHERE skill_id = 643;
UPDATE aa_actions SET spell_id = 5227, nonspell_action = 0 WHERE aaid = 643;
-- AA Improved Reclaim Energy
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('180', '1', '241', '95', '0');
-- AA Headshot
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '1', '217', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('644', '2', '346', '46', '0');
-- AA Anatomy (Rogue Assassinate)
INSERT INTO `altadv_vars` (`skill_id`, `name`, `cost`, `max_level`, `hotkey_sid`, `hotkey_sid2`, `title_sid`, `desc_sid`, `type`, `spellid`, `prereq_skill`, `prereq_minpoints`, `spell_type`, `spell_refresh`, `classes`, `berserker`, `class_type`, `cost_inc`, `aa_expansion`, `special_category`, `sof_type`, `sof_cost_inc`, `sof_max_level`, `sof_next_skill`, `clientver`, `account_time_required`, `sof_current_level`,`sof_next_id`,`level_inc`) VALUES ('1604', 'Anatomy', '5', '3', '4294967295', '4294967295', '1604', '1604', '1', '4294967295', '0', '0', '0', '0', '512', '0', '60', '1', '10', '4294967295', '3', '0', '3', '1604', '1', '0', '0', '0', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1604', '2', '345', '48', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1605', '2', '345', '51', '0');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '1', '439', '0', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('1606', '2', '345', '53', '0');
-- AA Finishing Blow Fix
DELETE FROM aa_effects WHERE aaid = 199 AND slot = 2;
DELETE FROM aa_effects WHERE aaid = 200 AND slot = 2;
DELETE FROM aa_effects WHERE aaid = 201 AND slot = 2;
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '1', '278', '500', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('119', '2', '440', '50', '200');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '1', '278', '500', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('120', '2', '440', '52', '200');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '1', '278', '500', '32000');
INSERT INTO `aa_effects` (`aaid`, `slot`, `effectid`, `base1`, `base2`) VALUES ('121', '2', '440', '54', '200');

View File

@ -1 +1 @@
ALTER TABLE `account` ADD COLUMN `ban_reason` TEXT NULL DEFAULT NULL AFTER `expansion`, ADD COLUMN `suspend_reason` TEXT NULL DEFAULT NULL AFTER `ban_reason`;
ALTER TABLE `account` ADD COLUMN `ban_reason` TEXT NULL DEFAULT NULL, ADD COLUMN `suspend_reason` TEXT NULL DEFAULT NULL AFTER `ban_reason`;

View File

@ -111,6 +111,15 @@ int main(int argc, char** argv) {
RegisterExecutablePlatform(ExePlatformWorld);
set_exception_handler();
/* Database Version Check */
uint32 Database_Version = CURRENT_BINARY_DATABASE_VERSION;
if (argc >= 2) {
if (strcasecmp(argv[1], "db_version") == 0) {
std::cout << "Binary Database Version: " << Database_Version << std::endl;
return 0;
}
}
// Load server configuration
_log(WORLD__INIT, "Loading server configuration..");
if (!WorldConfig::LoadConfig()) {

View File

@ -7296,26 +7296,24 @@ void Client::SendMercPersonalInfo()
{
uint32 mercTypeCount = 1;
uint32 mercCount = 1; //TODO: Un-hardcode this and support multiple mercs like in later clients than SoD.
//uint32 packetSize = 0;
uint32 i=0;
uint32 i = 0;
uint32 altCurrentType = 19; //TODO: Implement alternate currency purchases involving mercs!
if (GetClientVersion() >= EQClientRoF)
{
MercTemplate *mercData = &zone->merc_templates[GetMercInfo().MercTemplateID];
if (mercData)
{
int i = 0;
int stancecount = 0;
stancecount += zone->merc_stance_list[GetMercInfo().MercTemplateID].size();
if(stancecount > MAX_MERC_STANCES || mercCount > MAX_MERC || mercTypeCount > MAX_MERC_GRADES)
{
SendMercMerchantResponsePacket(0);
return;
}
if (mercCount > 0 && mercCount)
if(mercData)
{
if (GetClientVersion() >= EQClientRoF)
{
if (mercCount > 0)
{
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataUpdate, sizeof(MercenaryDataUpdate_Struct));
MercenaryDataUpdate_Struct* mdus = (MercenaryDataUpdate_Struct*)outapp->pBuffer;
@ -7353,40 +7351,19 @@ void Client::SendMercPersonalInfo()
mdus->MercData[i].MercUnk05 = 1;
FastQueuePacket(&outapp);
safe_delete(outapp);
return;
}
}
}
else
{
int stancecount = 0;
stancecount += zone->merc_stance_list[GetMercInfo().MercTemplateID].size();
if(mercCount > MAX_MERC || mercTypeCount > MAX_MERC_GRADES)
if(mercTypeCount > 0 && mercCount > 0)
{
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
return;
}
EQApplicationPacket *outapp = new EQApplicationPacket(OP_MercenaryDataResponse, sizeof(MercenaryMerchantList_Struct));
MercenaryMerchantList_Struct* mml = (MercenaryMerchantList_Struct*)outapp->pBuffer;
MercTemplate *mercData = &zone->merc_templates[GetMercInfo().MercTemplateID];
if(mercData)
{
if(mercTypeCount > 0)
{
mml->MercTypeCount = mercTypeCount; //We only should have one merc entry.
mml->MercTypeCount = mercTypeCount; //We should only have one merc entry.
mml->MercGrades[i] = 1;
}
mml->MercCount = mercCount;
if(mercCount > 0)
{
mml->Mercs[i].MercID = mercData->MercTemplateID;
mml->Mercs[i].MercType = mercData->MercType;
mml->Mercs[i].MercSubType = mercData->MercSubType;
@ -7403,7 +7380,7 @@ void Client::SendMercPersonalInfo()
mml->Mercs[i].StanceCount = zone->merc_stance_list[mercData->MercTemplateID].size();
mml->Mercs[i].MercUnk03 = 0;
mml->Mercs[i].MercUnk04 = 1;
//mml->Mercs[i].MercName;
strn0cpy(mml->Mercs[i].MercName, GetMercInfo().merc_name , sizeof(mml->Mercs[i].MercName));
int stanceindex = 0;
if(mml->Mercs[i].StanceCount != 0)
{
@ -7417,31 +7394,12 @@ void Client::SendMercPersonalInfo()
}
}
FastQueuePacket(&outapp);
}
else
{
safe_delete(outapp);
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
return;
}
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
}
else
{
safe_delete(outapp);
if (GetClientVersion() == EQClientSoD)
{
SendMercMerchantResponsePacket(0);
}
return;
}
}
}
SendMercMerchantResponsePacket(0);
}
void Client::SendClearMercInfo()

View File

@ -829,11 +829,11 @@ public:
bool Hungry() const {if (GetGM()) return false; return m_pp.hunger_level <= 3000;}
bool Thirsty() const {if (GetGM()) return false; return m_pp.thirst_level <= 3000;}
int32 GetHunger() const { return m_pp.hunger_level; }
int32 GetThirst() const { return m_pp.thirst_level; }
void SetHunger(int32 in_hunger);
void SetThirst(int32 in_thirst);
void SetConsumption(int32 in_hunger, int32 in_thirst);
int32 GetHunger() const { return m_pp.hunger_level; }
int32 GetThirst() const { return m_pp.thirst_level; }
void SetHunger(int32 in_hunger);
void SetThirst(int32 in_thirst);
void SetConsumption(int32 in_hunger, int32 in_thirst);
bool CheckTradeLoreConflict(Client* other);
void LinkDead();
@ -1129,6 +1129,7 @@ public:
void RemoveAutoXTargets();
void ShowXTargets(Client *c);
void InitializeMercInfo();
bool CheckCanSpawnMerc(uint32 template_id);
bool CheckCanHireMerc(Mob* merchant, uint32 template_id);
bool CheckCanRetainMerc(uint32 upkeep);
bool CheckCanUnsuspendMerc();
@ -1142,9 +1143,11 @@ public:
MercInfo& GetMercInfo() { return m_mercinfo[mercSlot]; }
uint8 GetNumMercs();
void SetMerc(Merc* newmerc);
void SendMercResponsePackets(uint32 ResponseType);
void SendMercMerchantResponsePacket(int32 response_type);
void SendMercenaryUnknownPacket(uint8 type);
void SendMercenaryUnsuspendPacket(uint8 type);
void SendMercTimer(Merc* merc = nullptr);
void SendMercTimerPacket(int32 entity_id, int32 merc_state, int32 suspended_time, int32 update_interval = 900000, int32 unk01 = 180000);
void SendMercSuspendResponsePacket(uint32 suspended_time);
void SendMercAssignPacket(uint32 entityID, uint32 unk01, uint32 unk02);
@ -1538,4 +1541,3 @@ private:
};
#endif

View File

@ -3034,47 +3034,23 @@ void Client::Handle_OP_AssistGroup(const EQApplicationPacket *app)
void Client::Handle_OP_AugmentInfo(const EQApplicationPacket *app)
{
// This packet is sent by the client when an Augment item information window is opened.
// We respond with an OP_ReadBook containing the type of distiller required to remove the augment.
// The OP_Augment packet includes a window parameter to determine which Item window in the UI the
// text is to be displayed in. out->type = 2 indicates the BookText_Struct contains item information.
//
// Some clients this seems to nuke the charm text (ex. Adventurer's Stone)
if (app->size != sizeof(AugmentInfo_Struct))
{
if (app->size != sizeof(AugmentInfo_Struct)) {
LogFile->write(EQEMuLog::Debug, "Size mismatch in OP_AugmentInfo expected %i got %i",
sizeof(AugmentInfo_Struct), app->size);
DumpPacket(app);
return;
}
AugmentInfo_Struct* AugInfo = (AugmentInfo_Struct*)app->pBuffer;
char *outstring = nullptr;
const Item_Struct * item = database.GetItem(AugInfo->itemid);
if (item)
{
MakeAnyLenString(&outstring, "You must use the solvent %s to remove this augment safely.", item->Name);
EQApplicationPacket* outapp = new EQApplicationPacket(OP_ReadBook, strlen(outstring) + sizeof(BookText_Struct));
BookText_Struct *out = (BookText_Struct *)outapp->pBuffer;
out->window = AugInfo->window;
out->type = 2;
out->invslot = 0;
strcpy(out->booktext, outstring);
safe_delete_array(outstring);
FastQueuePacket(&outapp);
if (item) {
strn0cpy(AugInfo->augment_info, item->Name, 64);
AugInfo->itemid = 0;
QueuePacket(app);
}
}
@ -3842,19 +3818,23 @@ void Client::Handle_OP_BlockedBuffs(const EQApplicationPacket *app)
void Client::Handle_OP_BoardBoat(const EQApplicationPacket *app)
{
if (app->size <= 5)
// this sends unclean mob name, so capped at 64
// a_boat006
if (app->size <= 5 || app->size > 64) {
LogFile->write(EQEMuLog::Error, "Size mismatch in OP_BoardBoad. Expected greater than 5 less than 64, got %i", app->size);
DumpPacket(app);
return;
}
char *boatname;
boatname = new char[app->size - 3];
memset(boatname, 0, app->size - 3);
memcpy(boatname, app->pBuffer, app->size - 4);
char boatname[64];
memcpy(boatname, app->pBuffer, app->size);
boatname[63] = '\0';
Mob* boat = entity_list.GetMob(boatname);
if (boat)
this->BoatID = boat->GetID(); // set the client's BoatID to show that it's on this boat
safe_delete_array(boatname);
if (!boat || (boat->GetRace() != CONTROLLED_BOAT && boat->GetRace() != 502))
return;
BoatID = boat->GetID(); // set the client's BoatID to show that it's on this boat
return;
}
@ -9719,17 +9699,13 @@ void Client::Handle_OP_MercenaryDismiss(const EQApplicationPacket *app)
Message(7, "Mercenary Debug: Dismiss Request ( %i ) Received.", Command);
// Handle the dismiss here...
if (GetMercID()) {
Merc* merc = GetMerc();
if (merc) {
if (CheckCanDismissMerc()) {
merc->Dismiss();
}
}
}
//SendMercMerchantResponsePacket(10);
}
void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
@ -9769,21 +9745,22 @@ void Client::Handle_OP_MercenaryHire(const EQApplicationPacket *app)
return;
}
if (RuleB(Mercs, ChargeMercPurchaseCost)) {
uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold
TakeMoneyFromPP(cost, true);
}
// Set time remaining to max on Hire
GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS);
// Get merc, assign it to client & spawn
Merc* merc = Merc::LoadMerc(this, merc_template, merchant_id, false);
if (merc) {
if (merc)
{
SpawnMerc(merc, true);
merc->Save();
if (RuleB(Mercs, ChargeMercPurchaseCost)) {
uint32 cost = Merc::CalcPurchaseCost(merc_template->MercTemplateID, GetLevel()) * 100; // Cost is in gold
TakeMoneyFromPP(cost, true);
}
// 0 is approved hire request
SendMercMerchantResponsePacket(0);
}

View File

@ -78,7 +78,8 @@ bool Client::Process() {
if(Connected() || IsLD())
{
// try to send all packets that weren't sent before
if(!IsLD() && zoneinpacket_timer.Check()){
if(!IsLD() && zoneinpacket_timer.Check())
{
SendAllPackets();
}
@ -145,7 +146,9 @@ bool Client::Process() {
if(mana_timer.Check())
SendManaUpdatePacket();
if(dead && dead_timer.Check()) {
if(dead && dead_timer.Check())
{
database.MoveCharacterToZone(GetName(),database.GetZoneName(m_pp.binds[0].zoneId));
m_pp.zone_id = m_pp.binds[0].zoneId;
m_pp.zoneInstance = 0;
@ -176,14 +179,16 @@ bool Client::Process() {
if(TaskPeriodic_Timer.Check() && taskstate)
taskstate->TaskPeriodicChecks(this);
if(linkdead_timer.Check()){
if(linkdead_timer.Check())
{
LeaveGroup();
Save();
if (GetMerc())
{
GetMerc()->Save();
GetMerc()->Depop();
}
LeaveGroup();
Raid *myraid = entity_list.GetRaidByClient(this);
if (myraid)
{
@ -192,7 +197,8 @@ bool Client::Process() {
return false; //delete client
}
if (camp_timer.Check()) {
if (camp_timer.Check())
{
LeaveGroup();
Save();
if (GetMerc())
@ -228,7 +234,7 @@ bool Client::Process() {
} else {
if(!ApplyNextBardPulse(bardsong, song_target, bardsong_slot))
InterruptSpell(SONG_ENDS_ABRUPTLY, 0x121, bardsong);
// SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
//SpellFinished(bardsong, bardsong_target, bardsong_slot, spells[bardsong].mana);
}
}
@ -239,7 +245,9 @@ bool Client::Process() {
if(GetMercInfo().MercTemplateID != 0 && GetMercInfo().IsSuspended)
{
if(p_timers.Expired(&database, pTimerMercSuspend, false)) {
//CheckMercSuspendTimer();
if(p_timers.Expired(&database, pTimerMercSuspend, false))
{
CheckMercSuspendTimer();
}
}
@ -715,16 +723,13 @@ bool Client::Process() {
}
#endif
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED))) {
if (client_state != CLIENT_LINKDEAD && (client_state == CLIENT_ERROR || client_state == DISCONNECTED || client_state == CLIENT_KICKED || !eqs->CheckState(ESTABLISHED)))
{
//client logged out or errored out
//ResetTrade();
if (client_state != CLIENT_KICKED) {
Save();
}
if (GetMerc())
{
GetMerc()->Depop();
}
client_state = CLIENT_LINKDEAD;
if (zoning || instalog || GetGM())
@ -732,23 +737,32 @@ bool Client::Process() {
Group *mygroup = GetGroup();
if (mygroup)
{
if (!zoning) {
if (!zoning)
{
entity_list.MessageGroup(this, true, 15, "%s logged out.", GetName());
mygroup->DelMember(this);
} else {
LeaveGroup();
}
else
{
entity_list.MessageGroup(this, true, 15, "%s left the zone.", GetName());
mygroup->MemberZoned(this);
if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == mygroup)
{
mygroup->DelMember(GetMerc());
}
}
}
Raid *myraid = entity_list.GetRaidByClient(this);
if (myraid)
{
if (!zoning) {
if (!zoning)
{
//entity_list.MessageGroup(this,true,15,"%s logged out.",GetName());
//mygroup->DelMember(this);
myraid->MemberZoned(this);
} else {
}
else
{
//entity_list.MessageGroup(this,true,15,"%s left the zone.",GetName());
myraid->MemberZoned(this);
}
@ -774,8 +788,14 @@ bool Client::Process() {
/* Just a set of actions preformed all over in Client::Process */
void Client::OnDisconnect(bool hard_disconnect) {
if(hard_disconnect) {
if(hard_disconnect)
{
LeaveGroup();
if (GetMerc())
{
GetMerc()->Save();
GetMerc()->Depop();
}
Raid *MyRaid = entity_list.GetRaidByClient(this);
if (MyRaid)
@ -791,7 +811,8 @@ void Client::OnDisconnect(bool hard_disconnect) {
}
Mob *Other = trade->With();
if(Other) {
if(Other)
{
mlog(TRADING__CLIENT, "Client disconnected during a trade. Returning their items.");
FinishTrade(this);

View File

@ -1069,14 +1069,29 @@ void Group::GroupMessage_StringID(Mob* sender, uint32 type, uint32 string_id, co
void Client::LeaveGroup() {
Group *g = GetGroup();
if(g) {
if(g)
{
if(g->GroupCount() < 3)
{
g->DisbandGroup();
}
else
{
g->DelMember(this);
} else {
if (GetMerc() && GetMerc()->HasGroup() && GetMerc()->GetGroup() == g)
{
g->DelMember(GetMerc());
}
}
}
else
{
//force things a little
database.SetGroupID(GetName(), 0, CharacterID());
if (GetMerc())
{
database.SetGroupID(GetMerc()->GetName(), 0, CharacterID());
}
}
isgrouped = false;

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,12 @@
#define HEALER 2
#define MELEEDPS 9
#define CASTERDPS 12
#define NO_MERC_ID 0
#define MERC_STATE_NORMAL 5
#define MERC_STATE_SUSPENDED 1
#define NOT_SUSPENDED_TIME 0
const int MercAISpellRange = 100; // TODO: Write a method that calcs what the merc's spell range is based on spell, equipment, AA, whatever and replace this
enum MercStanceType {
@ -126,7 +132,7 @@ public:
static Merc* LoadMerc(Client *c, MercTemplate* merc_template, uint32 merchant_id, bool updateFromDB = false);
void UpdateMercInfo(Client *c);
void UpdateMercStats(Client *c);
void UpdateMercAppearance(Client *c);
void UpdateMercAppearance();
void AddItem(uint8 slot, uint32 item_id);
static const char *GetRandomName();
bool Spawn(Client *owner);
@ -139,8 +145,8 @@ public:
bool GetDepop() { return p_depop; }
bool IsDead() { return GetHP() < 0;};
bool IsMedding() {return _medding; };
bool IsSuspended() {return _suspended; };
bool IsMedding() { return _medding; };
bool IsSuspended() { return _suspended; };
static uint32 CalcPurchaseCost( uint32 templateID , uint8 level, uint8 currency_type = 0);
static uint32 CalcUpkeepCost( uint32 templateID , uint8 level, uint8 currency_type = 0);
@ -329,6 +335,7 @@ private:
void GetMercSize();
void GenerateAppearance();
bool LoadMercSpells();
bool CheckStance(int16 stance);
std::vector<MercSpell> GetMercSpells() { return merc_spells; }

View File

@ -400,7 +400,7 @@ void Zone::LoadTempMerchantData() {
LogFile->write(EQEMuLog::Status, "Loading Temporary Merchant Lists...");
std::string query = StringFormat(
"SELECT "
"ml.npcid, "
"DISTINCT ml.npcid, "
"ml.slot, "
"ml.charges, "
"ml.itemid "

View File

@ -2107,9 +2107,6 @@ const NPCType* ZoneDatabase::GetMercType(uint32 id, uint16 raceid, uint32 client
bool ZoneDatabase::LoadMercInfo(Client *client) {
if(client->GetEPP().merc_name[0] == 0)
return false;
std::string query = StringFormat("SELECT MercID, Slot, Name, TemplateID, SuspendedTime, "
"IsSuspended, TimerRemaining, Gender, StanceID, HP, Mana, "
"Endurance, Face, LuclinHairStyle, LuclinHairColor, "
@ -2120,6 +2117,9 @@ bool ZoneDatabase::LoadMercInfo(Client *client) {
if (!results.Success())
return false;
if(results.RowCount() == 0)
return false;
for (auto row = results.begin(); row != results.end(); ++row) {
uint8 slot = atoi(row[1]);
@ -2156,9 +2156,6 @@ bool ZoneDatabase::LoadMercInfo(Client *client) {
bool ZoneDatabase::LoadCurrentMerc(Client *client) {
if(client->GetEPP().merc_name[0] == 0)
return false;
uint8 slot = client->GetMercSlot();
if(slot > MAXMERCS)
@ -2176,6 +2173,9 @@ bool ZoneDatabase::LoadCurrentMerc(Client *client) {
if(!results.Success())
return false;
if(results.RowCount() == 0)
return false;
for (auto row = results.begin(); row != results.end(); ++row) {
client->GetMercInfo(slot).mercid = atoi(row[0]);
@ -2211,9 +2211,9 @@ bool ZoneDatabase::SaveMerc(Merc *merc) {
if(!owner)
return false;
if(merc->GetMercID() == 0) {
if(merc->GetMercID() == 0)
{
// New merc record
uint32 TempNewMercID = 0;
std::string query = StringFormat("INSERT INTO mercs "
"(OwnerCharacterID, Slot, Name, TemplateID, "
"SuspendedTime, IsSuspended, TimerRemaining, "
@ -2234,6 +2234,7 @@ bool ZoneDatabase::SaveMerc(Merc *merc) {
merc->GetEyeColor2(), merc->GetBeardColor(),
merc->GetBeard(), merc->GetDrakkinHeritage(),
merc->GetDrakkinTattoo(), merc->GetDrakkinDetails());
auto results = database.QueryDatabase(query);
if(!results.Success()) {
owner->Message(13, results.ErrorMessage().c_str());
@ -2243,7 +2244,7 @@ bool ZoneDatabase::SaveMerc(Merc *merc) {
return false;
}
merc->SetMercID(TempNewMercID);
merc->SetMercID(results.LastInsertedID());
merc->UpdateMercInfo(owner);
database.SaveMercBuffs(merc);
return true;
@ -2266,6 +2267,7 @@ bool ZoneDatabase::SaveMerc(Merc *merc) {
merc->GetHairColor(), merc->GetEyeColor1(), merc->GetEyeColor2(),
merc->GetBeardColor(), merc->GetBeard(), merc->GetDrakkinHeritage(),
merc->GetDrakkinTattoo(), merc->GetDrakkinDetails(), merc->GetMercID());
auto results = database.QueryDatabase(query);
if (!results.Success()) {
owner->Message(13, results.ErrorMessage().c_str());
@ -2388,23 +2390,25 @@ bool ZoneDatabase::DeleteMerc(uint32 merc_id) {
if(merc_id == 0)
return false;
bool firstQueryWorked = false;
// TODO: These queries need to be ran together as a transaction.. ie,
// if one or more fail then they all will fail to commit to the database.
std::string query = StringFormat("DELETE FROM merc_buffs WHERE MercID = '%u'", merc_id);
// ...Not all mercs will have buffs, so why is it required that both deletes succeed?
std::string query = StringFormat("DELETE FROM merc_buffs WHERE MercId = '%u'", merc_id);
auto results = database.QueryDatabase(query);
if(!results.Success())
LogFile->write(EQEMuLog::Error, "Error Deleting Merc: %s", results.ErrorMessage().c_str());
else
firstQueryWorked = true;
{
LogFile->write(EQEMuLog::Error, "Error Deleting Merc Buffs: %s", results.ErrorMessage().c_str());
}
query = StringFormat("DELETE FROM mercs WHERE MercID = '%u'", merc_id);
if(!results.Success()) {
results = database.QueryDatabase(query);
if(!results.Success())
{
LogFile->write(EQEMuLog::Error, "Error Deleting Merc: %s", results.ErrorMessage().c_str());
return false;
}
return firstQueryWorked;
return true;
}
void ZoneDatabase::LoadMercEquipment(Merc *merc) {