· 9 years ago · Aug 14, 2017, 04:36 PM
1#!/usr/bin/perl
2
3###########################################################
4#::: Automatic (Database) Upgrade Script
5#::: Author: Akkadius
6#::: Purpose: To upgrade databases with ease and maintain versioning
7###########################################################
8
9$menu_displayed = 0;
10
11use Config;
12use File::Copy qw(copy);
13use POSIX qw(strftime);
14use File::Path;
15use File::Find;
16use URI::Escape;
17use Time::HiRes qw(usleep);
18
19$time_stamp = strftime('%m-%d-%Y', gmtime());
20
21$console_output .= " Operating System is: $Config{osname}\n";
22if($Config{osname}=~/linux/i){ $OS = "Linux"; }
23if($Config{osname}=~/Win|MS/i){ $OS = "Windows"; }
24
25#::: If current version is less than what world is reporting, then download a new one...
26$current_version = 14;
27
28if($ARGV[0] eq "V"){
29 if($ARGV[1] > $current_version){
30 print "eqemu_update.pl Automatic Database Upgrade Needs updating...\n";
31 print " Current version: " . $current_version . "\n";
32 print " New version: " . $ARGV[1] . "\n";
33 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl");
34 exit;
35 }
36 else{
37 print "[Upgrade Script] No script update necessary \n";
38 }
39 exit;
40}
41
42#::: Sets database run stage check
43$db_run_stage = 0;
44
45$perl_version = $^V;
46$perl_version =~s/v//g;
47print "Perl Version is " . $perl_version . "\n";
48if($perl_version > 5.12){ no warnings 'uninitialized'; }
49no warnings;
50
51($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime();
52
53my $confile = "eqemu_config.xml"; #default
54open(F, "<$confile");
55my $indb = 0;
56while(<F>) {
57 s/\r//g;
58 if(/<database>/i) { $indb = 1; }
59 next unless($indb == 1);
60 if(/<\/database>/i) { $indb = 0; last; }
61 if(/<host>(.*)<\/host>/i) { $host = $1; }
62 elsif(/<username>(.*)<\/username>/i) { $user = $1; }
63 elsif(/<password>(.*)<\/password>/i) { $pass = $1; }
64 elsif(/<db>(.*)<\/db>/i) { $db = $1; }
65}
66
67$console_output =
68"============================================================
69 EQEmu: Automatic Upgrade Check
70============================================================
71";
72
73if($OS eq "Windows"){
74 $has_mysql_path = `echo %PATH%`;
75 if($has_mysql_path=~/MySQL|MariaDB/i){
76 @mysql = split(';', $has_mysql_path);
77 foreach my $v (@mysql){
78 if($v=~/MySQL|MariaDB/i){
79 $v =~s/\n//g;
80 $path = trim($v) . "/mysql";
81 last;
82 }
83 }
84 $console_output .= " (Windows) MySQL is in system path \n";
85 $console_output .= " Path = " . $path . "\n";
86 $console_output .= "============================================================\n";
87 }
88}
89
90#::: Linux Check
91if($OS eq "Linux"){
92 $path = `which mysql`;
93 if ($path eq "") {
94 $path = `which mariadb`;
95 }
96 $path =~s/\n//g;
97
98 $console_output .= " (Linux) MySQL is in system path \n";
99 $console_output .= " Path = " . $path . "\n";
100 $console_output .= "============================================================\n";
101}
102
103#::: Path not found, error and exit
104if($path eq ""){
105 print "MySQL path not found, please add the path for automatic database upgrading to continue... \n\n";
106 print "script_exiting...\n";
107 exit;
108}
109
110if($ARGV[0] eq "install_peq_db"){
111
112 $db_name = "peq";
113 if($ARGV[1]){
114 $db_name = $ARGV[1];
115 }
116
117 $db = $db_name;
118
119 #::: Database Routines
120 print "MariaDB :: Creating Database '" . $db_name . "'\n";
121 print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS $db_name;"`;
122 print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE $db_name"`;
123 if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
124 if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
125 $bin_db_ver = trim($db_version[1]);
126 check_db_version_table();
127 $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
128 fetch_peq_db_full();
129 print "\nFetching Latest Database Updates...\n";
130 main_db_management();
131 print "\nApplying Latest Database Updates...\n";
132 main_db_management();
133
134 print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'");
135}
136
137if($ARGV[0] eq "remove_duplicate_rules"){
138 remove_duplicate_rule_values();
139 exit;
140}
141
142if($ARGV[0] eq "installer"){
143 print "Running EQEmu Server installer routines...\n";
144 mkdir('logs');
145 mkdir('updates_staged');
146 mkdir('shared');
147 fetch_latest_windows_binaries();
148 map_files_fetch_bulk();
149 opcodes_fetch();
150 plugins_fetch();
151 quest_files_fetch();
152 lua_modules_fetch();
153
154 #::: Binary dll's
155 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1);
156 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/zlib1.dll", "zlib1.dll", 1);
157 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/libmysql.dll", "libmysql.dll", 1);
158
159 #::: Server scripts
160 fetch_utility_scripts();
161
162 #::: Database Routines
163 print "MariaDB :: Creating Database 'peq'\n";
164 print `"$path" --host $host --user $user --password="$pass" -N -B -e "DROP DATABASE IF EXISTS peq;"`;
165 print `"$path" --host $host --user $user --password="$pass" -N -B -e "CREATE DATABASE peq"`;
166 if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
167 if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
168 $bin_db_ver = trim($db_version[1]);
169 check_db_version_table();
170 $local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
171 fetch_peq_db_full();
172 print "\nFetching Latest Database Updates...\n";
173 main_db_management();
174 print "\nApplying Latest Database Updates...\n";
175 main_db_management();
176
177 print get_mysql_result("UPDATE `launcher` SET `dynamics` = 30 WHERE `name` = 'zone'");
178
179 if($OS eq "Windows"){
180 check_windows_firewall_rules();
181 do_windows_login_server_setup();
182 }
183 exit;
184}
185
186if($ARGV[0] eq "db_dump_compress"){ database_dump_compress(); exit; }
187if($ARGV[0] eq "login_server_setup"){
188 do_windows_login_server_setup();
189 exit;
190}
191
192#::: Create db_update working directory if not created
193mkdir('db_update');
194
195#::: Check if db_version table exists...
196if(trim(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'Revision'")) ne "" && $db){
197 print get_mysql_result("DROP TABLE db_version");
198 print "Old db_version table present, dropping...\n\n";
199}
200
201sub check_db_version_table{
202 if(get_mysql_result("SHOW TABLES LIKE 'db_version'") eq "" && $db){
203 print get_mysql_result("
204 CREATE TABLE db_version (
205 version int(11) DEFAULT '0'
206 ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
207 INSERT INTO db_version (version) VALUES ('1000');");
208 print "Table 'db_version' does not exists.... Creating...\n\n";
209 }
210}
211
212check_db_version_table();
213
214if($OS eq "Windows"){ @db_version = split(': ', `world db_version`); }
215if($OS eq "Linux"){ @db_version = split(': ', `./world db_version`); }
216
217$bin_db_ver = trim($db_version[1]);
218$local_db_ver = trim(get_mysql_result("SELECT version FROM db_version LIMIT 1"));
219
220#::: If ran from Linux startup script, supress output
221if($bin_db_ver == $local_db_ver && $ARGV[0] eq "ran_from_start"){
222 print "Database up to date...\n";
223 exit;
224}
225else{
226 print $console_output if $db;
227}
228
229if($db){
230 print " Binary Revision / Local: (" . $bin_db_ver . " / " . $local_db_ver . ")\n";
231
232 #::: Bots
233 #::: Make sure we're running a bots binary to begin with
234 if(trim($db_version[2]) > 0){
235 $bots_local_db_version = get_bots_db_version();
236 if($bots_local_db_version > 0){
237 print " (Bots) Binary Revision / Local: (" . trim($db_version[2]) . " / " . $bots_local_db_version . ")\n";
238 }
239 }
240
241 #::: If World ran this script, and our version is up to date, continue...
242 if($bin_db_ver <= $local_db_ver && $ARGV[0] eq "ran_from_world"){
243 print " Database up to Date: Continuing World Bootup...\n";
244 print "============================================================\n";
245 exit;
246 }
247
248}
249
250if($local_db_ver < $bin_db_ver && $ARGV[0] eq "ran_from_world"){
251 print "You have missing database updates, type 1 or 2 to backup your database before running them as recommended...\n\n";
252 #::: Display Menu
253 show_menu_prompt();
254}
255else{
256 #::: Most likely ran standalone
257 print "\n";
258 show_menu_prompt();
259}
260
261sub do_update_self{
262 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_update.pl", "eqemu_update.pl");
263 die "Rerun eqemu_update.pl";
264}
265
266sub fetch_utility_scripts {
267 if($OS eq "Windows"){
268 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_database_backup.bat", "t_database_backup.bat");
269 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_start_server.bat", "t_start_server.bat");
270 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_start_server_with_login_server.bat", "t_start_server_with_login_server.bat");
271 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_stop_server.bat", "t_stop_server.bat");
272 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_server_crash_report.pl", "t_server_crash_report.pl");
273 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/win_server_launcher.pl", "win_server_launcher.pl");
274 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/t_start_server_with_login_server.bat", "t_start_server_with_login_server.bat");
275 }
276 else {
277 print "No scripts found for OS: " . $OS . "...\n";
278 }
279}
280
281sub show_menu_prompt {
282 my %dispatch = (
283 1 => \&database_dump,
284 2 => \&database_dump_compress,
285 3 => \&main_db_management,
286 4 => \&bots_db_management,
287 5 => \&opcodes_fetch,
288 6 => \&map_files_fetch,
289 7 => \&plugins_fetch,
290 8 => \&quest_files_fetch,
291 9 => \&lua_modules_fetch,
292 10 => \&aa_fetch,
293 11 => \&fetch_latest_windows_binaries,
294 12 => \&fetch_server_dlls,
295 13 => \&do_windows_login_server_setup,
296 14 => \&remove_duplicate_rule_values,
297 15 => \&fetch_utility_scripts,
298 19 => \&do_bots_db_schema_drop,
299 20 => \&do_update_self,
300 0 => \&script_exit,
301 );
302
303 while (1) {
304 {
305 local $| = 1;
306 if(!$menu_show && ($ARGV[0] eq "ran_from_world" || $ARGV[0] eq "ran_from_start")){
307 $menu_show++;
308 next;
309 }
310 print menu_options(), '> ';
311 $menu_displayed++;
312 if($menu_displayed > 50){
313 print "Safety: Menu looping too many times, exiting...\n";
314 exit;
315 }
316 }
317
318 my $choice = <>;
319
320 $choice =~ s/\A\s+//;
321 $choice =~ s/\s+\z//;
322
323 if (defined(my $handler = $dispatch{$choice})) {
324 my $result = $handler->();
325 unless (defined $result) {
326 exit 0;
327 }
328 }
329 else {
330 if($ARGV[0] ne "ran_from_world"){
331 # warn "\n\nInvalid selection\n\n";
332 }
333 }
334 }
335}
336
337sub menu_options {
338 if(@total_updates){
339 if($bots_db_management == 1){
340 $option[3] = "Check and stage pending REQUIRED Database updates";
341 $bots_management = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")";
342 }
343 else{
344 $option[3] = "Run pending REQUIRED updates... (" . scalar (@total_updates) . ")";
345 if(get_mysql_result("SHOW TABLES LIKE 'bots'") eq ""){
346 $bots_management = "Install bots database pre-requisites (Requires bots server binaries)";
347 }
348 else{
349 $bots_management = "Check for Bot pending REQUIRED database updates... (Must have bots enabled)";
350 }
351 }
352 }
353 else{
354 $option[3] = "Check and stage pending REQUIRED Database updates";
355 $bots_management = "Check for Bot REQUIRED database updates... (Must have bots enabled)";
356 }
357
358return <<EO_MENU;
359============================================================
360#::: EQEmu Update Utility Menu: (eqemu_update.pl)
361============================================================
362 1) [Backup Database] :: (Saves to Backups folder)
363 2) [Backup Database Compressed] :: (Saves to Backups folder)
364 3) [EQEmu DB Schema] :: $option[3]
365 4) [EQEmu DB Bots Schema] $bots_management
366 5) [OPCodes] :: Download latest opcodes for each EQ Client
367 6) [Maps] :: Download latest map and water files
368 7) [Plugins (Perl)] :: Download latest Perl plugins
369 8) [Quests (Perl/LUA)] :: Download latest PEQ quests and stage updates
370 9) [LUA Modules] :: Download latest LUA Modules (Required for Lua)
371 10) [DB Data : Alternate Advancement] :: Download Latest AA's from PEQ (This overwrites existing data)
372 11) [Windows Server Build] :: Download Latest and Stable Server Build (Overwrites existing .exe's, includes .dll's)
373 12) [Windows Server .dll's] :: Download Pre-Requisite Server .dll's
374 13) [Windows Server Loginserver Setup] :: Download and install Windows Loginserver
375 14) [Remove Duplicate Rule Values] :: Looks for redundant rule_values entries and removes them
376 15) [Fetch Utility Scripts] :: Fetches server management utility scripts
377 19) [EQEmu DB Drop Bots Schema] :: Remove Bots schema and return database to normal state
378 20) [Update the updater] Force update this script (Redownload)
379 0) Exit
380
381 Enter numbered option and press enter...
382
383EO_MENU
384}
385
386sub check_for_database_dump_script{
387 if(`perl db_dumper.pl`=~/Need arguments/i){
388 return;
389 }
390 else{
391 print "db_dumper.pl not found... retrieving...\n\n";
392 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/db_dumper.pl", "db_dumper.pl");
393 }
394}
395
396sub ran_from_world {
397 print "Running from world...\n";
398}
399
400sub database_dump {
401 check_for_database_dump_script();
402 print "Performing database backup....\n";
403 print `perl db_dumper.pl database="$db" loc="backups"`;
404}
405sub database_dump_compress {
406 check_for_database_dump_script();
407 print "Performing database backup....\n";
408 print `perl db_dumper.pl database="$db" loc="backups" compress`;
409}
410
411sub script_exit{
412 #::: Cleanup staged folder...
413 rmtree("updates_staged/");
414 exit;
415}
416
417#::: Returns Tab Delimited MySQL Result from Command Line
418sub get_mysql_result{
419 my $run_query = $_[0];
420 if(!$db){ return; }
421 if($OS eq "Windows"){ return `"$path" --host $host --user $user --password="$pass" $db -N -B -e "$run_query"`; }
422 if($OS eq "Linux"){
423 $run_query =~s/`//g;
424 return `$path --user="$user" --host $host --password="$pass" $db -N -B -e "$run_query"`;
425 }
426}
427
428sub get_mysql_result_from_file{
429 my $update_file = $_[0];
430 if(!$db){ return; }
431 if($OS eq "Windows"){ return `"$path" --host $host --user $user --password="$pass" --force $db < $update_file`; }
432 if($OS eq "Linux"){ return `"$path" --host $host --user $user --password="$pass" --force $db < $update_file`; }
433}
434
435#::: Gets Remote File based on URL (1st Arg), and saves to destination file (2nd Arg)
436#::: Example: get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
437sub get_remote_file{
438 my $URL = $_[0];
439 my $Dest_File = $_[1];
440 my $content_type = $_[2];
441
442 #::: Build file path of the destination file so that we may check for the folder's existence and make it if necessary
443 if($Dest_File=~/\//i){
444 my @dir_path = split('/', $Dest_File);
445 $build_path = "";
446 $di = 0;
447 while($dir_path[$di]){
448 $build_path .= $dir_path[$di] . "/";
449 #::: If path does not exist, create the directory...
450 if (!-d $build_path) {
451 mkdir($build_path);
452 }
453 if(!$dir_path[$di + 2] && $dir_path[$di + 1]){
454 # print $actual_path . "\n";
455 $actual_path = $build_path;
456 last;
457 }
458 $di++;
459 }
460 }
461
462 if($OS eq "Windows"){
463 #::: For non-text type requests...
464 if($content_type == 1){
465 $break = 0;
466 while($break == 0) {
467 use LWP::Simple qw(getstore);
468 if(!getstore($URL, $Dest_File)){
469 # print "Error, no connection or failed request...\n\n";
470 }
471 # sleep(1);
472 #::: Make sure the file exists before continuing...
473 if(-e $Dest_File) {
474 $break = 1;
475 print " [URL] :: " . $URL . "\n";
476 print " [Saved] :: " . $Dest_File . "\n";
477 } else { $break = 0; }
478 usleep(500);
479 }
480 }
481 else{
482 $break = 0;
483 while($break == 0) {
484 require LWP::UserAgent;
485 my $ua = LWP::UserAgent->new;
486 $ua->timeout(10);
487 $ua->env_proxy;
488 my $response = $ua->get($URL);
489 if ($response->is_success){
490 open (FILE, '> ' . $Dest_File . '');
491 print FILE $response->decoded_content;
492 close (FILE);
493 }
494 else {
495 # print "Error, no connection or failed request...\n\n";
496 }
497 if(-e $Dest_File) {
498 $break = 1;
499 print " [URL] :: " . $URL . "\n";
500 print " [Saved] :: " . $Dest_File . "\n";
501 } else { $break = 0; }
502 usleep(500);
503 }
504 }
505 }
506 if($OS eq "Linux"){
507 #::: wget -O db_update/db_update_manifest.txt https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt
508 $wget = `wget --no-check-certificate --quiet -O $Dest_File $URL`;
509 print " o URL: (" . $URL . ")\n";
510 print " o Saved: (" . $Dest_File . ") \n";
511 if($wget=~/unable to resolve/i){
512 print "Error, no connection or failed request...\n\n";
513 #die;
514 }
515 }
516}
517
518#::: Trim Whitespaces
519sub trim {
520 my $string = $_[0];
521 $string =~ s/^\s+//;
522 $string =~ s/\s+$//;
523 return $string;
524}
525
526#::: Fetch Latest PEQ AA's
527sub aa_fetch{
528 if(!$db){
529 print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n";
530 return;
531 }
532
533 print "Pulling down PEQ AA Tables...\n";
534 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/peq_aa_tables_post_rework.sql", "db_update/peq_aa_tables_post_rework.sql");
535 print "\n\nInstalling AA Tables...\n";
536 print get_mysql_result_from_file("db_update/peq_aa_tables_post_rework.sql");
537 print "\nDone...\n\n";
538}
539
540#::: Fetch Latest Opcodes
541sub opcodes_fetch{
542 print "Pulling down latest opcodes...\n";
543 %opcodes = (
544 1 => ["opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/opcodes.conf"],
545 2 => ["mail_opcodes", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/mail_opcodes.conf"],
546 3 => ["Titanium", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_Titanium.conf"],
547 4 => ["Secrets of Faydwer", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoF.conf"],
548 5 => ["Seeds of Destruction", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_SoD.conf"],
549 6 => ["Underfoot", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_UF.conf"],
550 7 => ["Rain of Fear", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF.conf"],
551 8 => ["Rain of Fear 2", "https://raw.githubusercontent.com/EQEmu/Server/master/utils/patches/patch_RoF2.conf"],
552 );
553 $loop = 1;
554 while($opcodes{$loop}[0]){
555 #::: Split the URL by the patches folder to get the file name from URL
556 @real_file = split("patches/", $opcodes{$loop}[1]);
557 $find = 0;
558 while($real_file[$find]){
559 $file_name = $real_file[$find];
560 $find++;
561 }
562
563 print "\nDownloading (" . $opcodes{$loop}[0] . ") File: '" . $file_name . "'...\n\n";
564 get_remote_file($opcodes{$loop}[1], $file_name);
565 $loop++;
566 }
567 print "\nDone...\n\n";
568}
569
570sub remove_duplicate_rule_values{
571 $ruleset_id = trim(get_mysql_result("SELECT `ruleset_id` FROM `rule_sets` WHERE `name` = 'default'"));
572 print "Default Ruleset ID: " . $ruleset_id . "\n";
573
574 $total_removed = 0;
575 #::: Store Default values...
576 $mysql_result = get_mysql_result("SELECT * FROM `rule_values` WHERE `ruleset_id` = " . $ruleset_id);
577 my @lines = split("\n", $mysql_result);
578 foreach my $val (@lines){
579 my @values = split("\t", $val);
580 $rule_set_values{$values[1]}[0] = $values[2];
581 }
582 #::: Compare default values against other rulesets to check for duplicates...
583 $mysql_result = get_mysql_result("SELECT * FROM `rule_values` WHERE `ruleset_id` != " . $ruleset_id);
584 my @lines = split("\n", $mysql_result);
585 foreach my $val (@lines){
586 my @values = split("\t", $val);
587 if($values[2] == $rule_set_values{$values[1]}[0]){
588 print "DUPLICATE : " . $values[1] . " (Ruleset (" . $values[0] . ")) matches default value of : " . $values[2] . ", removing...\n";
589 get_mysql_result("DELETE FROM `rule_values` WHERE `ruleset_id` = " . $values[0] . " AND `rule_name` = '" . $values[1] . "'");
590 $total_removed++;
591 }
592 }
593
594 print "Total duplicate rules removed... " . $total_removed . "\n";
595}
596
597sub copy_file{
598 $l_source_file = $_[0];
599 $l_dest_file = $_[1];
600 if($l_dest_file=~/\//i){
601 my @dir_path = split('/', $l_dest_file);
602 $build_path = "";
603 $di = 0;
604 while($dir_path[$di]){
605 $build_path .= $dir_path[$di] . "/";
606 #::: If path does not exist, create the directory...
607 if (!-d $build_path) {
608 mkdir($build_path);
609 }
610 if(!$dir_path[$di + 2] && $dir_path[$di + 1]){
611 # print $actual_path . "\n";
612 $actual_path = $build_path;
613 last;
614 }
615 $di++;
616 }
617 }
618 copy $l_source_file, $l_dest_file;
619}
620
621sub fetch_latest_windows_binaries{
622 print "\n --- Fetching Latest Windows Binaries... --- \n";
623 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/master_windows_build.zip", "updates_staged/master_windows_build.zip", 1);
624 print "\n --- Fetched Latest Windows Binaries... --- \n";
625 print "\n --- Extracting... --- \n";
626 unzip('updates_staged/master_windows_build.zip', 'updates_staged/binaries/');
627 my @files;
628 my $start_dir = "updates_staged/binaries";
629 find(
630 sub { push @files, $File::Find::name unless -d; },
631 $start_dir
632 );
633 for my $file (@files) {
634 $dest_file = $file;
635 $dest_file =~s/updates_staged\/binaries\///g;
636 print "Installing :: " . $dest_file . "\n";
637 copy_file($file, $dest_file);
638 }
639 print "\n --- Done... --- \n";
640
641 rmtree('updates_staged');
642}
643
644sub do_windows_login_server_setup{
645 print "\n --- Fetching Loginserver... --- \n";
646 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/login_server.zip", "updates_staged/login_server.zip", 1);
647 print "\n --- Extracting... --- \n";
648 unzip('updates_staged/login_server.zip', 'updates_staged/login_server/');
649 my @files;
650 my $start_dir = "updates_staged/login_server";
651 find(
652 sub { push @files, $File::Find::name unless -d; },
653 $start_dir
654 );
655 for my $file (@files) {
656 $dest_file = $file;
657 $dest_file =~s/updates_staged\/login_server\///g;
658 print "Installing :: " . $dest_file . "\n";
659 copy_file($file, $dest_file);
660 }
661 print "\n Done... \n";
662
663 print "Pulling down Loginserver database tables...\n";
664 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/login_server_tables.sql", "db_update/login_server_tables.sql");
665 print "\n\nInstalling Loginserver tables...\n";
666 print get_mysql_result_from_file("db_update/login_server_tables.sql");
667 print "\nDone...\n\n";
668
669 add_login_server_firewall_rules();
670
671 rmtree('updates_staged');
672 rmtree('db_update');
673
674 print "\nPress any key to continue...\n";
675
676 <>; #Read from STDIN
677
678}
679
680sub add_login_server_firewall_rules{
681 #::: Check Loginserver Firewall install for Windows
682 if($OS eq "Windows"){
683 $output = `netsh advfirewall firewall show rule name=all`;
684 @output_buffer = split("\n", $output);
685 $has_loginserver_rules_titanium = 0;
686 $has_loginserver_rules_sod = 0;
687 foreach my $val (@output_buffer){
688 if($val=~/Rule Name/i){
689 $val=~s/Rule Name://g;
690 if($val=~/EQEmu Loginserver/i && $val=~/Titanium/i){
691 $has_loginserver_rules_titanium = 1;
692 print "Found existing rule :: " . trim($val) . "\n";
693 }
694 if($val=~/EQEmu Loginserver/i && $val=~/SOD/i){
695 $has_loginserver_rules_sod = 1;
696 print "Found existing rule :: " . trim($val) . "\n";
697 }
698 }
699 }
700
701 if($has_loginserver_rules_titanium == 0){
702 print "Attempting to add EQEmu Loginserver Firewall Rules (Titanium) (TCP) port 5998 \n";
703 print `netsh advfirewall firewall add rule name="EQEmu Loginserver (Titanium) (5998) TCP" dir=in action=allow protocol=TCP localport=5998`;
704 print "Attempting to add EQEmu Loginserver Firewall Rules (Titanium) (UDP) port 5998 \n";
705 print `netsh advfirewall firewall add rule name="EQEmu Loginserver (Titanium) (5998) UDP" dir=in action=allow protocol=UDP localport=5998`;
706 }
707 if($has_loginserver_rules_sod == 0){
708 print "Attempting to add EQEmu Loginserver Firewall Rules (SOD+) (TCP) port 5999 \n";
709 print `netsh advfirewall firewall add rule name="EQEmu Loginserver (SOD+) (5999) TCP" dir=in action=allow protocol=TCP localport=5999`;
710 print "Attempting to add EQEmu Loginserver Firewall Rules (SOD+) (UDP) port 5999 \n";
711 print `netsh advfirewall firewall add rule name="EQEmu Loginserver (SOD+) (5999) UDP" dir=in action=allow protocol=UDP localport=5999`;
712 }
713
714 print "If firewall rules don't add you must run this script (eqemu_update.pl) as administrator\n";
715 print "\n";
716 print "#::: Instructions \n";
717 print "In order to connect your server to the loginserver you must point your eqemu_config.xml to your local server similar to the following:\n";
718 print "
719 <loginserver1>
720 <host>login.eqemulator.net</host>
721 <port>5998</port>
722 <account></account>
723 <password></password>
724 </loginserver1>
725 <loginserver2>
726 <host>127.0.0.1</host>
727 <port>5998</port>
728 <account></account>
729 <password></password>
730 </loginserver2>
731 ";
732 print "\nWhen done, make sure your EverQuest client points to your loginserver's IP (In this case it would be 127.0.0.1) in the eqhosts.txt file\n";
733 }
734}
735
736sub check_windows_firewall_rules{
737 $output = `netsh advfirewall firewall show rule name=all`;
738 @output_buffer = split("\n", $output);
739 $has_world_rules = 0;
740 $has_zone_rules = 0;
741 foreach my $val (@output_buffer){
742 if($val=~/Rule Name/i){
743 $val=~s/Rule Name://g;
744 if($val=~/EQEmu World/i){
745 $has_world_rules = 1;
746 print "Found existing rule :: " . trim($val) . "\n";
747 }
748 if($val=~/EQEmu Zone/i){
749 $has_zone_rules = 1;
750 print "Found existing rule :: " . trim($val) . "\n";
751 }
752 }
753 }
754
755 if($has_world_rules == 0){
756 print "Attempting to add EQEmu World Firewall Rules (TCP) port 9000 \n";
757 print `netsh advfirewall firewall add rule name="EQEmu World (9000) TCP" dir=in action=allow protocol=TCP localport=9000`;
758 print "Attempting to add EQEmu World Firewall Rules (UDP) port 9000 \n";
759 print `netsh advfirewall firewall add rule name="EQEmu World (9000) UDP" dir=in action=allow protocol=UDP localport=9000`;
760 }
761 if($has_zone_rules == 0){
762 print "Attempting to add EQEmu Zones (7000-7500) TCP \n";
763 print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) TCP" dir=in action=allow protocol=TCP localport=7000-7500`;
764 print "Attempting to add EQEmu Zones (7000-7500) UDP \n";
765 print `netsh advfirewall firewall add rule name="EQEmu Zones (7000-7500) UDP" dir=in action=allow protocol=UDP localport=7000-7500`;
766 }
767}
768
769sub fetch_server_dlls{
770 print "Fetching lua51.dll, zlib1.dll, libmysql.dll...\n";
771 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/lua51.dll", "lua51.dll", 1);
772 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/zlib1.dll", "zlib1.dll", 1);
773 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuInstall/master/libmysql.dll", "libmysql.dll", 1);
774}
775
776sub fetch_peq_db_full{
777 print "Downloading latest PEQ Database... Please wait...\n";
778 get_remote_file("http://edit.peqtgc.com/weekly/peq_beta.zip", "updates_staged/peq_beta.zip", 1);
779 print "Downloaded latest PEQ Database... Extracting...\n";
780 unzip('updates_staged/peq_beta.zip', 'updates_staged/peq_db/');
781 my $start_dir = "updates_staged\\peq_db";
782 find(
783 sub { push @files, $File::Find::name unless -d; },
784 $start_dir
785 );
786 for my $file (@files) {
787 $dest_file = $file;
788 $dest_file =~s/updates_staged\\peq_db\///g;
789 if($file=~/peqbeta|player_tables/i){
790 print "MariaDB :: Installing :: " . $dest_file . "\n";
791 get_mysql_result_from_file($file);
792 }
793 if($file=~/eqtime/i){
794 print "Installing eqtime.cfg\n";
795 copy_file($file, "eqtime.cfg");
796 }
797 }
798}
799
800sub map_files_fetch_bulk{
801 print "\n --- Fetching Latest Maps... (This could take a few minutes...) --- \n";
802 get_remote_file("http://github.com/Akkadius/EQEmuMaps/archive/master.zip", "maps/maps.zip", 1);
803 unzip('maps/maps.zip', 'maps/');
804 my @files;
805 my $start_dir = "maps\\EQEmuMaps-master\\maps";
806 find(
807 sub { push @files, $File::Find::name unless -d; },
808 $start_dir
809 );
810 for my $file (@files) {
811 $dest_file = $file;
812 $dest_file =~s/maps\\EQEmuMaps-master\\maps\///g;
813 print "Installing :: " . $dest_file . "\n";
814 copy_file($file, "maps/" . $new_file);
815 }
816 print "\n --- Fetched Latest Maps... --- \n";
817
818 rmtree('maps/EQEmuMaps-master');
819 unlink('maps/maps.zip');
820}
821
822sub map_files_fetch{
823 print "\n --- Fetching Latest Maps --- \n";
824
825 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/!eqemu_maps_manifest.txt", "updates_staged/eqemu_maps_manifest.txt");
826
827 #::: Get Data from manifest
828 open (FILE, "updates_staged/eqemu_maps_manifest.txt");
829 $i = 0;
830 while (<FILE>){
831 chomp;
832 $o = $_;
833 @manifest_map_data = split(',', $o);
834 if($manifest_map_data[0] ne ""){
835 $maps_manifest[$i] = [$manifest_map_data[0], $manifest_map_data[1]];
836 $i++;
837 }
838 }
839
840 #::: Download
841 $fc = 0;
842 for($m = 0; $m <= $i; $m++){
843 my $file_existing = $maps_manifest[$m][0];
844 my $file_existing_size = (stat $file_existing)[7];
845 if($file_existing_size != $maps_manifest[$m][1]){
846 print "Updating: '" . $maps_manifest[$m][0] . "'\n";
847 get_remote_file("https://raw.githubusercontent.com/Akkadius/EQEmuMaps/master/" . $maps_manifest[$m][0], $maps_manifest[$m][0], 1);
848 $fc++;
849 }
850 }
851
852 if($fc == 0){
853 print "\nNo Map Updates found... \n\n";
854 }
855}
856
857sub quest_files_fetch{
858 if (!-e "updates_staged/Quests-Plugins-master/quests/") {
859 print "\n --- Fetching Latest Quests --- \n";
860 get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
861 print "\nFetched latest quests...\n";
862 mkdir('updates_staged');
863 unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
864 }
865
866 $fc = 0;
867 use File::Find;
868 use File::Compare;
869
870 my @files;
871 my $start_dir = "updates_staged/Quests-Plugins-master/quests/";
872 find(
873 sub { push @files, $File::Find::name unless -d; },
874 $start_dir
875 );
876 for my $file (@files) {
877 if($file=~/\.pl|\.lua|\.ext/i){
878 $staged_file = $file;
879 $dest_file = $file;
880 $dest_file =~s/updates_staged\/Quests-Plugins-master\///g;
881
882 if (!-e $dest_file) {
883 copy_file($staged_file, $dest_file);
884 print "Installing :: '" . $dest_file . "'\n";
885 $fc++;
886 }
887 else{
888 $diff = do_file_diff($dest_file, $staged_file);
889 if($diff ne ""){
890 $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file;
891
892 print $diff . "\n";
893 print "\nFile Different :: '" . $dest_file . "'\n";
894 print "\nDo you wish to update this Quest? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n";
895 my $input = <STDIN>;
896 if($input=~/N/i){}
897 else{
898 #::: Make a backup
899 copy_file($dest_file, $backup_dest);
900 #::: Copy staged to running
901 copy($staged_file, $dest_file);
902 print "Installing :: '" . $dest_file . "'\n\n";
903 }
904 $fc++;
905 }
906 }
907 }
908 }
909
910 rmtree('updates_staged');
911
912 if($fc == 0){
913 print "\nNo Quest Updates found... \n\n";
914 }
915}
916
917sub lua_modules_fetch{
918 if (!-e "updates_staged/Quests-Plugins-master/quests/lua_modules/") {
919 print "\n --- Fetching Latest LUA Modules --- \n";
920 get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
921 print "\nFetched latest LUA Modules...\n";
922 unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
923 }
924
925 $fc = 0;
926 use File::Find;
927 use File::Compare;
928
929 my @files;
930 my $start_dir = "updates_staged/Quests-Plugins-master/quests/lua_modules/";
931 find(
932 sub { push @files, $File::Find::name unless -d; },
933 $start_dir
934 );
935 for my $file (@files) {
936 if($file=~/\.pl|\.lua|\.ext/i){
937 $staged_file = $file;
938 $dest_file = $file;
939 $dest_file =~s/updates_staged\/Quests-Plugins-master\/quests\///g;
940
941 if (!-e $dest_file) {
942 copy_file($staged_file, $dest_file);
943 print "Installing :: '" . $dest_file . "'\n";
944 $fc++;
945 }
946 else{
947 $diff = do_file_diff($dest_file, $staged_file);
948 if($diff ne ""){
949 $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file;
950 print $diff . "\n";
951 print "\nFile Different :: '" . $dest_file . "'\n";
952 print "\nDo you wish to update this LUA Module? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n";
953 my $input = <STDIN>;
954 if($input=~/N/i){}
955 else{
956 #::: Make a backup
957 copy_file($dest_file, $backup_dest);
958 #::: Copy staged to running
959 copy($staged_file, $dest_file);
960 print "Installing :: '" . $dest_file . "'\n\n";
961 }
962 $fc++;
963 }
964 }
965 }
966 }
967
968 if($fc == 0){
969 print "\nNo LUA Modules Updates found... \n\n";
970 }
971}
972
973sub plugins_fetch{
974 if (!-e "updates_staged/Quests-Plugins-master/plugins/") {
975 print "\n --- Fetching Latest Plugins --- \n";
976 get_remote_file("https://github.com/EQEmu/Quests-Plugins/archive/master.zip", "updates_staged/Quests-Plugins-master.zip", 1);
977 print "\nFetched latest plugins...\n";
978 unzip('updates_staged/Quests-Plugins-master.zip', 'updates_staged/');
979 }
980
981 $fc = 0;
982 use File::Find;
983 use File::Compare;
984
985 my @files;
986 my $start_dir = "updates_staged/Quests-Plugins-master/plugins/";
987 find(
988 sub { push @files, $File::Find::name unless -d; },
989 $start_dir
990 );
991 for my $file (@files) {
992 if($file=~/\.pl|\.lua|\.ext/i){
993 $staged_file = $file;
994 $dest_file = $file;
995 $dest_file =~s/updates_staged\/Quests-Plugins-master\///g;
996
997 if (!-e $dest_file) {
998 copy_file($staged_file, $dest_file);
999 print "Installing :: '" . $dest_file . "'\n";
1000 $fc++;
1001 }
1002 else{
1003 $diff = do_file_diff($dest_file, $staged_file);
1004 if($diff ne ""){
1005 $backup_dest = "updates_backups/" . $time_stamp . "/" . $dest_file;
1006 print $diff . "\n";
1007 print "\nFile Different :: '" . $dest_file . "'\n";
1008 print "\nDo you wish to update this Plugin? '" . $dest_file . "' [Yes (Enter) - No (N)] \nA backup will be found in '" . $backup_dest . "'\n";
1009 my $input = <STDIN>;
1010 if($input=~/N/i){}
1011 else{
1012 #::: Make a backup
1013 copy_file($dest_file, $backup_dest);
1014 #::: Copy staged to running
1015 copy($staged_file, $dest_file);
1016 print "Installing :: '" . $dest_file . "'\n\n";
1017 }
1018 $fc++;
1019 }
1020 }
1021 }
1022 }
1023
1024 if($fc == 0){
1025 print "\nNo Plugin Updates found... \n\n";
1026 }
1027}
1028
1029sub do_file_diff{
1030 $file_1 = $_[0];
1031 $file_2 = $_[1];
1032 if($OS eq "Windows"){
1033 eval "use Text::Diff";
1034 $diff = diff($file_1, $file_2, { STYLE => "Unified" });
1035 return $diff;
1036 }
1037 if($OS eq "Linux"){
1038 # print 'diff -u "$file_1" "$file_2"' . "\n";
1039 return `diff -u "$file_1" "$file_2"`;
1040 }
1041}
1042
1043sub unzip{
1044 $archive_to_unzip = $_[0];
1045 $dest_folder = $_[1];
1046
1047 if($OS eq "Windows"){
1048 eval "use Archive::Zip qw( :ERROR_CODES :CONSTANTS )";
1049 my $zip = Archive::Zip->new();
1050 unless ( $zip->read($archive_to_unzip) == AZ_OK ) {
1051 die 'read error';
1052 }
1053 print "Extracting...\n";
1054 $zip->extractTree('', $dest_folder);
1055 }
1056 if($OS eq "Linux"){
1057 print `unzip -o "$archive_to_unzip" -d "$dest_folder"`;
1058 }
1059}
1060
1061sub are_file_sizes_different{
1062 $file_1 = $_[0];
1063 $file_2 = $_[1];
1064 my $file_1 = (stat $file_1)[7];
1065 my $file_2 = (stat $file_2)[7];
1066 # print $file_1 . " :: " . $file_2 . "\n";
1067 if($file_1 != $file_2){
1068 return 1;
1069 }
1070 return;
1071}
1072
1073sub do_bots_db_schema_drop{
1074 #"drop_bots.sql" is run before reverting database back to 'normal'
1075 print "Fetching drop_bots.sql...\n";
1076 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/drop_bots.sql", "db_update/drop_bots.sql");
1077 print get_mysql_result_from_file("db_update/drop_bots.sql");
1078
1079 print "Restoring normality...\n";
1080 print get_mysql_result("DELETE FROM `rule_values` WHERE `rule_name` LIKE 'Bots:%';");
1081
1082 if(get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && $db){
1083 print get_mysql_result("DELETE FROM `commands` WHERE `command` LIKE 'bot';");
1084 }
1085
1086 if(get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && $db){
1087 print get_mysql_result("DELETE FROM `command_settings` WHERE `command` LIKE 'bot';");
1088 }
1089
1090 if(get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
1091 print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;");
1092 }
1093 print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY (`groupid`, `charid`, `ismerc`);");
1094
1095 if(get_mysql_result("SHOW KEYS FROM `guild_members` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
1096 print get_mysql_result("ALTER TABLE `guild_members` DROP PRIMARY KEY;");
1097 }
1098 print get_mysql_result("ALTER TABLE `guild_members` ADD PRIMARY KEY (`char_id`);");
1099
1100 print get_mysql_result("UPDATE `spawn2` SET `enabled` = 0 WHERE `id` IN (59297,59298);");
1101
1102 if(get_mysql_result("SHOW COLUMNS FROM `db_version` LIKE 'bots_version'") ne "" && $db){
1103 print get_mysql_result("UPDATE `db_version` SET `bots_version` = 0;");
1104 }
1105}
1106
1107sub modify_db_for_bots{
1108 #Called after the db bots schema (2015_09_30_bots.sql) has been loaded
1109 print "Modifying database for bots...\n";
1110 print get_mysql_result("UPDATE `spawn2` SET `enabled` = 1 WHERE `id` IN (59297,59298);");
1111
1112 if(get_mysql_result("SHOW KEYS FROM `guild_members` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
1113 print get_mysql_result("ALTER TABLE `guild_members` DROP PRIMARY KEY;");
1114 }
1115
1116 if(get_mysql_result("SHOW KEYS FROM `group_id` WHERE `Key_name` LIKE 'PRIMARY'") ne "" && $db){
1117 print get_mysql_result("ALTER TABLE `group_id` DROP PRIMARY KEY;");
1118 }
1119 print get_mysql_result("ALTER TABLE `group_id` ADD PRIMARY KEY USING BTREE(`groupid`, `charid`, `name`, `ismerc`);");
1120
1121 if(get_mysql_result("SHOW TABLES LIKE 'command_settings'") ne "" && get_mysql_result("SELECT `command` FROM `command_settings` WHERE `command` LIKE 'bot'") eq "" && $db){
1122 print get_mysql_result("INSERT INTO `command_settings` VALUES ('bot', '0', '');");
1123 }
1124
1125 if(get_mysql_result("SHOW TABLES LIKE 'commands'") ne "" && get_mysql_result("SELECT `command` FROM `commands` WHERE `command` LIKE 'bot'") eq "" && $db){
1126 print get_mysql_result("INSERT INTO `commands` VALUES ('bot', '0');");
1127 }
1128
1129 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotAAExpansion'") ne "" && $db){
1130 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:AAExpansion' WHERE `rule_name` LIKE 'Bots:BotAAExpansion';");
1131 }
1132 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:AAExpansion'") eq "" && $db){
1133 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:AAExpansion', '8', 'The expansion through which bots will obtain AAs');");
1134 }
1135
1136 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreateBotCount'") ne "" && $db){
1137 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:CreationLimit' WHERE `rule_name` LIKE 'Bots:CreateBotCount';");
1138 }
1139 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:CreationLimit'") eq "" && $db){
1140 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:CreationLimit', '150', 'Number of bots that each account can create');");
1141 }
1142
1143 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotFinishBuffing'") ne "" && $db){
1144 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:FinishBuffing' WHERE `rule_name` LIKE 'Bots:BotFinishBuffing';");
1145 }
1146 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:FinishBuffing'") eq "" && $db){
1147 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:FinishBuffing', 'false', 'Allow for buffs to complete even if the bot caster is out of mana. Only affects buffing out of combat.');");
1148 }
1149
1150 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotGroupBuffing'") ne "" && $db){
1151 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:GroupBuffing' WHERE `rule_name` LIKE 'Bots:BotGroupBuffing';");
1152 }
1153 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:GroupBuffing'") eq "" && $db){
1154 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:GroupBuffing', 'false', 'Bots will cast single target buffs as group buffs, default is false for single. Does not make single target buffs work for MGB.');");
1155 }
1156
1157 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotManaRegen'") ne "" && $db){
1158 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:ManaRegen' WHERE `rule_name` LIKE 'Bots:BotManaRegen';");
1159 }
1160 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:ManaRegen'") eq "" && $db){
1161 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:ManaRegen', '3.0', 'Adjust mana regen for bots, 1 is fast and higher numbers slow it down 3 is about the same as players.');");
1162 }
1163
1164 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotQuest'") ne "" && $db){
1165 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpawnLimit' WHERE `rule_name` LIKE 'Bots:BotQuest';");
1166 }
1167 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpawnLimit'") eq "" && $db){
1168 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpawnLimit', 'false', 'Optional quest method to manage bot spawn limits using the quest_globals name bot_spawn_limit, see: /bazaar/Aediles_Thrall.pl');");
1169 }
1170
1171 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:BotSpellQuest'") ne "" && $db){
1172 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:QuestableSpells' WHERE `rule_name` LIKE 'Bots:BotSpellQuest';");
1173 }
1174 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:QuestableSpells'") eq "" && $db){
1175 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:QuestableSpells', 'false', 'Anita Thrall\\\'s (Anita_Thrall.pl) Bot Spell Scriber quests.');");
1176 }
1177
1178 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnBotCount'") ne "" && $db){
1179 print get_mysql_result("UPDATE `rule_values` SET `rule_name` = 'Bots:SpawnLimit' WHERE `rule_name` LIKE 'Bots:SpawnBotCount';");
1180 }
1181 if(get_mysql_result("SELECT `rule_name` FROM `rule_values` WHERE `rule_name` LIKE 'Bots:SpawnLimit'") eq "" && $db){
1182 print get_mysql_result("INSERT INTO `rule_values` VALUES ('1', 'Bots:SpawnLimit', '71', 'Number of bots a character can have spawned at one time, You + 71 bots is a 12 group raid');");
1183 }
1184
1185 convert_existing_bot_data();
1186}
1187
1188sub convert_existing_bot_data{
1189 if(get_mysql_result("SHOW TABLES LIKE 'bots'") ne "" && $db){
1190 print "Converting existing bot data...\n";
1191 print get_mysql_result("INSERT INTO `bot_data` (`bot_id`, `owner_id`, `spells_id`, `name`, `last_name`, `zone_id`, `gender`, `race`, `class`, `level`, `creation_day`, `last_spawn`, `time_spawned`, `size`, `face`, `hair_color`, `hair_style`, `beard`, `beard_color`, `eye_color_1`, `eye_color_2`, `drakkin_heritage`, `drakkin_tattoo`, `drakkin_details`, `ac`, `atk`, `hp`, `mana`, `str`, `sta`, `cha`, `dex`, `int`, `agi`, `wis`, `fire`, `cold`, `magic`, `poison`, `disease`, `corruption`) SELECT `BotID`, `BotOwnerCharacterID`, `BotSpellsID`, `Name`, `LastName`, `LastZoneId`, `Gender`, `Race`, `Class`, `BotLevel`, UNIX_TIMESTAMP(`BotCreateDate`), UNIX_TIMESTAMP(`LastSpawnDate`), `TotalPlayTime`, `Size`, `Face`, `LuclinHairColor`, `LuclinHairStyle`, `LuclinBeard`, `LuclinBeardColor`, `LuclinEyeColor`, `LuclinEyeColor2`, `DrakkinHeritage`, `DrakkinTattoo`, `DrakkinDetails`, `AC`, `ATK`, `HP`, `Mana`, `STR`, `STA`, `CHA`, `DEX`, `_INT`, `AGI`, `WIS`, `FR`, `CR`, `MR`, `PR`, `DR`, `Corrup` FROM `bots`;");
1192
1193 print get_mysql_result("INSERT INTO `bot_inspect_messages` (`bot_id`, `inspect_message`) SELECT `BotID`, `BotInspectMessage` FROM `bots`;");
1194
1195 print get_mysql_result("RENAME TABLE `bots` TO `bots_old`;");
1196 }
1197
1198 if(get_mysql_result("SHOW TABLES LIKE 'botstances'") ne "" && $db){
1199 print get_mysql_result("INSERT INTO `bot_stances` (`bot_id`, `stance_id`) SELECT bs.`BotID`, bs.`StanceID` FROM `botstances` bs INNER JOIN `bot_data` bd ON bs.`BotID` = bd.`bot_id`;");
1200
1201 print get_mysql_result("RENAME TABLE `botstances` TO `botstances_old`;");
1202 }
1203
1204 if(get_mysql_result("SHOW TABLES LIKE 'bottimers'") ne "" && $db){
1205 print get_mysql_result("INSERT INTO `bot_timers` (`bot_id`, `timer_id`, `timer_value`) SELECT bt.`BotID`, bt.`TimerID`, bt.`Value` FROM `bottimers` bt INNER JOIN `bot_data` bd ON bt.`BotID` = bd.`bot_id`;");
1206
1207 print get_mysql_result("RENAME TABLE `bottimers` TO `bottimers_old`;");
1208 }
1209
1210 if(get_mysql_result("SHOW TABLES LIKE 'botbuffs'") ne "" && $db){
1211 print get_mysql_result("INSERT INTO `bot_buffs` (`buffs_index`, `bot_id`, `spell_id`, `caster_level`, `duration_formula`, `tics_remaining`, `poison_counters`, `disease_counters`, `curse_counters`, `corruption_counters`, `numhits`, `melee_rune`, `magic_rune`, `persistent`) SELECT bb.`BotBuffId`, bb.`BotId`, bb.`SpellId`, bb.`CasterLevel`, bb.`DurationFormula`, bb.`TicsRemaining`, bb.`PoisonCounters`, bb.`DiseaseCounters`, bb.`CurseCounters`, bb.`CorruptionCounters`, bb.`HitCount`, bb.`MeleeRune`, bb.`MagicRune`, bb.`Persistent` FROM `botbuffs` bb INNER JOIN `bot_data` bd ON bb.`BotId` = bd.`bot_id`;");
1212
1213 if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'dot_rune'") ne "" && $db){
1214 print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`dot_rune` = bbo.`dot_rune` WHERE bb.`bot_id` = bbo.`BotID`;");
1215 }
1216
1217 if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_x'") ne "" && $db){
1218 print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_x` = bbo.`caston_x` WHERE bb.`bot_id` = bbo.`BotID`;");
1219 }
1220
1221 if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_y'") ne "" && $db){
1222 print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_y` = bbo.`caston_y` WHERE bb.`bot_id` = bbo.`BotID`;");
1223 }
1224
1225 if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'caston_z'") ne "" && $db){
1226 print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`caston_z` = bbo.`caston_z` WHERE bb.`bot_id` = bbo.`BotID`;");
1227 }
1228
1229 if(get_mysql_result("SHOW COLUMNS FROM `botbuffs` LIKE 'ExtraDIChance'") ne "" && $db){
1230 print get_mysql_result("UPDATE `bot_buffs` bb INNER JOIN `botbuffs` bbo ON bb.`buffs_index` = bbo.`BotBuffId` SET bb.`extra_di_chance` = bbo.`ExtraDIChance` WHERE bb.`bot_id` = bbo.`BotID`;");
1231 }
1232
1233 print get_mysql_result("RENAME TABLE `botbuffs` TO `botbuffs_old`;");
1234 }
1235
1236 if(get_mysql_result("SHOW TABLES LIKE 'botinventory'") ne "" && $db){
1237 print get_mysql_result("INSERT INTO `bot_inventories` (`inventories_index`, `bot_id`, `slot_id`, `item_id`, `inst_charges`, `inst_color`, `inst_no_drop`, `augment_1`, `augment_2`, `augment_3`, `augment_4`, `augment_5`) SELECT bi.`BotInventoryID`, bi.`BotID`, bi.`SlotID`, bi.`ItemID`, bi.`charges`, bi.`color`, bi.`instnodrop`, bi.`augslot1`, bi.`augslot2`, bi.`augslot3`, bi.`augslot4`, bi.`augslot5` FROM `botinventory` bi INNER JOIN `bot_data` bd ON bi.`BotID` = bd.`bot_id`;");
1238
1239 if(get_mysql_result("SHOW COLUMNS FROM `botinventory` LIKE 'augslot6'") ne "" && $db){
1240 print get_mysql_result("UPDATE `bot_inventories` bi INNER JOIN `botinventory` bio ON bi.`inventories_index` = bio.`BotInventoryID` SET bi.`augment_6` = bio.`augslot6` WHERE bi.`bot_id` = bio.`BotID`;");
1241 }
1242
1243 print get_mysql_result("RENAME TABLE `botinventory` TO `botinventory_old`;");
1244 }
1245
1246 if(get_mysql_result("SHOW TABLES LIKE 'botpets'") ne "" && $db){
1247 print get_mysql_result("INSERT INTO `bot_pets` (`pets_index`, `pet_id`, `bot_id`, `name`, `mana`, `hp`) SELECT bp.`BotPetsId`, bp.`PetId`, bp.`BotId`, bp.`Name`, bp.`Mana`, bp.`HitPoints` FROM `botpets` bp INNER JOIN `bot_data` bd ON bp.`BotId` = bd.`bot_id`;");
1248
1249 print get_mysql_result("RENAME TABLE `botpets` TO `botpets_old`;");
1250 }
1251
1252 if(get_mysql_result("SHOW TABLES LIKE 'botpetbuffs'") ne "" && $db){
1253 print get_mysql_result("INSERT INTO `bot_pet_buffs` (`pet_buffs_index`, `pets_index`, `spell_id`, `caster_level`, `duration`) SELECT bpb.`BotPetBuffId`, bpb.`BotPetsId`, bpb.`SpellId`, bpb.`CasterLevel`, bpb.`Duration` FROM `botpetbuffs` bpb INNER JOIN `bot_pets` bp ON bpb.`BotPetsId` = bp.`pets_index`;");
1254
1255 print get_mysql_result("RENAME TABLE `botpetbuffs` TO `botpetbuffs_old`;");
1256 }
1257
1258 if(get_mysql_result("SHOW TABLES LIKE 'botpetinventory'") ne "" && $db){
1259 print get_mysql_result("INSERT INTO `bot_pet_inventories` (`pet_inventories_index`, `pets_index`, `item_id`) SELECT bpi.`BotPetInventoryId`, bpi.`BotPetsId`, bpi.`ItemId` FROM `botpetinventory` bpi INNER JOIN `bot_pets` bp ON bpi.`BotPetsId` = bp.`pets_index`;");
1260
1261 print get_mysql_result("RENAME TABLE `botpetinventory` TO `botpetinventory_old`;");
1262 }
1263
1264 if(get_mysql_result("SHOW TABLES LIKE 'botgroup'") ne "" && $db){
1265 print get_mysql_result("INSERT INTO `bot_groups` (`groups_index`, `group_leader_id`, `group_name`) SELECT bg.`BotGroupId`, bg.`BotGroupLeaderBotId`, bg.`BotGroupName` FROM `botgroup` bg INNER JOIN `bot_data` bd ON bg.`BotGroupLeaderBotId` = bd.`bot_id`;");
1266
1267 print get_mysql_result("RENAME TABLE `botgroup` TO `botgroup_old`;");
1268 }
1269
1270 if(get_mysql_result("SHOW TABLES LIKE 'botgroupmembers'") ne "" && $db){
1271 print get_mysql_result("INSERT INTO `bot_group_members` (`group_members_index`, `groups_index`, `bot_id`) SELECT bgm.`BotGroupMemberId`, bgm.`BotGroupId`, bgm.`BotId` FROM `botgroupmembers` bgm INNER JOIN `bot_groups` bg ON bgm.`BotGroupId` = bg.`groups_index` INNER JOIN `bot_data` bd ON bgm.`BotId` = bd.`bot_id`;");
1272
1273 print get_mysql_result("RENAME TABLE `botgroupmembers` TO `botgroupmembers_old`;");
1274 }
1275
1276 if(get_mysql_result("SHOW TABLES LIKE 'botguildmembers'") ne "" && $db){
1277 print get_mysql_result("INSERT INTO `bot_guild_members` (`bot_id`, `guild_id`, `rank`, `tribute_enable`, `total_tribute`, `last_tribute`, `banker`, `public_note`, `alt`) SELECT bgm.`char_id`, bgm.`guild_id`, bgm.`rank`, bgm.`tribute_enable`, bgm.`total_tribute`, bgm.`last_tribute`, bgm.`banker`, bgm.`public_note`, bgm.`alt` FROM `botguildmembers` bgm INNER JOIN `guilds` g ON bgm.`guild_id` = g.`id` INNER JOIN `bot_data` bd ON bgm.`char_id` = bd.`bot_id`;");
1278
1279 print get_mysql_result("RENAME TABLE `botguildmembers` TO `botguildmembers_old`;");
1280 }
1281}
1282
1283sub get_bots_db_version{
1284 #::: Check if bots_version column exists...
1285 if(get_mysql_result("SHOW COLUMNS FROM db_version LIKE 'bots_version'") eq "" && $db){
1286 print get_mysql_result("ALTER TABLE db_version ADD bots_version int(11) DEFAULT '0' AFTER version;");
1287 print "\nColumn 'bots_version' does not exists.... Adding to 'db_version' table...\n\n";
1288 }
1289 $bots_local_db_version = trim(get_mysql_result("SELECT bots_version FROM db_version LIMIT 1"));
1290 return $bots_local_db_version;
1291}
1292
1293sub bots_db_management{
1294 #::: Main Binary Database version
1295 $bin_db_ver = trim($db_version[2]);
1296
1297 #::: If we have stale data from main db run
1298 if($db_run_stage > 0 && $bots_db_management == 0){
1299 clear_database_runs();
1300 }
1301
1302 if($bin_db_ver == 0){
1303 print "Your server binaries (world/zone) are not compiled for bots...\n";
1304 return;
1305 }
1306
1307 #::: Set on flag for running bot updates...
1308 $bots_db_management = 1;
1309
1310 $bots_local_db_version = get_bots_db_version();
1311
1312 run_database_check();
1313}
1314
1315sub main_db_management{
1316 #::: If we have stale data from bots db run
1317 if($db_run_stage > 0 && $bots_db_management == 1){
1318 clear_database_runs();
1319 }
1320
1321 #::: Main Binary Database version
1322 $bin_db_ver = trim($db_version[1]);
1323
1324 $bots_db_management = 0;
1325 run_database_check();
1326}
1327
1328sub clear_database_runs{
1329 # print "DEBUG :: clear_database_runs\n\n";
1330 #::: Clear manifest data...
1331 %m_d = ();
1332 #::: Clear updates...
1333 @total_updates = ();
1334 #::: Clear stage
1335 $db_run_stage = 0;
1336}
1337
1338#::: Responsible for Database Upgrade Routines
1339sub run_database_check{
1340
1341 if(!$db){
1342 print "No database present, check your eqemu_config.xml for proper MySQL/MariaDB configuration...\n";
1343 return;
1344 }
1345
1346 if(!@total_updates){
1347 #::: Pull down bots database manifest
1348 if($bots_db_management == 1){
1349 print "Retrieving latest bots database manifest...\n";
1350 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/bots_db_update_manifest.txt", "db_update/db_update_manifest.txt");
1351 }
1352 #::: Pull down mainstream database manifest
1353 else{
1354 print "Retrieving latest database manifest...\n";
1355 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/db_update_manifest.txt", "db_update/db_update_manifest.txt");
1356 }
1357 }
1358
1359 #::: Run 2 - Running pending updates...
1360 if(@total_updates){
1361 @total_updates = sort @total_updates;
1362 foreach my $val (@total_updates){
1363 $file_name = trim($m_d{$val}[1]);
1364 print "Running Update: " . $val . " - " . $file_name . "\n";
1365 print get_mysql_result_from_file("db_update/$file_name");
1366 print get_mysql_result("UPDATE db_version SET version = $val WHERE version < $val");
1367
1368 if($bots_db_management == 1 && $val == 9000){
1369 modify_db_for_bots();
1370 }
1371 }
1372 $db_run_stage = 2;
1373 }
1374 #::: Run 1 - Initial checking of needed updates...
1375 else{
1376 print "Reading manifest...\n\n";
1377 use Data::Dumper;
1378 open (FILE, "db_update/db_update_manifest.txt");
1379 while (<FILE>) {
1380 chomp;
1381 $o = $_;
1382 if($o=~/#/i){ next; }
1383 @manifest = split('\|', $o);
1384 $m_d{$manifest[0]} = [@manifest];
1385 }
1386 #::: Setting Manifest stage...
1387 $db_run_stage = 1;
1388 }
1389
1390 @total_updates = ();
1391
1392 #::: This is where we set checkpoints for where a database might be so we don't check so far back in the manifest...
1393 $revision_check = 1000;
1394 if(get_mysql_result("SHOW TABLES LIKE 'character_data'") ne ""){
1395 $revision_check = 9000;
1396 }
1397
1398 #::: Iterate through Manifest backwards from binary version down to local version...
1399 for($i = $bin_db_ver; $i > $revision_check; $i--){
1400 if(!defined($m_d{$i}[0])){ next; }
1401
1402 $file_name = trim($m_d{$i}[1]);
1403 $query_check = trim($m_d{$i}[2]);
1404 $match_type = trim($m_d{$i}[3]);
1405 $match_text = trim($m_d{$i}[4]);
1406
1407 #::: Match type update
1408 if($match_type eq "contains"){
1409 if(trim(get_mysql_result($query_check))=~/$match_text/i){
1410 print "Missing DB Update " . $i . " '" . $file_name . "' \n";
1411 fetch_missing_db_update($i, $file_name);
1412 push(@total_updates, $i);
1413 }
1414 else{
1415 print "DB up to date with: " . $i . " - '" . $file_name . "' \n";
1416 }
1417 print_match_debug();
1418 print_break();
1419 }
1420 if($match_type eq "missing"){
1421 if(get_mysql_result($query_check)=~/$match_text/i){
1422 print "DB up to date with: " . $i . " - '" . $file_name . "' \n";
1423 next;
1424 }
1425 else{
1426 print "Missing DB Update " . $i . " '" . $file_name . "' \n";
1427 fetch_missing_db_update($i, $file_name);
1428 push(@total_updates, $i);
1429 }
1430 print_match_debug();
1431 print_break();
1432 }
1433 if($match_type eq "empty"){
1434 if(get_mysql_result($query_check) eq ""){
1435 print "Missing DB Update " . $i . " '" . $file_name . "' \n";
1436 fetch_missing_db_update($i, $file_name);
1437 push(@total_updates, $i);
1438 }
1439 else{
1440 print "DB up to date with: " . $i . " - '" . $file_name . "' \n";
1441 }
1442 print_match_debug();
1443 print_break();
1444 }
1445 if($match_type eq "not_empty"){
1446 if(get_mysql_result($query_check) ne ""){
1447 print "Missing DB Update " . $i . " '" . $file_name . "' \n";
1448 fetch_missing_db_update($i, $file_name);
1449 push(@total_updates, $i);
1450 }
1451 else{
1452 print "DB up to date with: " . $i . " - '" . $file_name . "' \n";
1453 }
1454 print_match_debug();
1455 print_break();
1456 }
1457 }
1458 print "\n";
1459
1460 if(scalar (@total_updates) == 0 && $db_run_stage == 2){
1461 print "No updates need to be run...\n";
1462 if($bots_db_management == 1){
1463 print "Setting Database to Bots Binary Version (" . $bin_db_ver . ") if not already...\n\n";
1464 get_mysql_result("UPDATE db_version SET bots_version = $bin_db_ver");
1465 }
1466 else{
1467 print "Setting Database to Binary Version (" . $bin_db_ver . ") if not already...\n\n";
1468 get_mysql_result("UPDATE db_version SET version = $bin_db_ver");
1469 }
1470
1471 clear_database_runs();
1472 }
1473}
1474
1475sub fetch_missing_db_update{
1476 $db_update = $_[0];
1477 $update_file = $_[1];
1478 if($db_update >= 9000){
1479 if($bots_db_management == 1){
1480 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/bots/required/" . $update_file, "db_update/" . $update_file . "");
1481 }
1482 else{
1483 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/git/required/" . $update_file, "db_update/" . $update_file . "");
1484 }
1485 }
1486 elsif($db_update >= 5000 && $db_update <= 9000){
1487 get_remote_file("https://raw.githubusercontent.com/EQEmu/Server/master/utils/sql/svn/" . $update_file, "db_update/" . $update_file . "");
1488 }
1489}
1490
1491sub print_match_debug{
1492 if(!$debug){ return; }
1493 print " Match Type: '" . $match_type . "'\n";
1494 print " Match Text: '" . $match_text . "'\n";
1495 print " Query Check: '" . $query_check . "'\n";
1496 print " Result: '" . trim(get_mysql_result($query_check)) . "'\n";
1497}
1498sub print_break{
1499 if(!$debug){ return; }
1500 print "\n==============================================\n";
1501}