1 //	This file is part of Glest (www.glest.org)
2 //
3 //	Copyright (C) 2001-2008 Martiño Figueroa
4 //
5 //	You can redistribute this code and/or modify it under
6 //	the terms of the GNU General Public License as published
7 //	by the Free Software Foundation; either version 2 of the
8 //	License, or (at your option) any later version
9 // ==============================================================
10 
11 #ifdef WIN32
12     #include <winsock2.h>
13     #include <winsock.h>
14     #include <process.h>
15 	#include <io.h>
16 #endif
17 
18 #ifdef HAVE_GOOGLE_BREAKPAD
19 #include "handler/exception_handler.h"
20 #endif
21 
22 #include "math_wrapper.h"
23 #include "main.h"
24 
25 #include <string>
26 #include <cstdlib>
27 
28 #include "game.h"
29 #include "main_menu.h"
30 #include "program.h"
31 #include "config.h"
32 #include "metrics.h"
33 #include "game_util.h"
34 #include "platform_util.h"
35 #include "platform_main.h"
36 #include "network_interface.h"
37 #include "ImageReaders.h"
38 #include "renderer.h"
39 #include "simple_threads.h"
40 //#include <memory>
41 #include "font.h"
42 #include <curl/curl.h>
43 #include "menu_state_masterserver.h"
44 #include "checksum.h"
45 #include <algorithm>
46 #include "sound_renderer.h"
47 #include "font_gl.h"
48 #include "FileReader.h"
49 #include "cache_manager.h"
50 #include <iterator>
51 #include "core_data.h"
52 #include "font_text.h"
53 #include <locale.h>
54 #include "string_utils.h"
55 #include "auto_test.h"
56 #include "lua_script.h"
57 #include "interpolation.h"
58 #include "common_scoped_ptr.h"
59 
60 // To handle signal catching
61 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__DragonFly__) && !defined(BSD)
62 #include <signal.h>
63 #endif
64 
65 #if defined WIN32 && !defined(HAVE_GOOGLE_BREAKPAD)
66 #if defined(__WIN32__) && !defined(__GNUC__)
67 #include <eh.h>
68 #endif
69 #include <dbghelp.h>
70 #endif
71 
72 #ifndef WIN32
73   #include <poll.h>
74 
75   #define stricmp strcasecmp
76   #define strnicmp strncasecmp
77   #define _strnicmp strncasecmp
78 #endif
79 
80 #include <stdlib.h>
81 #include "network_message.h"
82 #include "network_protocol.h"
83 #include "conversion.h"
84 #include "gen_uuid.h"
85 //#include "intro.h"
86 #include "leak_dumper.h"
87 
88 #if defined(WIN32)
89 #ifndef _DEBUG
90 #ifndef __GNUC__
91 
92 #define WIN32_STACK_TRACE
93 
94 #endif
95 #endif
96 #endif
97 
98 using namespace std;
99 using namespace Shared::Platform;
100 using namespace Shared::Util;
101 using namespace Shared::Graphics;
102 using namespace Shared::Graphics::Gl;
103 using namespace Shared::Xml;
104 using namespace Shared;
105 
106 /**
107  * @namespace Glest
108  * Namespace used for all %Glest related code.
109  */
110 /**
111  * @namespace Game
112  * Namespace used for game related code.
113  */
114 namespace Glest { namespace Game {
115 
116 static string tempDataLocation 			= getUserHome();
117 static string mg_app_name 				= "";
118 static string mailStringSupport 		= "";
119 static bool sdl_quitCalled 			= false;
120 
121 static bool disableheadless_console 			= false;
122 static bool disableBacktrace 					= false;
123 static bool gameInitialized 					= false;
124 
125 static Program *mainProgram 					= NULL;
126 static FileCRCPreCacheThread *preCacheThread	= NULL;
127 #ifdef WIN32
128 static string runtimeErrorMsg 					= "";
129 // keeps in scope for duration of the application
130 //SocketManager *winSockManager = NULL;
131 
132 #endif
133 
134 #ifdef HAVE_GOOGLE_BREAKPAD
135 auto_ptr<google_breakpad::ExceptionHandler> errorHandlerPtr;
136 #endif
137 
138 class NavtiveLanguageNameListCacheGenerator : public SimpleTaskCallbackInterface {
simpleTask(BaseThread * callingThread,void * userdata)139 	virtual void simpleTask(BaseThread *callingThread,void *userdata) {
140 		Lang &lang = Lang::getInstance();
141 		lang.getDiscoveredLanguageList(true);
142 	}
143 };
144 
145 // =====================================================
146 // 	class ExceptionHandler
147 // =====================================================
148 class ExceptionHandler: public PlatformExceptionHandler{
149 public:
150 
151 #if defined(__WIN32__) && !defined(__GNUC__)
152 	virtual void handle(LPEXCEPTION_POINTERS pointers);
153 #endif
154 
155 	virtual void handle();
156 
157     static void logError(const char *msg, bool confirmToConsole);
158     static void handleRuntimeError(const megaglest_runtime_error &ex);
159 	static void handleRuntimeError(const char *msg, bool getStackTraceString);
160 	static int DisplayMessage(const char *msg, bool exitApp);
161 };
162 
cleanupCRCThread()163 void cleanupCRCThread() {
164 	if(preCacheThread != NULL) {
165 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
166 
167 		const double MAX_THREAD_WAIT = 60;
168 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("START - shutting down crc threads\n");
169 		time_t elapsed = time(NULL);
170 		preCacheThread->signalQuit();
171 		for(;preCacheThread->canShutdown(false) == false &&
172 			difftime((long int)time(NULL),elapsed) <= MAX_THREAD_WAIT;) {
173 		}
174 		if(difftime((long int)time(NULL),elapsed) <= MAX_THREAD_WAIT) {
175 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("B - shutting down crc threads\n");
176 
177 			for(;preCacheThread->shutdownAndWait() == false &&
178 				difftime((long int)time(NULL),elapsed) <= MAX_THREAD_WAIT;) {
179 			}
180 			if(preCacheThread->getRunningStatus() == false) {
181 				delete preCacheThread;
182 				preCacheThread=NULL;
183 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("C - shutting down crc threads\n");
184 			}
185 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
186 		}
187 		else {
188 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("D - shutting down crc threads\n");
189 
190 			if(preCacheThread->canShutdown(false) == true) {
191 				if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
192 				delete preCacheThread;
193 				preCacheThread=NULL;
194 
195 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("E - shutting down crc threads\n");
196 			}
197 		}
198 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("F - shutting down crc threads\n");
199 		preCacheThread = NULL;
200 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
201 	}
202 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
203 }
204 
cleanupProcessObjects()205 static void cleanupProcessObjects() {
206 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
207 
208 	if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
209 		showCursor(true);
210 		restoreVideoMode(::Shared::Platform::Window::getSDLWindow(), true);
211 	}
212 
213 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#1 IRCCLient Cache SHUTDOWN\n");
214 	IRCThread * &ircClient = CacheManager::getCachedItem< IRCThread * >(GameConstants::ircClientCacheLookupKey);
215     if(ircClient != NULL) {
216     	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#2 IRCCLient Cache SHUTDOWN\n");
217     	if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
218 
219     	ircClient->disconnect();
220 		ircClient->signalQuit();
221     	ircClient = NULL;
222     	sleep(0);
223     }
224     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#4 IRCCLient Cache SHUTDOWN\n");
225 
226     cleanupCRCThread();
227     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
228 
229     if(Renderer::isEnded() == false) {
230     	Renderer::getInstance().end();
231     	CoreData &coreData= CoreData::getInstance();
232         coreData.cleanup();
233     }
234 
235     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
236 
237 	SystemFlags::Close();
238 	SystemFlags::SHUTDOWN_PROGRAM_MODE=true;
239 
240 	//printf("Closing IRC CLient %d\n",__LINE__);
241 
242 	Thread::shutdownThreads();
243 
244 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("start running threads = " MG_SIZE_T_SPECIFIER "\n",Thread::getThreadList().size());
245 	time_t elapsed = time(NULL);
246 	int lastLazyThreadDump = 0;
247     for(;Thread::getThreadList().size() > 0 &&
248     	 difftime((long int)time(NULL),elapsed) <= 10;) {
249 
250     	if(difftime((long int)time(NULL),elapsed) > 1) {
251 			if(lastLazyThreadDump != (int)difftime((long int)time(NULL),elapsed)) {
252 				lastLazyThreadDump = difftime((long int)time(NULL),elapsed);
253 
254 				printf("Waiting for the following threads to exit [" MG_SIZE_T_SPECIFIER "]:\n",Thread::getThreadList().size());
255 
256 				for(int i = 0; i < (int)Thread::getThreadList().size(); ++i) {
257 					BaseThread *baseThread = dynamic_cast<BaseThread *>(Thread::getThreadList()[i]);
258 					printf("Thread index: %d ptr [%p] isBaseThread: %d, Name: [%s]\n",i,baseThread,(baseThread != NULL ? 1 : 0),(baseThread != NULL ? baseThread->getUniqueID().c_str() : "<na>"));
259 				}
260 			}
261     	}
262     }
263     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("end running threads = " MG_SIZE_T_SPECIFIER "\n",Thread::getThreadList().size());
264 
265     Thread::shutdownThreads();
266 
267 	std::map<int,Texture2D *> &crcPlayerTextureCache = CacheManager::getCachedItem< std::map<int,Texture2D *> >(GameConstants::playerTextureCacheLookupKey);
268 	crcPlayerTextureCache.clear();
269 
270 	std::map<string,Texture2D *> &crcFactionPreviewTextureCache = CacheManager::getCachedItem< std::map<string,Texture2D *> >(GameConstants::factionPreviewTextureCacheLookupKey);
271 	crcFactionPreviewTextureCache.clear();
272 
273 	std::map<string, vector<FileReader<Pixmap2D> const * >* > &list2d = FileReader<Pixmap2D>::getFileReadersMap();
274 	deleteMapValues(list2d.begin(),list2d.end());
275 	std::map<string, vector<FileReader<Pixmap3D> const * >* > &list3d = FileReader<Pixmap3D>::getFileReadersMap();
276 	deleteMapValues(list3d.begin(),list3d.end());
277 
278 #if defined(WANT_XERCES)
279 
280 	XmlIo::getInstance().cleanup();
281 
282 #endif
283 
284 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
285 
286 	SystemFlags::globalCleanupHTTP();
287 	CacheManager::cleanupMutexes();
288 }
289 
290 #if defined(WIN32) && !defined(_DEBUG) && !defined(__GNUC__)
fatal(const char * s,...)291 void fatal(const char *s, ...)    // failure exit
292 {
293     static int errors = 0;
294     errors++;
295 
296 	if(errors <= 5) { // print up to two extra recursive errors
297         defvformatstring(msg,s,s);
298 		string errText = string(msg) + " [" + runtimeErrorMsg + "]";
299         //puts(msg);
300 	    string sErr = string(mg_app_name) + " fatal error";
301 		SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",errText.c_str());
302 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n",errText.c_str());
303 
304 		if(errors <= 1) { // avoid recursion
305             if(SDL_WasInit(SDL_INIT_VIDEO)) {
306                 SDL_SetRelativeMouseMode(SDL_FALSE);
307             }
308             #ifdef WIN32
309 				LPWSTR wstr = Ansi2WideString(errText.c_str());
310 				LPWSTR wstr1 = Ansi2WideString(sErr.c_str());
311 
312 				if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
313 					MessageBox(NULL, wstr, wstr1, MB_OK|MB_SYSTEMMODAL);
314 				}
315 
316 				if(wstr) delete [] wstr;
317 				if(wstr1) delete [] wstr1;
318             #endif
319         }
320     }
321 
322     // Now try to shutdown threads if possible
323     delete mainProgram;
324     mainProgram = NULL;
325     // END
326 
327     if(sdl_quitCalled == false) {
328     	sdl_quitCalled = true;
329     	SDL_Quit();
330     }
331     exit(EXIT_FAILURE);
332 }
333 
get_module_path(HMODULE module=0)334 std::string get_module_path(HMODULE module = 0) {
335   char path_name[MAX_PATH] = {};
336   DWORD size = GetModuleFileNameA(module, path_name, MAX_PATH);
337   return std::string(path_name, size);
338 }
write_module_name(string & out,HANDLE process,DWORD64 program_counter)339 void write_module_name(string &out, HANDLE process, DWORD64 program_counter) {
340   DWORD64 module_base = SymGetModuleBase64(process, program_counter);
341   if (module_base) {
342     std::string module_name = get_module_path(reinterpret_cast<HMODULE>(module_base));
343     if (!module_name.empty())
344       out += module_name + "|";
345     else
346       out += "Unknown module|";
347   } else {
348     out += "Unknown module|";
349   }
350 }
351 
write_function_name(string & out,HANDLE process,DWORD64 program_counter)352 void write_function_name(string &out, HANDLE process, DWORD64 program_counter) {
353   SYMBOL_INFO_PACKAGE sym = { sizeof(sym) };
354   sym.si.MaxNameLen = MAX_SYM_NAME;
355   if (SymFromAddr(process, program_counter, 0, &sym.si)) {
356     out += string(sym.si.Name) + "()";
357   } else {
358     out += "Unknown function";
359   }
360 }
361 
write_file_and_line(string & out,HANDLE process,DWORD64 program_counter)362 void write_file_and_line(string & out, HANDLE process, DWORD64 program_counter) {
363   IMAGEHLP_LINE64 ih_line = { sizeof(IMAGEHLP_LINE64) };
364   DWORD dummy = 0;
365   if (SymGetLineFromAddr64(process, program_counter, &dummy, &ih_line)) {
366     out += string("|") + string(ih_line.FileName) + ":" + intToStr(ih_line.LineNumber);
367   }
368 }
generate_stack_trace(string & out,CONTEXT ctx,int skip)369 void generate_stack_trace(string &out, CONTEXT ctx, int skip) {
370   STACKFRAME64 sf = {};
371 #if !defined(_WIN64)
372   sf.AddrPC.Offset    = ctx.Eip;
373 #else
374   sf.AddrPC.Offset    = ctx.Rip;
375 #endif
376   sf.AddrPC.Mode      = AddrModeFlat;
377 #if !defined(_WIN64)
378   sf.AddrStack.Offset = ctx.Esp;
379 #else
380   sf.AddrStack.Offset = ctx.Rsp;
381 #endif
382   sf.AddrStack.Mode   = AddrModeFlat;
383 #if !defined(_WIN64)
384   sf.AddrFrame.Offset = ctx.Ebp;
385 #else
386   sf.AddrFrame.Offset = ctx.Rbp;
387 #endif
388   sf.AddrFrame.Mode   = AddrModeFlat;
389 
390   HANDLE process = GetCurrentProcess();
391   HANDLE thread = GetCurrentThread();
392 
393   bool tryThreadContext = true;
394   CONTEXT threadContext;
395   memset(&threadContext, 0, sizeof(CONTEXT));
396   threadContext.ContextFlags = CONTEXT_FULL;
397 
398   for (;;) {
399     SetLastError(0);
400 #if !defined(_WIN64)
401     BOOL stack_walk_ok = StackWalk64(IMAGE_FILE_MACHINE_I386,
402 #else
403 	BOOL stack_walk_ok = StackWalk64(IMAGE_FILE_MACHINE_AMD64,
404 #endif
405 									process, thread, &sf,
406                                      (tryThreadContext == false ? &threadContext : &ctx),
407 									 0, &SymFunctionTableAccess64,
408                                      &SymGetModuleBase64, 0);
409     if (!stack_walk_ok || !sf.AddrFrame.Offset) {
410 		if(tryThreadContext == true) {
411 			tryThreadContext = false;
412 			if(GetThreadContext(thread, &threadContext) != 0) {
413 #if !defined(_WIN64)
414 			  sf.AddrPC.Offset    = threadContext.Eip;
415 #else
416 				sf.AddrPC.Offset    = threadContext.Rip;
417 #endif
418 			  sf.AddrPC.Mode      = AddrModeFlat;
419 #if !defined(_WIN64)
420 			  sf.AddrStack.Offset = threadContext.Esp;
421 #else
422 			  sf.AddrStack.Offset = threadContext.Rsp;
423 #endif
424 			  sf.AddrStack.Mode   = AddrModeFlat;
425 #if !defined(_WIN64)
426 			  sf.AddrFrame.Offset = threadContext.Ebp;
427 #else
428 			  sf.AddrFrame.Offset = threadContext.Rbp;
429 #endif
430 			  sf.AddrFrame.Mode   = AddrModeFlat;
431 			}
432 			else {
433 				return;
434 			}
435 		}
436 		else {
437 			return;
438 		}
439 	}
440 
441     if (skip) {
442 		--skip;
443     }
444 	else {
445       // write the address
446 		out += intToStr(sf.AddrPC.Offset) + "|";
447 
448 		write_module_name(out, process, sf.AddrPC.Offset);
449 		write_function_name(out, process, sf.AddrPC.Offset);
450 		write_file_and_line(out, process, sf.AddrPC.Offset);
451 
452 		out += "\n";
453     }
454   }
455 }
456 
457 struct UntypedException {
UntypedExceptionGlest::Game::UntypedException458   UntypedException(const EXCEPTION_RECORD & er)
459     : exception_object(reinterpret_cast<void *>(er.ExceptionInformation[1])),
460       type_array(reinterpret_cast<_ThrowInfo *>(er.ExceptionInformation[2])->pCatchableTypeArray)
461   {}
462   void * exception_object;
463   _CatchableTypeArray * type_array;
464 };
465 
exception_cast_worker(const UntypedException & e,const type_info & ti)466 void * exception_cast_worker(const UntypedException & e, const type_info & ti) {
467   for (int i = 0; i < e.type_array->nCatchableTypes; ++i) {
468     _CatchableType & type_i = *e.type_array->arrayOfCatchableTypes[i];
469     const std::type_info & ti_i = *reinterpret_cast<std::type_info *>(type_i.pType);
470     if (ti_i == ti) {
471       char * base_address = reinterpret_cast<char *>(e.exception_object);
472       base_address += type_i.thisDisplacement.mdisp;
473       return base_address;
474     }
475   }
476   return 0;
477 }
478 
479 template <typename T>
exception_cast(const UntypedException & e)480 T * exception_cast(const UntypedException & e) {
481   const std::type_info & ti = typeid(T);
482   return reinterpret_cast<T *>(exception_cast_worker(e, ti));
483 }
stackdumper(unsigned int type,EXCEPTION_POINTERS * ep,bool fatalExit)484 void stackdumper(unsigned int type, EXCEPTION_POINTERS *ep, bool fatalExit) {
485 #ifdef HAVE_GOOGLE_BREAKPAD
486 	if(errorHandlerPtr.get() != NULL) {
487 		errorHandlerPtr->WriteMinidump();
488 	}
489 #endif
490 	if(!ep) {
491 		fatal("unknown type");
492 		return;
493 	}
494     EXCEPTION_RECORD *er = ep->ExceptionRecord;
495     CONTEXT *context = ep->ContextRecord;
496     string out="";
497     int skip = 0;
498 
499     switch (er->ExceptionCode) {
500        case 0xE06D7363: { // C++ exception
501          UntypedException ue(*er);
502          if (std::exception * e = exception_cast<std::exception>(ue)) {
503 			const std::type_info & ti = typeid(*e);
504 			out += string(ti.name()) + ":" + string(e->what());
505          }
506 		 else {
507 			out += "Unknown C++ exception thrown.";
508          }
509          skip = 2; // skip RaiseException and _CxxThrowException
510        } break;
511        case EXCEPTION_ACCESS_VIOLATION: {
512          out += string("Access violation. Illegal ")
513               + (er->ExceptionInformation[0] ? "write" : "read")
514               + string(" by ")
515               + intToStr((int)er->ExceptionAddress)
516               + string(" at ")
517 			  + intToStr(er->ExceptionInformation[1]);
518        } break;
519        default: {
520          out += "SEH exception thrown. Exception code: "
521               + er->ExceptionCode
522               + string(" at ")
523               + intToStr((int)er->ExceptionAddress);
524        }
525     }
526 
527     generate_stack_trace(out, *context, skip);
528 
529 	if(fatalExit == true) {
530 		fatal(out.c_str());
531 	}
532 	else {
533 		ExceptionHandler::logError(out.c_str(), true);
534 	}
535 }
536 #endif
537 
538 // =====================================================
539 // 	class ExceptionHandler
540 // =====================================================
541 #if defined(WIN32) && !defined(__GNUC__)
handle(LPEXCEPTION_POINTERS pointers)542 	void ExceptionHandler::handle(LPEXCEPTION_POINTERS pointers) {
543 		string msg = "#1 An error occurred and " + string(mg_app_name) + " will close.\nPlease report this bug to: " + string(mailString);
544 		msg += ", attaching the generated " + getCrashDumpFileName()+ " file.";
545 
546 		SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",msg.c_str());
547 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n",msg.c_str());
548 
549 		stackdumper(0, pointers, false);
550 
551         if(mainProgram && gameInitialized == true) {
552         	mainProgram->showMessage(msg.c_str());
553         }
554 
555         message(msg.c_str(),GlobalStaticFlags::getIsNonGraphicalModeEnabled(),tempDataLocation);
556 }
557 #endif
558 
handle()559 	void ExceptionHandler::handle() {
560 		string msg = "#1 An error occurred and " + string(mg_app_name) + " will close.\nPlease report this bug to: " + string(mailString);
561 #ifdef WIN32
562 		msg += ", attaching the generated " + getCrashDumpFileName()+ " file.";
563 #endif
564 		SystemFlags::OutputDebug(SystemFlags::debugError,"%s\n",msg.c_str());
565 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n",msg.c_str());
566 
567         if(mainProgram && gameInitialized == true) {
568         	mainProgram->showMessage(msg.c_str());
569         }
570 
571         message(msg.c_str(),GlobalStaticFlags::getIsNonGraphicalModeEnabled(),tempDataLocation);
572 	}
573 
logError(const char * msg,bool confirmToConsole)574     void ExceptionHandler::logError(const char *msg, bool confirmToConsole) {
575 		string errorLogFile = "error.log";
576 		if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
577 			errorLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + errorLogFile;
578 		}
579 		else {
580 	        string userData = Config::getInstance().getString("UserData_Root","");
581 	        if(userData != "") {
582 	        	endPathWithSlash(userData);
583 	        }
584 	        errorLogFile = userData + errorLogFile;
585 		}
586 
587 #if defined(WIN32) && !defined(__MINGW32__)
588 		FILE *fp = _wfopen(utf8_decode(errorLogFile).c_str(), L"w");
589 		std::ofstream logFile(fp);
590 #else
591 		std::ofstream logFile;
592 		logFile.open(errorLogFile.c_str(), ios_base::out | ios_base::trunc);
593 #endif
594 
595 		if(logFile.is_open() == true) {
596 			//time_t curtime = time (NULL);
597 			//struct tm *loctime = localtime (&curtime);
598 			struct tm loctime = threadsafe_localtime(systemtime_now());
599 			char szBuf2[100]="";
600 			strftime(szBuf2,100,"%Y-%m-%d %H:%M:%S",&loctime);
601 
602 			logFile << "[" << szBuf2 << "] Runtime Error information:"  << std::endl;
603 			logFile << "======================================================"  << std::endl;
604 			logFile << (msg != NULL ? msg : "null") << std::endl;
605 			logFile.close();
606 
607 #if defined(WIN32) && !defined(__MINGW32__)
608 			if(fp) {
609 				fclose(fp);
610 			}
611 #endif
612 			if(confirmToConsole == true) {
613 				printf("Error saved to logfile [%s]\n",errorLogFile.c_str());
614 				fflush(stdout);
615 			}
616 		}
617 		else {
618 			if(confirmToConsole == true) {
619 				printf("COULD NOT SAVE TO ERROR logfile [%s]\n",errorLogFile.c_str());
620 				fflush(stdout);
621 			}
622 		}
623     }
624 
handleRuntimeError(const megaglest_runtime_error & ex)625     void ExceptionHandler::handleRuntimeError(const megaglest_runtime_error &ex) {
626 		const char *msg = ex.what();
627 		handleRuntimeError(msg,false);
628     }
629 
handleRuntimeError(const char * msg,bool getStackTraceString)630 	void ExceptionHandler::handleRuntimeError(const char *msg, bool getStackTraceString) {
631 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
632 
633 		static bool inErrorNow = false;
634 		if(inErrorNow == true) {
635 			printf("\n=====================================\n");
636 			printf("\n** Already in error handler aborting, msg [%s]\n",msg);
637 			fflush(stdout);
638 			abort();
639 			return;
640 		}
641 		inErrorNow = true;
642 
643 		logError(msg,true);
644 
645 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] program = %p gameInitialized = %d msg [%s]\n",__FILE__,__FUNCTION__,__LINE__,mainProgram,gameInitialized,msg);
646 		SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] [%s] gameInitialized = %d, program = %p\n",__FILE__,__FUNCTION__,__LINE__,msg,gameInitialized,mainProgram);
647 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%s] gameInitialized = %d, program = %p\n",__FILE__,__FUNCTION__,__LINE__,msg,gameInitialized,mainProgram);
648 
649         string errMsg = (msg != NULL ? msg : "null");
650 
651         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
652 
653         bool gotStackTrace = false;
654         if(getStackTraceString == true && disableBacktrace == false && sdl_quitCalled == false) {
655         	string stackTrace = getStackTrace();
656         	errMsg += stackTrace;
657         	gotStackTrace = true;
658         }
659 
660         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
661 
662         logError(errMsg.c_str(),false);
663 
664         if(gotStackTrace == true) {
665         	SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] [%s]\n",__FILE__,__FUNCTION__,__LINE__,errMsg.c_str());
666         }
667 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%s]\n",__FILE__,__FUNCTION__,__LINE__,errMsg.c_str());
668 
669 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
670 
671 		//abort();
672 
673         if(mainProgram && gameInitialized == true) {
674         	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
675 
676 			if(mainProgram->getState() != NULL) {
677 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
678 				mainProgram->showMessage(errMsg.c_str());
679                 if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
680 
681 				if(glActiveTexture != NULL) {
682 					for(;GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false && mainProgram->isMessageShowing();) {
683 						::Shared::Platform::Window::handleEvent();
684 						try {
685 							mainProgram->loop();
686 						}
687 						catch(const exception &e) {
688 							printf("\n=====================================\n");
689 							printf("\n** Already in error handler exiting error rendering, msg [%s]\n",e.what());
690 							fflush(stdout);
691 							break;
692 						}
693 					}
694 				}
695 			}
696 			else {
697 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
698 				mainProgram->showMessage(errMsg.c_str());
699                 if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
700 
701 				if(glActiveTexture != NULL) {
702 					for(;GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false && mainProgram->isMessageShowing();) {
703 						::Shared::Platform::Window::handleEvent();
704 						try {
705 							mainProgram->loop();
706 						}
707 						catch(const exception &e) {
708 							printf("\n=====================================\n");
709 							printf("\n** Already in error handler exiting error rendering, msg [%s]\n",e.what());
710 							fflush(stdout);
711 							break;
712 						}
713 					}
714 				}
715 			}
716 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
717         }
718         else {
719         	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
720 
721             string err = "#2 An error occurred and ";
722             if(sdl_quitCalled == false) {
723             	err += mg_app_name;
724             }
725             err += " will close.\nError msg = [" + errMsg + "]\n\nPlease report this bug to ";
726             if(sdl_quitCalled == false) {
727             	err += mailStringSupport;
728             }
729 #ifdef WIN32
730             err += string(", attaching the generated ") + getCrashDumpFileName() + string(" file.");
731 #endif
732             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
733 
734 			message(err,GlobalStaticFlags::getIsNonGraphicalModeEnabled(),tempDataLocation);
735         }
736 
737         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
738 
739         // Now try to shutdown threads if possible
740         delete mainProgram;
741         mainProgram = NULL;
742         // END
743 
744         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
745 
746 #ifdef WIN32
747 
748         if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
749         	showCursor(true);
750         	restoreVideoMode(::Shared::Platform::Window::getSDLWindow(), true);
751         }
752 
753 		runtimeErrorMsg = errMsg;
754 		inErrorNow = false;
755 		throw runtimeErrorMsg;
756 #endif
757 
758 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
759 
760 		cleanupProcessObjects();
761 
762 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
763 
764 	    if(sdl_quitCalled == false) {
765 	    	sdl_quitCalled = true;
766 	    	SDL_Quit();
767 	    }
768 
769 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
770 
771 		inErrorNow = false;
772 
773         abort();
774 	}
775 
DisplayMessage(const char * msg,bool exitApp)776 	int ExceptionHandler::DisplayMessage(const char *msg, bool exitApp) {
777 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
778 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
779 
780         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
781 
782         if(mainProgram && gameInitialized == true) {
783         	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
784         	mainProgram->showMessage(msg);
785         }
786         else {
787         	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
788             message(msg,GlobalStaticFlags::getIsNonGraphicalModeEnabled(),tempDataLocation);
789         }
790 
791         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
792 
793         if(exitApp == true) {
794 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s\n",msg);
795 
796 		    // Now try to shutdown threads if possible
797 		    delete mainProgram;
798 		    mainProgram = NULL;
799 		    // END
800 
801 		    if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
802 		    cleanupProcessObjects();
803 
804 		    if(sdl_quitCalled == false) {
805 		    	sdl_quitCalled = true;
806 		    	SDL_Quit();
807 		    }
808 		    exit(-1);
809         }
810 
811         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] msg [%s] exitApp = %d\n",__FILE__,__FUNCTION__,__LINE__,msg,exitApp);
812 	    return 0;
813 	}
814 
815 // =====================================================
816 // 	class MainWindow
817 // =====================================================
818 
MainWindow(Program * program)819 MainWindow::MainWindow(Program *program) : WindowGl(), popupMenu("MainWindow", "popupMenu") {
820 	this->program= program;
821 	//this->popupMenu.registerGraphicComponentOnlyFontCallbacks("MainWindow", "popupMenu");
822 	this->popupMenu.setEnabled(false);
823 	this->popupMenu.setVisible(false);
824     this->triggerLanguageToggle = false;
825     this->triggerLanguage = "";
826     this->cancelLanguageSelection = -1;
827 }
828 
~MainWindow()829 MainWindow::~MainWindow(){
830 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
831 	delete program;
832 	program = NULL;
833 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
834 }
835 
getDesiredScreenWidth()836 int MainWindow::getDesiredScreenWidth() {
837 	Config &config= Config::getInstance();
838 	return config.getInt("ScreenWidth");
839 }
getDesiredScreenHeight()840 int MainWindow::getDesiredScreenHeight() {
841 	Config &config= Config::getInstance();
842 	return config.getInt("ScreenHeight");
843 }
844 
eventToggleFullScreen(bool isFullscreen)845 void MainWindow::eventToggleFullScreen(bool isFullscreen) {
846 	WindowGl::eventToggleFullScreen(isFullscreen);
847 
848 	if(isFullscreen) {
849 		Metrics::reload(this->program->getWindow()->getScreenWidth(),
850 				this->program->getWindow()->getScreenHeight());
851 	}
852 	else {
853 		Config &config= Config::getInstance();
854 		Metrics::reload(config.getInt("ScreenWidth"),config.getInt("ScreenHeight"));
855 		//window->setText(config.getString("WindowTitle","MegaGlest"));
856 		//this->mainMenu->init();
857 	}
858 
859 }
860 
eventMouseDown(int x,int y,MouseButton mouseButton)861 void MainWindow::eventMouseDown(int x, int y, MouseButton mouseButton){
862     const Metrics &metrics = Metrics::getInstance();
863     int vx = metrics.toVirtualX(x);
864     int vy = metrics.toVirtualY(getH() - y);
865 
866     if(program == NULL) {
867     	throw megaglest_runtime_error("In [MainWindow::eventMouseDown] ERROR, program == NULL!");
868     }
869 
870 	if(popupMenu.getVisible() == true && popupMenu.mouseClick(vx, vy)) {
871 		std::pair<int,string> result = popupMenu.mouseClickedMenuItem(vx, vy);
872 
873 		popupMenu.setEnabled(false);
874 		popupMenu.setVisible(false);
875 
876 		// Exit game
877 		if(result.first != cancelLanguageSelection) {
878 			Lang &lang= Lang::getInstance();
879 			map<string,string> languageList = lang.getDiscoveredLanguageList(true);
880 			for(map<string,string>::iterator iterMap = languageList.begin();
881 				iterMap != languageList.end(); ++iterMap) {
882 				string matchLanguage = iterMap->first + "-" + iterMap->second;
883 				if(matchLanguage == result.second) {
884 					this->triggerLanguageToggle = true;
885 					this->triggerLanguage = iterMap->first;
886 					break;
887 				}
888 			}
889 
890 		}
891 
892 		return;
893 	}
894     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
895 
896 	switch(mouseButton) {
897 		case mbLeft:
898 			program->mouseDownLeft(vx, vy);
899 			break;
900 		case mbRight:
901 			//program->mouseDownRight(vx, vy);
902 			break;
903 		case mbCenter:
904 			//program->mouseDownCenter(vx, vy);
905 			break;
906 		default:
907 			break;
908 	}
909 
910 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
911 
912     ProgramState *programState = program->getState();
913     if(programState != NULL) {
914 		switch(mouseButton) {
915 			case mbLeft:
916 				programState->mouseDownLeft(vx, vy);
917 				break;
918 			case mbRight:
919 				programState->mouseDownRight(vx, vy);
920 				break;
921 			case mbCenter:
922 				programState->mouseDownCenter(vx, vy);
923 				break;
924 			default:
925 				break;
926 		}
927 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
928     }
929     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
930 }
931 
eventMouseUp(int x,int y,MouseButton mouseButton)932 void MainWindow::eventMouseUp(int x, int y, MouseButton mouseButton){
933 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
934 
935     const Metrics &metrics = Metrics::getInstance();
936     int vx = metrics.toVirtualX(x);
937     int vy = metrics.toVirtualY(getH() - y);
938 
939     if(program == NULL) {
940     	throw megaglest_runtime_error("In [MainWindow::eventMouseUp] ERROR, program == NULL!");
941     }
942 
943     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
944 
945     ProgramState *programState = program->getState();
946 
947     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
948 
949     if(programState != NULL) {
950     	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
951 
952 		switch(mouseButton) {
953 			case mbLeft:
954 				programState->mouseUpLeft(vx, vy);
955 				break;
956 			case mbRight:
957 				programState->mouseUpRight(vx, vy);
958 				break;
959 			case mbCenter:
960 				programState->mouseUpCenter(vx, vy);
961 				break;
962 			default:
963 				break;
964 		}
965 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
966     }
967     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
968 }
969 
eventMouseDoubleClick(int x,int y,MouseButton mouseButton)970 void MainWindow::eventMouseDoubleClick(int x, int y, MouseButton mouseButton) {
971 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
972 
973     const Metrics &metrics= Metrics::getInstance();
974     int vx = metrics.toVirtualX(x);
975     int vy = metrics.toVirtualY(getH() - y);
976 
977     if(program == NULL) {
978     	throw megaglest_runtime_error("In [MainWindow::eventMouseDoubleClick] ERROR, program == NULL!");
979     }
980 
981     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
982 
983     ProgramState *programState = program->getState();
984 
985     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
986 
987     if(programState != NULL) {
988     	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
989 
990 		switch(mouseButton){
991 			case mbLeft:
992 				programState->mouseDoubleClickLeft(vx, vy);
993 				break;
994 			case mbRight:
995 				programState->mouseDoubleClickRight(vx, vy);
996 				break;
997 			case mbCenter:
998 				programState->mouseDoubleClickCenter(vx, vy);
999 				break;
1000 			default:
1001 				break;
1002 		}
1003 
1004 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1005     }
1006     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1007 }
1008 
eventMouseMove(int x,int y,const MouseState * ms)1009 void MainWindow::eventMouseMove(int x, int y, const MouseState *ms){
1010 
1011     const Metrics &metrics= Metrics::getInstance();
1012     int vx = metrics.toVirtualX(x);
1013     int vy = metrics.toVirtualY(getH() - y);
1014 
1015     if(program == NULL) {
1016     	throw megaglest_runtime_error("In [MainWindow::eventMouseMove] ERROR, program == NULL!");
1017     }
1018 
1019     program->eventMouseMove(vx, vy, ms);
1020 
1021     ProgramState *programState = program->getState();
1022     if(programState != NULL) {
1023     	programState->mouseMove(vx, vy, ms);
1024     }
1025 }
1026 
eventMouseWheel(int x,int y,int zDelta)1027 void MainWindow::eventMouseWheel(int x, int y, int zDelta) {
1028 
1029     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1030 
1031 	const Metrics &metrics= Metrics::getInstance();
1032 	int vx = metrics.toVirtualX(x);
1033 	int vy = metrics.toVirtualY(getH() - y);
1034 
1035     if(program == NULL) {
1036     	throw megaglest_runtime_error("In [MainWindow::eventMouseMove] ERROR, program == NULL!");
1037     }
1038 
1039     ProgramState *programState = program->getState();
1040 
1041     if(programState != NULL) {
1042     	programState->eventMouseWheel(vx, vy, zDelta);
1043     }
1044 
1045 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1046 }
1047 
render()1048 void MainWindow::render() {
1049 	if(popupMenu.getVisible() == true) {
1050 		Renderer &renderer= Renderer::getInstance();
1051 		renderer.renderPopupMenu(&popupMenu);
1052 	}
1053 }
1054 
showLanguages()1055 void MainWindow::showLanguages() {
1056 	Lang &lang= Lang::getInstance();
1057 	std::vector<string> menuItems;
1058 	map<string,string> languageList = lang.getDiscoveredLanguageList(true);
1059 	for(map<string,string>::iterator iterMap = languageList.begin();
1060 		iterMap != languageList.end(); ++iterMap) {
1061 		menuItems.push_back(iterMap->first + "-" + iterMap->second);
1062 	}
1063 
1064 	menuItems.push_back(lang.getString("Exit"));
1065 	cancelLanguageSelection = (int)menuItems.size()-1;
1066 
1067 	popupMenu.setW(100);
1068 	popupMenu.setH(100);
1069 	popupMenu.init(lang.getString("GameMenuTitle"),menuItems);
1070 	popupMenu.setEnabled(true);
1071 	popupMenu.setVisible(true);
1072 }
1073 
toggleLanguage(string language)1074 void MainWindow::toggleLanguage(string language) {
1075 	popupMenu.setEnabled(false);
1076 	popupMenu.setVisible(false);
1077     this->triggerLanguageToggle = false;
1078     this->triggerLanguage = "";
1079 
1080 	Lang &lang= Lang::getInstance();
1081 	string currentLanguage = lang.getLanguage();
1082 
1083 	string newLanguageSelected = language;
1084 	if(language == "") {
1085 		newLanguageSelected = currentLanguage;
1086 
1087 		vector<string> langResults;
1088 	    string data_path = getGameReadWritePath(GameConstants::path_data_CacheLookupKey);
1089 
1090 	    string userDataPath = getGameCustomCoreDataPath(data_path, "");
1091 		findAll(userDataPath + "data/lang/*.lng", langResults, true, false);
1092 
1093 		vector<string> langResults2;
1094 		findAll(data_path + "data/lang/*.lng", langResults2, true);
1095 		if(langResults2.empty() && langResults.empty()) {
1096 	        throw megaglest_runtime_error("There are no lang files");
1097 		}
1098 		for(unsigned int i = 0; i < langResults2.size(); ++i) {
1099 			string testLanguage = langResults2[i];
1100 			if(std::find(langResults.begin(),langResults.end(),testLanguage) == langResults.end()) {
1101 				langResults.push_back(testLanguage);
1102 			}
1103 		}
1104 
1105 		for(unsigned int i = 0; i < langResults.size(); ++i) {
1106 			string testLanguage = langResults[i];
1107 			if(testLanguage == currentLanguage) {
1108 				if( i+1 < langResults.size()) {
1109 					newLanguageSelected = langResults[i+1];
1110 				}
1111 				else {
1112 					newLanguageSelected = langResults[0];
1113 				}
1114 				break;
1115 			}
1116 		}
1117 	}
1118 	if(newLanguageSelected != currentLanguage) {
1119 		lang.loadGameStrings(newLanguageSelected);
1120 		program->reloadUI();
1121 		program->consoleAddLine(lang.getString("Language") + " " + newLanguageSelected);
1122 	}
1123 }
1124 
eventTextInput(std::string text)1125 bool MainWindow::eventTextInput(std::string text) {
1126 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%s]\n",__FILE__,__FUNCTION__,__LINE__,text.c_str());
1127 
1128     if(program == NULL) {
1129     	throw megaglest_runtime_error("In [MainWindow::eventKeyDown] ERROR, program == NULL!");
1130     }
1131 
1132 	bool result = program->textInput(text);
1133 
1134 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] result = %d\n",__FILE__,__FUNCTION__,__LINE__,result);
1135 
1136 	return result;
1137 }
1138 
eventSdlKeyDown(SDL_KeyboardEvent key)1139 bool MainWindow::eventSdlKeyDown(SDL_KeyboardEvent key) {
1140 	if(program == NULL) {
1141 	    	throw megaglest_runtime_error("In [MainWindow::eventKeyDown] ERROR, program == NULL!");
1142 	}
1143 	return program->sdlKeyDown(key);
1144 }
1145 
eventKeyDown(SDL_KeyboardEvent key)1146 void MainWindow::eventKeyDown(SDL_KeyboardEvent key) {
1147 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,key.keysym.sym);
1148 
1149 	//printf("In mainwindow checking keypress for key [%d]\n",key.keysym.sym);
1150 
1151 	SDL_keysym keystate = key.keysym;
1152 
1153 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] key = [%c][%d]\n",__FILE__,__FUNCTION__,__LINE__,key,key);
1154 
1155     if(program == NULL) {
1156     	throw megaglest_runtime_error("In [MainWindow::eventKeyDown] ERROR, program == NULL!");
1157     }
1158 
1159     if(popupMenu.getVisible() == true && isKeyPressed(SDLK_ESCAPE,key) == true) {
1160     	this->popupMenu.setEnabled(false);
1161     	this->popupMenu.setVisible(false);
1162     	return;
1163     }
1164 
1165 	program->keyDown(key);
1166 
1167 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1168 
1169 	if(keystate.mod & (KMOD_LALT | KMOD_RALT)) {
1170 		//if(key == vkReturn) {
1171 		if(isKeyPressed(SDLK_RETURN,key) == true) {
1172 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] ALT-ENTER pressed\n",__FILE__,__FUNCTION__,__LINE__);
1173 
1174 			// This stupidity only required in win32.
1175 			// We reload the textures so that the canvas paints textures properly
1176 #ifdef WIN32
1177 			if(Window::getAllowAltEnterFullscreenToggle() == true) {
1178 				Renderer &renderer= Renderer::getInstance();
1179 				renderer.reinitAll();
1180 			}
1181 #endif
1182 
1183 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1184 		}
1185 	}
1186 
1187 	//printf("In mainwindow checking keypress for key [%d] mod [%d] modvalue: %d\n",key.keysym.sym,keystate.mod,(keystate.mod & (KMOD_LCTRL | KMOD_RCTRL)));
1188 
1189 	if(program != NULL && program->isInSpecialKeyCaptureEvent() == false) {
1190 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1191 
1192     	vector<int> modifiersToCheck;
1193 		modifiersToCheck.push_back(KMOD_LCTRL);
1194 		modifiersToCheck.push_back(KMOD_RCTRL);
1195 		modifiersToCheck.push_back(KMOD_LALT);
1196 		modifiersToCheck.push_back(KMOD_RALT);
1197 		modifiersToCheck.push_back(KMOD_LSHIFT);
1198 		modifiersToCheck.push_back(KMOD_RSHIFT);
1199 
1200 		Config &configKeys = Config::getInstance(std::pair<ConfigType,ConfigType>(cfgMainKeys,cfgUserKeys));
1201 		if(isKeyPressed(configKeys.getSDLKey("HotKeyShowDebug"),key) == true) {
1202 
1203 			Renderer &renderer= Renderer::getInstance();
1204 			if(keystate.mod & (KMOD_LALT | KMOD_RALT)) {
1205 				renderer.cycleShowDebugUILevel();
1206 				printf("**Cycled Debug UI level to: %d\n",renderer.getShowDebugUILevel());
1207 			}
1208 			else {
1209 				bool showDebugUI = renderer.getShowDebugUI();
1210 				renderer.setShowDebugUI(!showDebugUI);
1211 			}
1212 		}
1213 		else if((keystate.mod & (KMOD_LCTRL | KMOD_RCTRL)) &&
1214 				isKeyPressed(configKeys.getSDLKey("SwitchLanguage"),key) == true) {
1215 			if((keystate.mod & (KMOD_LSHIFT | KMOD_RSHIFT))) {
1216 			    this->triggerLanguageToggle = true;
1217 			    this->triggerLanguage = "";
1218 			}
1219 			else {
1220 				showLanguages();
1221 			}
1222 		}
1223 		else if(isKeyPressed(configKeys.getSDLKey("ReloadINI"),key,modifiersToCheck) == true) {
1224 			Config &config = Config::getInstance();
1225 			config.reload();
1226 		}
1227 		else if(isKeyPressed(configKeys.getSDLKey("Screenshot"),key,modifiersToCheck) == true) {
1228 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Screenshot key pressed\n");
1229 
1230 	        string userData = Config::getInstance().getString("UserData_Root","");
1231 	        if(userData != "") {
1232         		endPathWithSlash(userData);
1233 	        }
1234 
1235 			string path = userData + GameConstants::folder_path_screenshots;
1236 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Screenshot checking path [%s]\n",path.c_str());
1237 
1238 			if(isdir(path.c_str()) == false) {
1239 				createDirectoryPaths(path);
1240 			}
1241 
1242 			if(isdir(path.c_str()) == true) {
1243 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Screenshot path [%s]\n",path.c_str());
1244 
1245 				Config &config= Config::getInstance();
1246 				string fileFormat = config.getString("ScreenShotFileType","jpg");
1247 
1248 				unsigned int queueSize = Renderer::getInstance().getSaveScreenQueueSize();
1249 
1250 				for(int i=0; i < 5000; ++i) {
1251 					path = userData + GameConstants::folder_path_screenshots;
1252 					path += string("screen") + intToStr(i + queueSize) + string(".") + fileFormat;
1253 #ifdef WIN32
1254 					FILE *f= _wfopen(utf8_decode(path).c_str(), L"rb");
1255 #else
1256 					FILE *f= fopen(path.c_str(), "rb");
1257 #endif
1258 					if(f == NULL) {
1259 						Lang &lang= Lang::getInstance();
1260 						char szBuf[8096]="";
1261 						if(lang.getString("ScreenshotSavedTo").length() > 0 && lang.getString("ScreenshotSavedTo")[0] != '?') {
1262 							snprintf(szBuf,8096,lang.getString("ScreenshotSavedTo").c_str(),path.c_str());
1263 						}
1264 						else {
1265 							snprintf(szBuf,8096,"Screenshot will be saved to: %s",path.c_str());
1266 						}
1267 
1268 						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf);
1269 
1270 						bool showScreenshotSavedMsg = Config::getInstance().getBool("DisableScreenshotConsoleText","false");
1271 						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Screenshot console showScreenshotSavedMsg = %d\n",showScreenshotSavedMsg);
1272 
1273 						if(showScreenshotSavedMsg == false) {
1274 							if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Screenshot console [%s]\n",szBuf);
1275 							program->consoleAddLine(szBuf);
1276 						}
1277 
1278 						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Screenshot save to [%s]\n",path.c_str());
1279 						Renderer::getInstance().saveScreen(path);
1280 						break;
1281 					}
1282 					else {
1283 						if(SystemFlags::VERBOSE_MODE_ENABLED) printf("CANNOT save Screenshot [%s]\n",path.c_str());
1284 						fclose(f);
1285 					}
1286 				}
1287 			}
1288 		}
1289 	}
1290 
1291 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1292 }
1293 
eventKeyUp(SDL_KeyboardEvent key)1294 void MainWindow::eventKeyUp(SDL_KeyboardEvent key) {
1295 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,key);
1296     if(program == NULL) {
1297     	throw megaglest_runtime_error("In [MainWindow::eventKeyUp] ERROR, program == NULL!");
1298     }
1299 
1300 	program->keyUp(key);
1301 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,key);
1302 }
1303 
eventKeyPress(SDL_KeyboardEvent c)1304 void MainWindow::eventKeyPress(SDL_KeyboardEvent c) {
1305 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,c);
1306     if(program == NULL) {
1307     	throw megaglest_runtime_error("In [MainWindow::eventKeyPress] ERROR, program == NULL!");
1308     }
1309 
1310 	program->keyPress(c);
1311 
1312 	if(program != NULL && program->isInSpecialKeyCaptureEvent() == false) {
1313 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1314 
1315 		Config &configKeys = Config::getInstance(std::pair<ConfigType,ConfigType>(cfgMainKeys,cfgUserKeys));
1316 		if(isKeyPressed(configKeys.getSDLKey("HotKeyToggleOSMouseEnabled"),c) == true) {
1317 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
1318 
1319 			bool showCursorState = false;
1320 			int state = SDL_ShowCursor(SDL_QUERY);
1321 			if(state == SDL_DISABLE) {
1322 				showCursorState = true;
1323 			}
1324 
1325 			showCursor(showCursorState);
1326 			Renderer &renderer= Renderer::getInstance();
1327 			renderer.setNo2DMouseRendering(showCursorState);
1328 
1329 			Window::lastShowMouseState = SDL_ShowCursor(SDL_QUERY);
1330 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Window::lastShowMouseState = %d\n",__FILE__,__FUNCTION__,__LINE__,Window::lastShowMouseState);
1331 		}
1332 	}
1333 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,c);
1334 }
1335 
eventWindowEvent(SDL_WindowEvent event)1336 void MainWindow::eventWindowEvent(SDL_WindowEvent event) {
1337 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,event.event);
1338     if(program == NULL) {
1339     	throw megaglest_runtime_error("In [MainWindow::eventKeyPress] ERROR, program == NULL!");
1340     }
1341 
1342 //    if(program->getState() != NULL && dynamic_cast<Intro *>(program->getState()) != NULL) {
1343 //    	printf("In eventWindowEvent skip\n");
1344 //    	return;
1345 //    }
1346     //Renderer &renderer= Renderer::getInstance();
1347     switch(event.event) {
1348 		case SDL_WINDOWEVENT_ENTER:
1349 		{
1350 			//printf("In SDL_WINDOWEVENT_ENTER\n");
1351 //			bool showCursorState = Window::lastShowMouseState;
1352 //			showCursor(showCursorState);
1353 //			renderer.setNo2DMouseRendering(showCursorState);
1354 //
1355 //			Window::lastShowMouseState = SDL_ShowCursor(SDL_QUERY);
1356 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Window::lastShowMouseState = %d\n",__FILE__,__FUNCTION__,__LINE__,Window::lastShowMouseState);
1357 		}
1358 			break;
1359 		case SDL_WINDOWEVENT_LEAVE:
1360 		{
1361 			//printf("In SDL_WINDOWEVENT_LEAVE\n");
1362 //			bool showCursorState = false;
1363 //			int state = SDL_ShowCursor(SDL_QUERY);
1364 //			if(state == SDL_DISABLE) {
1365 //				showCursorState = true;
1366 //			}
1367 //			showCursor(showCursorState);
1368 //			renderer.setNo2DMouseRendering(showCursorState);
1369 //
1370 //			Window::lastShowMouseState = SDL_ShowCursor(SDL_QUERY);
1371 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Window::lastShowMouseState = %d\n",__FILE__,__FUNCTION__,__LINE__,Window::lastShowMouseState);
1372 		}
1373 			break;
1374 		case SDL_WINDOWEVENT_FOCUS_GAINED:
1375 		{
1376 			//printf("SDL_WINDOWEVENT_FOCUS_GAINED\n");
1377 //			bool showCursorState = Window::lastShowMouseState;
1378 //			showCursor(showCursorState);
1379 //			renderer.setNo2DMouseRendering(showCursorState);
1380 //
1381 //			Window::lastShowMouseState = SDL_ShowCursor(SDL_QUERY);
1382 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Window::lastShowMouseState = %d\n",__FILE__,__FUNCTION__,__LINE__,Window::lastShowMouseState);
1383 		}
1384 			break;
1385 		case SDL_WINDOWEVENT_FOCUS_LOST:
1386 		{
1387 			//printf("SDL_WINDOWEVENT_FOCUS_LOST\n");
1388 //			bool showCursorState = false;
1389 //			int state = SDL_ShowCursor(SDL_QUERY);
1390 //			if(state == SDL_DISABLE) {
1391 //				showCursorState = true;
1392 //			}
1393 //			showCursor(showCursorState);
1394 //			renderer.setNo2DMouseRendering(showCursorState);
1395 //
1396 //			Window::lastShowMouseState = SDL_ShowCursor(SDL_QUERY);
1397 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Window::lastShowMouseState = %d\n",__FILE__,__FUNCTION__,__LINE__,Window::lastShowMouseState);
1398 		}
1399 			break;
1400 
1401     }
1402 
1403     SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] [%d]\n",__FILE__,__FUNCTION__,__LINE__,event.event);
1404 }
1405 
eventActivate(bool active)1406 void MainWindow::eventActivate(bool active) {
1407 	if(!active){
1408 		//minimize();
1409 	}
1410 }
1411 
eventResize(SizeState sizeState)1412 void MainWindow::eventResize(SizeState sizeState) {
1413     if(program == NULL) {
1414     	throw megaglest_runtime_error("In [MainWindow::eventResize] ERROR, program == NULL!");
1415     }
1416 
1417 	program->resize(sizeState);
1418 }
1419 
eventClose()1420 void MainWindow::eventClose(){
1421 	delete program;
1422 	program= NULL;
1423 }
1424 
setProgram(Program * program)1425 void MainWindow::setProgram(Program *program) {
1426 	this->program= program;
1427 }
1428 
1429 // =====================================================
1430 // Main
1431 // =====================================================
1432 SystemFlags debugger;
1433 
print_SDL_version(const char * preamble,SDL_version * v)1434 void print_SDL_version(const char *preamble, SDL_version *v) {
1435 	printf("%s %u.%u.%u\n", preamble, v->major, v->minor, v->patch);
1436 }
1437 
setupGameItemPaths(int argc,char ** argv,Config * config)1438 int setupGameItemPaths(int argc, char** argv, Config *config) {
1439     // Setup path cache for files and folders used in the game
1440     std::map<string,string> &pathCache = CacheManager::getCachedItem< std::map<string,string> >(GameConstants::pathCacheLookupKey);
1441 
1442     Properties devProperties;
1443     string devPropertyFile = Properties::getApplicationPath() + "glest-dev.ini";
1444 	if(fileExists(devPropertyFile) == true) {
1445 		devProperties.load(devPropertyFile);
1446 
1447 		if(devProperties.hasString("ServerListPath") == true) {
1448 			string devItem = devProperties.getString("ServerListPath");
1449             if(devItem != "") {
1450             	endPathWithSlash(devItem);
1451             }
1452             if(config != NULL) {
1453             	config->setString("ServerListPath",devItem,true);
1454             }
1455 		}
1456 
1457 		if(devProperties.hasString("GlestKeysIniPath") == true) {
1458 			string devItem = devProperties.getString("GlestKeysIniPath");
1459             if(devItem != "") {
1460             	endPathWithSlash(devItem);
1461             }
1462             if(config != NULL) {
1463             	config->setString("GlestKeysIniPath",devItem,true);
1464             }
1465 		}
1466 	}
1467 
1468     //GAME_ARG_DATA_PATH
1469     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DATA_PATH]) == true) {
1470         int foundParamIndIndex = -1;
1471         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_DATA_PATH]) + string("="),&foundParamIndIndex);
1472         if(foundParamIndIndex < 0) {
1473             hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_DATA_PATH]),&foundParamIndIndex);
1474         }
1475         string customPath = argv[foundParamIndIndex];
1476         vector<string> paramPartTokens;
1477         Tokenize(customPath,paramPartTokens,"=");
1478         if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
1479             string customPathValue = paramPartTokens[1];
1480             Properties::applyTagsToValue(customPathValue);
1481             if(customPathValue != "") {
1482             	endPathWithSlash(customPathValue);
1483             }
1484             pathCache[GameConstants::path_data_CacheLookupKey] = customPathValue;
1485             Properties::setApplicationDataPath(pathCache[GameConstants::path_data_CacheLookupKey]);
1486 
1487             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using custom data path [%s]\n",customPathValue.c_str());
1488         }
1489         else {
1490 
1491             printf("\nInvalid path specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
1492             printParameterHelp(argv[0],false);
1493             return 1;
1494         }
1495     }
1496     else if(config != NULL) {
1497 
1498     	bool foundPath 			= false;
1499     	string customPathValue 	= "";
1500 
1501     	if(fileExists(devPropertyFile) == true && devProperties.hasString("DataPath") == true) {
1502     		foundPath 		= true;
1503     		customPathValue = devProperties.getString("DataPath","");
1504     	}
1505     	else if(config->getString("DataPath","") != "") {
1506     		foundPath 		= true;
1507     		customPathValue = config->getString("DataPath","");
1508     	}
1509 
1510     	if(foundPath == true) {
1511             pathCache[GameConstants::path_data_CacheLookupKey] = customPathValue;
1512 
1513             if(customPathValue != "") {
1514     			endPathWithSlash(customPathValue);
1515     		}
1516 
1517             Properties::setApplicationDataPath(pathCache[GameConstants::path_data_CacheLookupKey]);
1518 
1519             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using ini specified data path [%s]\n",config->getString("DataPath","").c_str());
1520     	}
1521     }
1522 
1523     //GAME_ARG_INI_PATH
1524     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_INI_PATH]) == true) {
1525         int foundParamIndIndex = -1;
1526         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_INI_PATH]) + string("="),&foundParamIndIndex);
1527         if(foundParamIndIndex < 0) {
1528             hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_INI_PATH]),&foundParamIndIndex);
1529         }
1530         string customPath = argv[foundParamIndIndex];
1531         vector<string> paramPartTokens;
1532         Tokenize(customPath,paramPartTokens,"=");
1533         if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
1534             string customPathValue = paramPartTokens[1];
1535             Properties::applyTagsToValue(customPathValue);
1536             pathCache[GameConstants::path_ini_CacheLookupKey]=customPathValue;
1537             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using custom ini path [%s]\n",customPathValue.c_str());
1538         }
1539         else {
1540 
1541             printf("\nInvalid path specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
1542             printParameterHelp(argv[0],false);
1543             return 1;
1544         }
1545     }
1546 
1547     //GAME_ARG_LOG_PATH
1548     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LOG_PATH]) == true) {
1549         int foundParamIndIndex = -1;
1550         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LOG_PATH]) + string("="),&foundParamIndIndex);
1551         if(foundParamIndIndex < 0) {
1552             hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LOG_PATH]),&foundParamIndIndex);
1553         }
1554         string customPath = argv[foundParamIndIndex];
1555         vector<string> paramPartTokens;
1556         Tokenize(customPath,paramPartTokens,"=");
1557         if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
1558             string customPathValue = paramPartTokens[1];
1559             Properties::applyTagsToValue(customPathValue);
1560             pathCache[GameConstants::path_logs_CacheLookupKey]=customPathValue;
1561             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using custom logs path [%s]\n",customPathValue.c_str());
1562         }
1563         else {
1564 
1565             printf("\nInvalid path specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
1566             printParameterHelp(argv[0],false);
1567             return 1;
1568         }
1569     }
1570     else if(config != NULL) {
1571 
1572     	bool foundPath 			= false;
1573     	string customPathValue 	= "";
1574 
1575     	if(fileExists(devPropertyFile) == true && devProperties.hasString("LogPath") == true) {
1576     		foundPath 		= true;
1577     		customPathValue = devProperties.getString("LogPath","");
1578     	}
1579     	else if(config->getString("LogPath","") != "") {
1580     		foundPath 		= true;
1581     		customPathValue = config->getString("LogPath","");
1582     	}
1583 
1584     	if(foundPath == true) {
1585             pathCache[GameConstants::path_logs_CacheLookupKey] = customPathValue;
1586             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using ini specified logs path [%s]\n",config->getString("LogPath","").c_str());
1587     	}
1588     }
1589 
1590     Text::DEFAULT_FONT_PATH = pathCache[GameConstants::path_data_CacheLookupKey];
1591     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_FONT_PATH]) == true) {
1592         int foundParamIndIndex = -1;
1593         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_FONT_PATH]) + string("="),&foundParamIndIndex);
1594         if(foundParamIndIndex < 0) {
1595             hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_FONT_PATH]),&foundParamIndIndex);
1596         }
1597         string customPath = argv[foundParamIndIndex];
1598         vector<string> paramPartTokens;
1599         Tokenize(customPath,paramPartTokens,"=");
1600         if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
1601             string customPathValue = paramPartTokens[1];
1602             Properties::applyTagsToValue(customPathValue);
1603 
1604             Text::DEFAULT_FONT_PATH_ABSOLUTE = customPathValue;
1605             if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using custom fonts path [%s]\n",customPathValue.c_str());
1606         }
1607         else {
1608 
1609             printf("\nInvalid path specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
1610             printParameterHelp(argv[0],false);
1611             return 1;
1612         }
1613     }
1614 
1615     return 0;
1616 }
1617 
setupLogging(Config & config,bool haveSpecialOutputCommandLineOption)1618 void setupLogging(Config &config, bool haveSpecialOutputCommandLineOption) {
1619 
1620     SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled      	= config.getBool("DebugMode","false");
1621     SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled     	= config.getBool("DebugNetwork","false");
1622     SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled 	= config.getBool("DebugPerformance","false");
1623     SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled  	= config.getBool("DebugWorldSynch","false");
1624     SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled  	= config.getBool("DebugUnitCommands","false");
1625     SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled  	= config.getBool("DebugPathFinder","false");
1626     SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled  			= config.getBool("DebugLUA","false");
1627     LuaScript::setDebugModeEnabled(SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled);
1628     SystemFlags::getSystemSettingType(SystemFlags::debugSound).enabled  		= config.getBool("DebugSound","false");
1629     SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled  		= config.getBool("DebugError","true");
1630 
1631     string userData = config.getString("UserData_Root","");
1632     if(userData != "") {
1633     	endPathWithSlash(userData);
1634     }
1635 
1636 #ifdef HAVE_GOOGLE_BREAKPAD
1637 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#1 In setting up errorHandlerPtr->set_dump_path [%p]...\n",errorHandlerPtr.get());
1638 	if(errorHandlerPtr.get() != NULL) {
1639 		string dumpFilePath;
1640 		if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1641 			dumpFilePath = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey);
1642 		}
1643 		else {
1644     		dumpFilePath = userData;
1645 		}
1646 
1647 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("#2 In setting up errorHandlerPtr->set_dump_path...\n");
1648 #if defined(WIN32)
1649 		wstring dumpfilepath = utf8_decode(dumpFilePath);
1650 		if(SystemFlags::VERBOSE_MODE_ENABLED) wprintf(L"Hooking up google_breakpad::ExceptionHandler to save dmp files to [%s]...\n",dumpfilepath.c_str());
1651 		errorHandlerPtr->set_dump_path(dumpfilepath);
1652 #else
1653 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Hooking up google_breakpad::ExceptionHandler to save dmp files to [%s]...\n",dumpFilePath.c_str());
1654 		//errorHandlerPtr->set_dump_path(dumpfilepath);
1655 		google_breakpad::MinidumpDescriptor descriptor(dumpFilePath);
1656 		errorHandlerPtr->set_minidump_descriptor(descriptor);
1657 #endif
1658 
1659 	}
1660 #endif
1661 
1662     string debugLogFile 			= config.getString("DebugLogFile","");
1663     if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1664         debugLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugLogFile;
1665     }
1666     else {
1667     	debugLogFile = userData + debugLogFile;
1668     }
1669 
1670     string debugWorldSynchLogFile 	= config.getString("DebugLogFileWorldSynch","");
1671     if(debugWorldSynchLogFile == "") {
1672         debugWorldSynchLogFile = debugLogFile;
1673     }
1674     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1675         debugWorldSynchLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugWorldSynchLogFile;
1676     }
1677     else {
1678     	debugWorldSynchLogFile = userData + debugWorldSynchLogFile;
1679     }
1680 
1681     string debugPerformanceLogFile = config.getString("DebugLogFilePerformance","");
1682     if(debugPerformanceLogFile == "") {
1683         debugPerformanceLogFile = debugLogFile;
1684     }
1685     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1686         debugPerformanceLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugPerformanceLogFile;
1687     }
1688     else {
1689     	debugPerformanceLogFile = userData + debugPerformanceLogFile;
1690     }
1691 
1692     string debugNetworkLogFile = config.getString("DebugLogFileNetwork","");
1693     if(debugNetworkLogFile == "") {
1694         debugNetworkLogFile = debugLogFile;
1695     }
1696     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1697         debugNetworkLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugNetworkLogFile;
1698     }
1699     else {
1700     	debugNetworkLogFile = userData + debugNetworkLogFile;
1701     }
1702 
1703     string debugUnitCommandsLogFile = config.getString("DebugLogFileUnitCommands","");
1704     if(debugUnitCommandsLogFile == "") {
1705         debugUnitCommandsLogFile = debugLogFile;
1706     }
1707     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1708         debugUnitCommandsLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugUnitCommandsLogFile;
1709     }
1710     else {
1711     	debugUnitCommandsLogFile = userData + debugUnitCommandsLogFile;
1712     }
1713 
1714     string debugPathFinderLogFile = config.getString("DebugLogFilePathFinder","");
1715     if(debugPathFinderLogFile == "") {
1716     	debugPathFinderLogFile = debugLogFile;
1717     }
1718     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1719     	debugPathFinderLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugPathFinderLogFile;
1720     }
1721     else {
1722     	debugPathFinderLogFile = userData + debugPathFinderLogFile;
1723     }
1724 
1725     string debugLUALogFile = config.getString("DebugLogFileLUA","");
1726     if(debugLUALogFile == "") {
1727         debugLUALogFile = debugLogFile;
1728     }
1729     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1730         debugLUALogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugLUALogFile;
1731     }
1732     else {
1733     	debugLUALogFile = userData + debugLUALogFile;
1734     }
1735 
1736     string debugSoundLogFile = config.getString("DebugLogFileSound","");
1737     if(debugSoundLogFile == "") {
1738         debugSoundLogFile = debugLogFile;
1739     }
1740     else if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
1741         debugSoundLogFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + debugSoundLogFile;
1742     }
1743     else {
1744     	debugSoundLogFile = userData + debugSoundLogFile;
1745     }
1746 
1747     string debugErrorLogFile = config.getString("DebugLogFileError","");
1748 
1749     SystemFlags::getSystemSettingType(SystemFlags::debugSystem).debugLogFileName      = debugLogFile;
1750     SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).debugLogFileName     = debugNetworkLogFile;
1751     SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).debugLogFileName = debugPerformanceLogFile;
1752     SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).debugLogFileName  = debugWorldSynchLogFile;
1753     SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).debugLogFileName = debugUnitCommandsLogFile;
1754     SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).debugLogFileName   = debugPathFinderLogFile;
1755     SystemFlags::getSystemSettingType(SystemFlags::debugLUA).debugLogFileName  		   = debugLUALogFile;
1756     SystemFlags::getSystemSettingType(SystemFlags::debugSound).debugLogFileName  	   = debugSoundLogFile;
1757     SystemFlags::getSystemSettingType(SystemFlags::debugError).debugLogFileName  	   = debugErrorLogFile;
1758 
1759     if(haveSpecialOutputCommandLineOption == false) {
1760         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("--- Startup log settings are ---\ndebugSystem [%d][%s]\ndebugNetwork [%d][%s]\ndebugPerformance [%d][%s]\ndebugWorldSynch [%d][%s]\ndebugUnitCommands[%d][%s]\ndebugPathFinder[%d][%s]\ndebugLUA [%d][%s]\ndebugSound [%d][%s]\ndebugError [%d][%s]\n",
1761                 SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled,
1762                 debugLogFile.c_str(),
1763                 SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled,
1764                 debugNetworkLogFile.c_str(),
1765                 SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled,
1766                 debugPerformanceLogFile.c_str(),
1767                 SystemFlags::getSystemSettingType(SystemFlags::debugWorldSynch).enabled,
1768                 debugWorldSynchLogFile.c_str(),
1769                 SystemFlags::getSystemSettingType(SystemFlags::debugUnitCommands).enabled,
1770                 debugUnitCommandsLogFile.c_str(),
1771                 SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled,
1772                 debugPathFinderLogFile.c_str(),
1773                 SystemFlags::getSystemSettingType(SystemFlags::debugLUA).enabled,
1774                 debugLUALogFile.c_str(),
1775                 SystemFlags::getSystemSettingType(SystemFlags::debugSound).enabled,
1776                 debugSoundLogFile.c_str(),
1777                 SystemFlags::getSystemSettingType(SystemFlags::debugError).enabled,
1778                 debugErrorLogFile.c_str());
1779     }
1780 }
1781 
runTilesetValidationForPath(string tilesetPath,string tilesetName,World & world,bool purgeUnusedFiles,bool purgeDuplicateFiles,bool showDuplicateFiles,bool gitPurgeFiles,double & purgedMegaBytes)1782 void runTilesetValidationForPath(string tilesetPath, string tilesetName,
1783 		World &world, bool purgeUnusedFiles,bool purgeDuplicateFiles,
1784 		bool showDuplicateFiles, bool gitPurgeFiles,double &purgedMegaBytes) {
1785 	Checksum checksum;
1786 
1787 	bool techtree_errors = false;
1788 
1789 	std::map<string,vector<pair<string, string> >  > loadedFileList;
1790 	vector<string> pathList;
1791 	pathList.push_back(tilesetPath);
1792 	world.loadTileset(pathList, tilesetName,&checksum, loadedFileList);
1793 
1794 	// Fixup paths with ..
1795 	{
1796 		std::map<string,vector<pair<string, string> > > newLoadedFileList;
1797 		for( std::map<string,vector<pair<string, string> > >::iterator iterMap = loadedFileList.begin();
1798 			iterMap != loadedFileList.end(); ++iterMap) {
1799 			string loadedFile = iterMap->first;
1800 
1801 			replaceAll(loadedFile,"//","/");
1802 			replaceAll(loadedFile,"\\\\","\\");
1803 			updatePathClimbingParts(loadedFile);
1804 
1805 			if(newLoadedFileList.find(loadedFile) != newLoadedFileList.end()) {
1806 				for(unsigned int xx1 = 0; xx1 < iterMap->second.size(); ++xx1) {
1807 					pair<string, string> &newVal = iterMap->second[xx1];
1808 					replaceAll(newVal.first,"//","/");
1809 					replaceAll(newVal.first,"\\\\","\\");
1810 					updatePathClimbingParts(newVal.first);
1811 					replaceAll(newVal.second,"//","/");
1812 					replaceAll(newVal.second,"\\\\","\\");
1813 					updatePathClimbingParts(newVal.second);
1814 
1815 					newLoadedFileList[loadedFile].push_back(newVal);
1816 				}
1817 			}
1818 			else {
1819 				for(unsigned int xx1 = 0; xx1 < iterMap->second.size(); ++xx1) {
1820 					pair<string, string> &newVal = iterMap->second[xx1];
1821 					replaceAll(newVal.first,"//","/");
1822 					replaceAll(newVal.first,"\\\\","\\");
1823 					updatePathClimbingParts(newVal.first);
1824 					replaceAll(newVal.second,"//","/");
1825 					replaceAll(newVal.second,"\\\\","\\");
1826 					updatePathClimbingParts(newVal.second);
1827 				}
1828 
1829 				newLoadedFileList[loadedFile] = iterMap->second;
1830 			}
1831 		}
1832 		loadedFileList = newLoadedFileList;
1833 	}
1834 
1835 	// Validate the faction setup to ensure we don't have any bad associations
1836 //			std::vector<std::string> resultErrors = world.validateFactionTypes();
1837 
1838 	// Now check for unused files in the techtree
1839 	std::map<string,vector<pair<string, string> > > foundFileList;
1840 	for(unsigned int i = 0; i < pathList.size(); ++i) {
1841 		string path = pathList[i];
1842 		endPathWithSlash(path);
1843 		path = path + tilesetName + "/";
1844 
1845 		replaceAll(path, "//", "/");
1846 		replaceAll(path, "\\\\", "\\");
1847 
1848 		vector<string> foundFiles = getFolderTreeContentsListRecursively(path + "*.", "");
1849 		for(unsigned int j = 0; j < foundFiles.size(); ++j) {
1850 			string file = foundFiles[j];
1851 			replaceAll(file, "//", "/");
1852 			replaceAll(file, "\\\\", "\\");
1853 
1854 			replaceAll(file,"//","/");
1855 			replaceAll(file,"\\\\","\\");
1856 
1857 			foundFileList[file].push_back(make_pair(path,path));
1858 		}
1859 	}
1860 
1861 	printf("Found tileset filecount = " MG_SIZE_T_SPECIFIER ", used = " MG_SIZE_T_SPECIFIER "\n",foundFileList.size(),loadedFileList.size());
1862 
1863 	int purgeCount = 0;
1864 	bool foundUnusedFile = false;
1865 	for( std::map<string,vector<pair<string, string> > >::iterator iterMap = foundFileList.begin();
1866 		iterMap != foundFileList.end(); ++iterMap) {
1867 		string foundFile = iterMap->first;
1868 		replaceAll(foundFile, "//", "/");
1869 		replaceAll(foundFile, "\\\\", "\\");
1870 
1871 		if(loadedFileList.find(foundFile) == loadedFileList.end() &&
1872 				foundFile.find("lang/") == foundFile.npos) {
1873 			if(foundUnusedFile == false) {
1874 				printf("\nLine ref: %d, Warning, unused files were detected - START:\n=====================\n",__LINE__);
1875 			}
1876 			foundUnusedFile = true;
1877 
1878 			printf("[%s]\n",foundFile.c_str());
1879 
1880 			string fileName = extractFileFromDirectoryPath(foundFile);
1881 			if(loadedFileList.find(fileName) != loadedFileList.end()) {
1882 				printf("possible match on [%s] ?\n",loadedFileList.find(fileName)->first.c_str());
1883 			}
1884 			else if(purgeUnusedFiles == true) {
1885 				off_t fileSize = getFileSize(foundFile);
1886 				// convert to MB
1887 				purgedMegaBytes += ((double)fileSize / 1048576.0);
1888 				purgeCount++;
1889 
1890 				if(gitPurgeFiles == true) {
1891 					char szBuf[8096]="";
1892 					snprintf(szBuf,8096,"git rm \"%s\"",foundFile.c_str());
1893 					bool gitOk = executeShellCommand(szBuf,0);
1894 					if(gitOk == false) {
1895 						throw megaglest_runtime_error("Call to command failed [" + string(szBuf) + "]");
1896 					}
1897 				}
1898 				else {
1899 					removeFile(foundFile);
1900 				}
1901 			}
1902 		}
1903 	}
1904 	if(foundUnusedFile == true) {
1905 		if(purgedMegaBytes > 0) {
1906 			printf("Purged %.2f MB (%d) in files\n",purgedMegaBytes,purgeCount);
1907 		}
1908 		printf("\nLine ref: %d, Warning, unused files were detected - END:\n",__LINE__);
1909 	}
1910 
1911 	if(showDuplicateFiles == true) {
1912 		std::map<uint32,vector<string> > mapDuplicateFiles;
1913 		// Now check for duplicate data content
1914 		for(std::map<string,vector<pair<string, string> > >::iterator iterMap = loadedFileList.begin();
1915 			iterMap != loadedFileList.end(); ++iterMap) {
1916 			string fileName = iterMap->first;
1917 			Checksum checksum;
1918 			checksum.addFile(fileName);
1919 			uint32 crcValue = checksum.getSum();
1920 			mapDuplicateFiles[crcValue].push_back(fileName);
1921 		}
1922 
1923 		double duplicateMegaBytesPurged=0;
1924 		int duplicateCountPurged=0;
1925 
1926 		double duplicateMegaBytes=0;
1927 		int duplicateCount=0;
1928 
1929 		bool foundDuplicates = false;
1930 		for(std::map<uint32,vector<string> >::iterator iterMap = mapDuplicateFiles.begin();
1931 			iterMap != mapDuplicateFiles.end(); ++iterMap) {
1932 			vector<string> &fileList = iterMap->second;
1933 			if(fileList.size() > 1) {
1934 				if(foundDuplicates == false) {
1935 					foundDuplicates = true;
1936 					printf("\nWarning, duplicate files were detected - START:\n=====================\n");
1937 				}
1938 
1939 				map<string,int> parentList;
1940 				for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
1941 					string duplicateFile = fileList[idx];
1942 					if(idx > 0) {
1943 						off_t fileSize = getFileSize(duplicateFile);
1944 						// convert to MB
1945 						duplicateMegaBytes += ((double)fileSize / 1048576.0);
1946 						duplicateCount++;
1947 					}
1948 					else {
1949 						printf("\n");
1950 					}
1951 
1952 					printf("[%s]\n",duplicateFile.c_str());
1953 					std::map<string,vector<pair<string, string> > >::iterator iterFind = loadedFileList.find(duplicateFile);
1954 					if(iterFind != loadedFileList.end()) {
1955 						for(unsigned int jdx = 0; jdx < iterFind->second.size(); jdx++) {
1956 							parentList[iterFind->second[jdx].first]++;
1957 						}
1958 					}
1959 				}
1960 
1961 				for(map<string,int>::iterator iterMap1 = parentList.begin();
1962 						iterMap1 != parentList.end(); ++iterMap1) {
1963 
1964 					if(iterMap1 == parentList.begin()) {
1965 						printf("\tParents:\n");
1966 					}
1967 					printf("\t[%s]\n",iterMap1->first.c_str());
1968 				}
1969 
1970 				if(purgeDuplicateFiles == true) {
1971 
1972 					string newCommonFileName = "";
1973 					for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
1974 						string duplicateFile = fileList[idx];
1975 						string fileExt = extractExtension(duplicateFile);
1976 						if(fileExt == "wav" || fileExt == "ogg") {
1977 							off_t fileSize = getFileSize(duplicateFile);
1978 							if(idx == 0) {
1979 								newCommonFileName = "$COMMONDATAPATH/sounds/" + extractFileFromDirectoryPath(duplicateFile);
1980 
1981 								string expandedNewCommonFileName = newCommonFileName;
1982 
1983 								std::map<string,string> mapExtraTagReplacementValues;
1984 
1985 								mapExtraTagReplacementValues = Properties::getTagReplacementValues(&mapExtraTagReplacementValues);
1986 								Properties::applyTagsToValue(expandedNewCommonFileName,&mapExtraTagReplacementValues);
1987 								replaceAll(expandedNewCommonFileName, "//", "/");
1988 								createDirectoryPaths(extractDirectoryPathFromFile(expandedNewCommonFileName));
1989 
1990 								if(gitPurgeFiles == true) {
1991 									copyFileTo(duplicateFile, expandedNewCommonFileName);
1992 
1993 									char szBuf[8096]="";
1994 									snprintf(szBuf,8096,"git rm \"%s\"",duplicateFile.c_str());
1995 									bool gitOk = executeShellCommand(szBuf,0);
1996 									if(gitOk == false) {
1997 										throw megaglest_runtime_error("Call to command failed [" + string(szBuf) + "]");
1998 									}
1999 									printf("*** Duplicate file:\n[%s]\nwas git rm and copied to:\n[%s]\n",duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2000 								}
2001 								else {
2002 									//int result = 0;
2003 									int result = rename(duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2004 									if(result != 0) {
2005 										char szBuf[8096]="";
2006 										char *errmsg = strerror(errno);
2007 										snprintf(szBuf,8096,"!!! Error [%s] Could not rename [%s] to [%s]!",errmsg,duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2008 										throw megaglest_runtime_error(szBuf);
2009 									}
2010 									else {
2011 										printf("*** Duplicate file:\n[%s]\nwas renamed to:\n[%s]\n",duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2012 									}
2013 								}
2014 							}
2015 							else {
2016 								if(gitPurgeFiles == true) {
2017 									char szBuf[8096]="";
2018 									snprintf(szBuf,8096,"git rm \"%s\"",duplicateFile.c_str());
2019 									bool gitOk = executeShellCommand(szBuf,0);
2020 									if(gitOk == false) {
2021 										throw megaglest_runtime_error("Call to command failed [" + string(szBuf) + "]");
2022 									}
2023 									printf("*** Duplicate file:\n[%s]\nwas git rm\n",duplicateFile.c_str());
2024 								}
2025 								else {
2026 									removeFile(duplicateFile);
2027 								}
2028 								printf("*** Duplicate file:\n[%s]\nwas removed\n",duplicateFile.c_str());
2029 
2030 								// convert to MB
2031 								duplicateMegaBytesPurged += ((double)fileSize / 1048576.0);
2032 								duplicateCountPurged++;
2033 							}
2034 						}
2035 					}
2036 
2037 					std::map<string,int> mapUniqueParentList;
2038 
2039 					for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2040 						string duplicateFile = fileList[idx];
2041 						string fileExt = extractExtension(duplicateFile);
2042 						if(fileExt == "wav" || fileExt == "ogg") {
2043 							std::map<string,vector<pair<string, string> > >::iterator iterFind2 = loadedFileList.find(duplicateFile);
2044 							if(iterFind2 != loadedFileList.end()) {
2045 								for(unsigned int jdx1 = 0; jdx1 < iterFind2->second.size(); jdx1++) {
2046 									string parentFile = iterFind2->second[jdx1].first;
2047 									string searchText = iterFind2->second[jdx1].second;
2048 
2049 									if(mapUniqueParentList.find(parentFile) == mapUniqueParentList.end()) {
2050 										printf("*** Searching parent file:\n[%s]\nfor duplicate file reference:\n[%s]\nto replace with newname:\n[%s]\n",parentFile.c_str(),searchText.c_str(),newCommonFileName.c_str());
2051 										bool foundText = searchAndReplaceTextInFile(parentFile, searchText, newCommonFileName, false);
2052 										printf("foundText = %d\n",foundText);
2053 										if(foundText == false) {
2054 											char szBuf[8096]="";
2055 											snprintf(szBuf,8096,"Line ref = %d, Error finding text [%s] in file [%s]",__LINE__,searchText.c_str(),parentFile.c_str());
2056 											throw megaglest_runtime_error(szBuf);
2057 										}
2058 										mapUniqueParentList[parentFile]++;
2059 									}
2060 								}
2061 							}
2062 						}
2063 					}
2064 				}
2065 				else {
2066 					string newCommonFileName = "";
2067 					for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2068 						string duplicateFile = fileList[idx];
2069 						string fileExt = extractExtension(duplicateFile);
2070 						if(fileExt == "wav" || fileExt == "ogg") {
2071 							//off_t fileSize = getFileSize(duplicateFile);
2072 							if(idx == 0) {
2073 								newCommonFileName = "$COMMONDATAPATH/sounds/" + extractFileFromDirectoryPath(duplicateFile);
2074 								break;
2075 							}
2076 						}
2077 					}
2078 
2079 					for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2080 						string duplicateFile = fileList[idx];
2081 						string fileExt = extractExtension(duplicateFile);
2082 						if(fileExt == "wav" || fileExt == "ogg") {
2083 							std::map<string,vector<pair<string, string> > >::iterator iterFind4 = loadedFileList.find(duplicateFile);
2084 							if(iterFind4 != loadedFileList.end()) {
2085 								for(unsigned int jdx = 0; jdx < iterFind4->second.size(); jdx++) {
2086 									string parentFile = iterFind4->second[jdx].first;
2087 									string searchText = iterFind4->second[jdx].second;
2088 
2089 									bool foundText = searchAndReplaceTextInFile(parentFile, searchText, newCommonFileName, true);
2090 									if(foundText == false) {
2091 
2092 										char szBuf[8096]="";
2093 										snprintf(szBuf,8096,"Line ref = %d, Error finding text\n[%s]\nin file\n[%s]\nnew Common File [%s]\n",__LINE__,searchText.c_str(),parentFile.c_str(),newCommonFileName.c_str());
2094 										printf("\n\n=================================================\n%s",szBuf);
2095 
2096 										throw megaglest_runtime_error(szBuf);
2097 									}
2098 								}
2099 							}
2100 						}
2101 					}
2102 				}
2103 			}
2104 		}
2105 		if(foundDuplicates == true) {
2106 			printf("Duplicates %.2f MB (%d) in files\n",duplicateMegaBytes,duplicateCount);
2107 			printf("Duplicates purged %.2f MB (%d) in files\n",duplicateMegaBytesPurged,duplicateCountPurged);
2108 
2109 			printf("\nWarning, duplicate files were detected - END:\n");
2110 		}
2111 	}
2112 
2113 	if(techtree_errors == false) {
2114 		printf("\nValidation found NO ERRORS for tilesetPath [%s] tilesetName [%s]:\n",tilesetPath.c_str(), tilesetName.c_str());
2115 	}
2116 
2117 	printf("----------------------------------------------------------------");
2118 }
2119 
runTechValidationForPath(string techPath,string techName,const std::vector<string> & filteredFactionList,World & world,bool purgeUnusedFiles,bool purgeDuplicateFiles,bool showDuplicateFiles,bool gitPurgeFiles,double & purgedMegaBytes)2120 void runTechValidationForPath(string techPath, string techName,
2121 		const std::vector<string> &filteredFactionList, World &world,
2122 		bool purgeUnusedFiles,bool purgeDuplicateFiles, bool showDuplicateFiles,
2123 		bool gitPurgeFiles,double &purgedMegaBytes) {
2124 
2125 	string techTreeFolder = techPath + techName;
2126 	string techTreeFactionFolder = techTreeFolder + "/factions/";
2127 	vector<string> factionsList;
2128 	findDirs(techTreeFactionFolder, factionsList, false, false);
2129 
2130 	if(factionsList.empty() == false) {
2131 		Checksum checksum;
2132 		set<string> factions;
2133 		for(int j = 0; j < (int)factionsList.size(); ++j) {
2134 			if(	filteredFactionList.empty() == true ||
2135 				std::find(filteredFactionList.begin(),filteredFactionList.end(),factionsList[j]) != filteredFactionList.end()) {
2136 				factions.insert(factionsList[j]);
2137 			}
2138 		}
2139 
2140 		printf("\n----------------------------------------------------------------");
2141 		printf("\nChecking techPath [%s] techName [%s] total faction count = %d\n",techPath.c_str(), techName.c_str(),(int)factionsList.size());
2142 		for(int j = 0; j < (int)factionsList.size(); ++j) {
2143 			if(	filteredFactionList.empty() == true ||
2144 				std::find(filteredFactionList.begin(),filteredFactionList.end(),factionsList[j]) != filteredFactionList.end()) {
2145 				printf("Using faction [%s]\n",factionsList[j].c_str());
2146 			}
2147 		}
2148 
2149 		if(factions.empty() == false) {
2150 			bool techtree_errors = false;
2151 
2152 			std::map<string,vector<pair<string, string> >  > loadedFileList;
2153 			vector<string> pathList;
2154 			pathList.push_back(techPath);
2155 			Config &config = Config::getInstance();
2156 			vector<string> otherTechPaths = config.getPathListForType(ptTechs,"");
2157 			pathList.insert(pathList.end(), otherTechPaths.begin(), otherTechPaths.end());
2158 
2159 			try {
2160 				world.loadTech(pathList, techName, factions, &checksum, loadedFileList, true);
2161 
2162 				// Fixup paths with ..
2163 				{
2164 					std::map<string,vector<pair<string, string> > > newLoadedFileList;
2165 					for( std::map<string,vector<pair<string, string> > >::iterator iterMap = loadedFileList.begin();
2166 						iterMap != loadedFileList.end(); ++iterMap) {
2167 						string loadedFile = iterMap->first;
2168 
2169 						replaceAll(loadedFile,"//","/");
2170 						replaceAll(loadedFile,"\\\\","\\");
2171 						updatePathClimbingParts(loadedFile);
2172 
2173 						if(newLoadedFileList.find(loadedFile) != newLoadedFileList.end()) {
2174 							for(unsigned int xx1 = 0; xx1 < iterMap->second.size(); ++xx1) {
2175 								pair<string, string> &newVal = iterMap->second[xx1];
2176 								replaceAll(newVal.first,"//","/");
2177 								replaceAll(newVal.first,"\\\\","\\");
2178 								updatePathClimbingParts(newVal.first);
2179 								replaceAll(newVal.second,"//","/");
2180 								replaceAll(newVal.second,"\\\\","\\");
2181 								updatePathClimbingParts(newVal.second);
2182 
2183 								newLoadedFileList[loadedFile].push_back(newVal);
2184 							}
2185 						}
2186 						else {
2187 							for(unsigned int xx1 = 0; xx1 < iterMap->second.size(); ++xx1) {
2188 								pair<string, string> &newVal = iterMap->second[xx1];
2189 								replaceAll(newVal.first,"//","/");
2190 								replaceAll(newVal.first,"\\\\","\\");
2191 								updatePathClimbingParts(newVal.first);
2192 								replaceAll(newVal.second,"//","/");
2193 								replaceAll(newVal.second,"\\\\","\\");
2194 								updatePathClimbingParts(newVal.second);
2195 							}
2196 
2197 							newLoadedFileList[loadedFile] = iterMap->second;
2198 						}
2199 					}
2200 					loadedFileList = newLoadedFileList;
2201 				}
2202 
2203 				// Validate the faction setup to ensure we don't have any bad associations
2204 				std::vector<std::string> resultErrors = world.validateFactionTypes();
2205 				if(resultErrors.empty() == false) {
2206 					techtree_errors = true;
2207 					// Display the validation errors
2208 					string errorText = "\nErrors were detected:\n=====================\n";
2209 					for(int i = 0; i < (int)resultErrors.size(); ++i) {
2210 						if(i > 0) {
2211 							errorText += "\n";
2212 						}
2213 						errorText = errorText + resultErrors[i];
2214 					}
2215 					errorText += "\n=====================\n";
2216 					printf("%s",errorText.c_str());
2217 				}
2218 
2219 				// Validate the faction resource setup to ensure we don't have any bad associations
2220 				printf("\nChecking resources, count = %d\n",world.getTechTree()->getResourceTypeCount());
2221 
2222 				for(int i = 0; i < world.getTechTree()->getResourceTypeCount(); ++i) {
2223 					printf("Found techtree resource [%s]\n",world.getTechTree()->getResourceType(i)->getName().c_str());
2224 				}
2225 
2226 				resultErrors = world.validateResourceTypes();
2227 				if(resultErrors.empty() == false) {
2228 					techtree_errors = true;
2229 					// Display the validation errors
2230 					string errorText = "\nErrors were detected:\n=====================\n";
2231 					for(int i = 0; i < (int)resultErrors.size(); ++i) {
2232 						if(i > 0) {
2233 							errorText += "\n";
2234 						}
2235 						errorText = errorText + resultErrors[i];
2236 					}
2237 					errorText += "\n=====================\n";
2238 					printf("%s",errorText.c_str());
2239 				}
2240 
2241 				// Now check for unused files in the techtree
2242 				std::map<string,vector<pair<string, string> > > foundFileList;
2243 				for(unsigned int i = 0; i < pathList.size(); ++i) {
2244 					string path = pathList[i];
2245 					endPathWithSlash(path);
2246 					path = path + techName + "/";
2247 
2248 					replaceAll(path, "//", "/");
2249 					replaceAll(path, "\\\\", "\\");
2250 
2251 					vector<string> foundFiles = getFolderTreeContentsListRecursively(path + "*.", "");
2252 					for(unsigned int j = 0; j < foundFiles.size(); ++j) {
2253 						string file = foundFiles[j];
2254 						replaceAll(file, "//", "/");
2255 						replaceAll(file, "\\\\", "\\");
2256 
2257 						// ignore loading screen, preview screen and hud
2258 						if(	file.find(GameConstants::LOADING_SCREEN_FILE) != string::npos ||
2259 								file.find(GameConstants::PREVIEW_SCREEN_FILE) != string::npos ||
2260 								file.find(GameConstants::HUD_SCREEN_FILE) != string::npos) {
2261 							continue;
2262 						}
2263 
2264 						// ignore commondata since we are not loading all factions
2265 						if(filteredFactionList.size() > 0) {
2266 							if(	file.find("/commondata/") != string::npos) {
2267 								continue;
2268 							}
2269 						}
2270 
2271 						if(file.find("/factions/") != string::npos) {
2272 							bool includeFaction = false;
2273 							for ( set<string>::iterator it = factions.begin(); it != factions.end(); ++it ) {
2274 								string currentFaction = *it;
2275 								if(file.find("/factions/" + currentFaction) != string::npos) {
2276 									includeFaction = true;
2277 									break;
2278 								}
2279 							}
2280 							if(includeFaction == false) {
2281 								continue;
2282 							}
2283 						}
2284 
2285 						replaceAll(file,"//","/");
2286 						replaceAll(file,"\\\\","\\");
2287 
2288 						foundFileList[file].push_back(make_pair(path,path));
2289 					}
2290 				}
2291 
2292 				printf("Found techtree filecount = " MG_SIZE_T_SPECIFIER ", used = " MG_SIZE_T_SPECIFIER "\n",foundFileList.size(),loadedFileList.size());
2293 
2294 				int purgeCount = 0;
2295 				bool foundUnusedFile = false;
2296 				for( std::map<string,vector<pair<string, string> > >::iterator iterMap = foundFileList.begin();
2297 					iterMap != foundFileList.end(); ++iterMap) {
2298 					string foundFile = iterMap->first;
2299 					replaceAll(foundFile, "//", "/");
2300 					replaceAll(foundFile, "\\\\", "\\");
2301 
2302 					if(loadedFileList.find(foundFile) == loadedFileList.end() &&
2303 							foundFile.find("lang/") == foundFile.npos) {
2304 						if(foundUnusedFile == false) {
2305 							printf("\nLine ref: %d, Warning, unused files were detected - START:\n=====================\n",__LINE__);
2306 						}
2307 						foundUnusedFile = true;
2308 
2309 						printf("[%s]\n",foundFile.c_str());
2310 
2311 						string fileName = extractFileFromDirectoryPath(foundFile);
2312 						if(loadedFileList.find(fileName) != loadedFileList.end()) {
2313 							printf("possible match on [%s] ?\n",loadedFileList.find(fileName)->first.c_str());
2314 						}
2315 						else if(purgeUnusedFiles == true) {
2316 							off_t fileSize = getFileSize(foundFile);
2317 							// convert to MB
2318 							purgedMegaBytes += ((double)fileSize / 1048576.0);
2319 							purgeCount++;
2320 
2321 							if(gitPurgeFiles == true) {
2322 								char szBuf[8096]="";
2323 								snprintf(szBuf,8096,"git rm \"%s\"",foundFile.c_str());
2324 								bool gitOk = executeShellCommand(szBuf,0);
2325 								if(gitOk == false) {
2326 									throw megaglest_runtime_error("Call to command failed [" + string(szBuf) + "]");
2327 								}
2328 							}
2329 							else {
2330 								removeFile(foundFile);
2331 							}
2332 						}
2333 					}
2334 				}
2335 				if(foundUnusedFile == true) {
2336 					if(purgedMegaBytes > 0) {
2337 						printf("Purged %.2f MB (%d) in files\n",purgedMegaBytes,purgeCount);
2338 					}
2339 					printf("\nLine ref: %d, Warning, unused files were detected - END:\n",__LINE__);
2340 				}
2341 
2342 				if(showDuplicateFiles == true) {
2343 					std::map<uint32,vector<string> > mapDuplicateFiles;
2344 					// Now check for duplicate data content
2345 					for(std::map<string,vector<pair<string, string> > >::iterator iterMap = loadedFileList.begin();
2346 						iterMap != loadedFileList.end(); ++iterMap) {
2347 						string fileName = iterMap->first;
2348 						Checksum checksum;
2349 						checksum.addFile(fileName);
2350 						uint32 crcValue = checksum.getSum();
2351 						if(crcValue == 0) {
2352 							char szBuf[8096]="";
2353 							snprintf(szBuf,8096,"Error calculating CRC for file [%s]",fileName.c_str());
2354 							throw megaglest_runtime_error(szBuf);
2355 						}
2356 						mapDuplicateFiles[crcValue].push_back(fileName);
2357 					}
2358 
2359 					double duplicateMegaBytesPurged=0;
2360 					int duplicateCountPurged=0;
2361 
2362 					double duplicateMegaBytes=0;
2363 					int duplicateCount=0;
2364 
2365 					bool foundDuplicates = false;
2366 					for(std::map<uint32,vector<string> >::iterator iterMap = mapDuplicateFiles.begin();
2367 						iterMap != mapDuplicateFiles.end(); ++iterMap) {
2368 						vector<string> &fileList = iterMap->second;
2369 						if(fileList.size() > 1) {
2370 							if(foundDuplicates == false) {
2371 								foundDuplicates = true;
2372 								printf("\nWarning, duplicate files were detected - START:\n=====================\n");
2373 							}
2374 
2375 							printf("----- START duplicate files for CRC [%u] count [" MG_SIZE_T_SPECIFIER "] first file is [%s]\n",iterMap->first,fileList.size(),fileList[0].c_str());
2376 
2377 							map<string,int> parentList;
2378 							for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2379 								string duplicateFile = fileList[idx];
2380 								if(idx > 0) {
2381 									off_t fileSize = getFileSize(duplicateFile);
2382 									// convert to MB
2383 									duplicateMegaBytes += ((double)fileSize / 1048576.0);
2384 									duplicateCount++;
2385 								}
2386 								else {
2387 									printf("\n");
2388 								}
2389 
2390 								printf("[%s]\n",duplicateFile.c_str());
2391 								std::map<string,vector<pair<string, string> > >::iterator iterFind = loadedFileList.find(duplicateFile);
2392 								if(iterFind != loadedFileList.end()) {
2393 									for(unsigned int jdx = 0; jdx < iterFind->second.size(); jdx++) {
2394 										parentList[iterFind->second[jdx].first]++;
2395 									}
2396 								}
2397 
2398 								string newCommonFileName = "$COMMONDATAPATH/sounds/" + extractFileFromDirectoryPath(duplicateFile);
2399 								string expandedNewCommonFileName = newCommonFileName;
2400 								std::map<string,string> mapExtraTagReplacementValues;
2401 								string techCommonData = techPath + techName + "/commondata/";
2402 								replaceAll(techCommonData, "//", "/");
2403 								mapExtraTagReplacementValues["$COMMONDATAPATH"] = techCommonData;
2404 								mapExtraTagReplacementValues = Properties::getTagReplacementValues(&mapExtraTagReplacementValues);
2405 								Properties::applyTagsToValue(expandedNewCommonFileName,&mapExtraTagReplacementValues);
2406 								replaceAll(expandedNewCommonFileName, "//", "/");
2407 							}
2408 
2409 							printf("----- Finding parents for duplicate files [" MG_SIZE_T_SPECIFIER "] first file is [%s]\n",fileList.size(),fileList[0].c_str());
2410 
2411 							for(map<string,int>::iterator iterMap1 = parentList.begin();
2412 									iterMap1 != parentList.end(); ++iterMap1) {
2413 
2414 								if(iterMap1 == parentList.begin()) {
2415 									printf("\tParents:\n");
2416 								}
2417 								printf("\t[%s]\n",iterMap1->first.c_str());
2418 							}
2419 
2420 							if(purgeDuplicateFiles == true) {
2421 
2422 								printf("----- move / remove duplicate files [" MG_SIZE_T_SPECIFIER "] first file is [%s]\n",fileList.size(),fileList[0].c_str());
2423 								// First move first duplicate to commondata and delete all other copies
2424 								string newCommonFileName = "";
2425 								for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2426 									string duplicateFile = fileList[idx];
2427 									string fileExt = extractExtension(duplicateFile);
2428 									if(fileExt == "wav" || fileExt == "ogg") {
2429 										off_t fileSize = getFileSize(duplicateFile);
2430 
2431 										printf("#1 [%u / " MG_SIZE_T_SPECIFIER "] removing duplicate [%s]\n",idx,fileList.size(),duplicateFile.c_str());
2432 
2433 										if(idx == 0) {
2434 											newCommonFileName = "$COMMONDATAPATH/sounds/" + extractFileFromDirectoryPath(duplicateFile);
2435 
2436 											string expandedNewCommonFileName = newCommonFileName;
2437 
2438 											std::map<string,string> mapExtraTagReplacementValues;
2439 
2440 											string techCommonData = techPath + techName + "/commondata/";
2441 											replaceAll(techCommonData, "//", "/");
2442 
2443 											mapExtraTagReplacementValues["$COMMONDATAPATH"] = techCommonData;
2444 											mapExtraTagReplacementValues = Properties::getTagReplacementValues(&mapExtraTagReplacementValues);
2445 											Properties::applyTagsToValue(expandedNewCommonFileName,&mapExtraTagReplacementValues);
2446 											replaceAll(expandedNewCommonFileName, "//", "/");
2447 											createDirectoryPaths(extractDirectoryPathFromFile(expandedNewCommonFileName));
2448 
2449 											if(gitPurgeFiles == true) {
2450 												copyFileTo(duplicateFile, expandedNewCommonFileName);
2451 
2452 												char szBuf[8096]="";
2453 												snprintf(szBuf,8096,"git rm \"%s\"",duplicateFile.c_str());
2454 												bool gitOk = executeShellCommand(szBuf,0);
2455 												if(gitOk == false) {
2456 													throw megaglest_runtime_error("Call to command failed [" + string(szBuf) + "]");
2457 												}
2458 												printf("*** Duplicate file:\n[%s]\nwas git rm and copied to:\n[%s]\n",duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2459 											}
2460 											else {
2461 												printf("moving duplicate [%s] to common data [%s] expanded to [%s]\n",duplicateFile.c_str(),newCommonFileName.c_str(),expandedNewCommonFileName.c_str());
2462 
2463 												int result = rename(duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2464 												if(result != 0) {
2465 													char szBuf[8096]="";
2466 													char *errmsg = strerror(errno);
2467 													snprintf(szBuf,8096,"!!! Error [%s] Could not rename [%s] to [%s]!",errmsg,duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2468 													throw megaglest_runtime_error(szBuf);
2469 												}
2470 												else {
2471 													printf("*** Duplicate file:\n[%s]\nwas renamed to:\n[%s]\n",duplicateFile.c_str(),expandedNewCommonFileName.c_str());
2472 												}
2473 											}
2474 										}
2475 										else {
2476 											if(gitPurgeFiles == true) {
2477 												char szBuf[8096]="";
2478 												snprintf(szBuf,8096,"git rm \"%s\"",duplicateFile.c_str());
2479 												bool gitOk = executeShellCommand(szBuf,0);
2480 												if(gitOk == false) {
2481 													throw megaglest_runtime_error("Call to command failed [" + string(szBuf) + "]");
2482 												}
2483 												printf("*** Duplicate file:\n[%s]\nwas git rm\n",duplicateFile.c_str());
2484 											}
2485 											else {
2486 												printf("removing duplicate [%s]\n",duplicateFile.c_str());
2487 												removeFile(duplicateFile);
2488 											}
2489 											printf("*** Duplicate file:\n[%s]\nwas removed\n",duplicateFile.c_str());
2490 
2491 											// convert to MB
2492 											duplicateMegaBytesPurged += ((double)fileSize / 1048576.0);
2493 											duplicateCountPurged++;
2494 										}
2495 									}
2496 								}
2497 
2498 								printf("----- update XML files for duplicate files [" MG_SIZE_T_SPECIFIER "] first file is [%s]\n",fileList.size(),fileList[0].c_str());
2499 								std::map<string,int> mapUniqueParentList;
2500 
2501 								// Update the XML files to point to the new single copy in commondata
2502 								for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2503 									string duplicateFile = fileList[idx];
2504 									string fileExt = extractExtension(duplicateFile);
2505 									if(fileExt == "wav" || fileExt == "ogg") {
2506 										std::map<string,vector<pair<string, string> > >::iterator iterFind2 = loadedFileList.find(duplicateFile);
2507 										if(iterFind2 != loadedFileList.end()) {
2508 											for(unsigned int jdx1 = 0; jdx1 < iterFind2->second.size(); jdx1++) {
2509 												string parentFile = iterFind2->second[jdx1].first;
2510 												string searchText = iterFind2->second[jdx1].second;
2511 
2512 												if(mapUniqueParentList.find(parentFile) == mapUniqueParentList.end()) {
2513 													printf("*** Searching parent file:\n[%s]\nfor duplicate file reference:\n[%s]\nto replace with newname:\n[%s]\n",parentFile.c_str(),searchText.c_str(),newCommonFileName.c_str());
2514 													bool foundText = searchAndReplaceTextInFile(parentFile, searchText, newCommonFileName, false);
2515 													printf("foundText = %d\n",foundText);
2516 													if(foundText == false) {
2517 
2518 														string techCommonData = techPath + techName + "/commondata/";
2519 														replaceAll(techCommonData, "//", "/");
2520 
2521 														if(StartsWith(searchText, techCommonData) == true) {
2522 															printf("WARNING #1 [%d] techCommonData check\n[%s]\n[%s]\n[%s]\n[%s]\n",
2523 																	foundText,parentFile.c_str(),techCommonData.c_str(),searchText.c_str(),newCommonFileName.c_str());
2524 
2525 															replaceAll(searchText, techCommonData, "$COMMONDATAPATH/");
2526 															foundText = searchAndReplaceTextInFile(parentFile, searchText, newCommonFileName, false);
2527 
2528 															printf("WARNING #2 [%d] techCommonData check\n[%s]\n[%s]\n[%s]\n[%s]\n",
2529 																	foundText,parentFile.c_str(),techCommonData.c_str(),searchText.c_str(),newCommonFileName.c_str());
2530 														}
2531 														if(foundText == false) {
2532 															char szBuf[8096]="";
2533 															snprintf(szBuf,8096,"Line ref = %d, Error finding text\n[%s]\nin file\n[%s]\nnew Common File [%s]\n",__LINE__,searchText.c_str(),parentFile.c_str(),newCommonFileName.c_str());
2534 															printf("\n\n=================================================\n%s",szBuf);
2535 
2536 															throw megaglest_runtime_error(szBuf);
2537 														}
2538 													}
2539 													mapUniqueParentList[parentFile]++;
2540 												}
2541 											}
2542 										}
2543 									}
2544 								}
2545 							}
2546 							else {
2547 
2548 								string newCommonFileName = "";
2549 								for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2550 									string duplicateFile = fileList[idx];
2551 									string fileExt = extractExtension(duplicateFile);
2552 									if(fileExt == "wav" || fileExt == "ogg") {
2553 										//off_t fileSize = getFileSize(duplicateFile);
2554 										if(idx == 0) {
2555 											newCommonFileName = "$COMMONDATAPATH/sounds/" + extractFileFromDirectoryPath(duplicateFile);
2556 											break;
2557 										}
2558 									}
2559 								}
2560 
2561 								for(unsigned int idx = 0; idx < fileList.size(); ++idx) {
2562 									string duplicateFile = fileList[idx];
2563 									string fileExt = extractExtension(duplicateFile);
2564 									if(fileExt == "wav" || fileExt == "ogg") {
2565 										std::map<string,vector<pair<string, string> > >::iterator iterFind4 = loadedFileList.find(duplicateFile);
2566 										if(iterFind4 != loadedFileList.end()) {
2567 											for(unsigned int jdx = 0; jdx < iterFind4->second.size(); jdx++) {
2568 												string parentFile = iterFind4->second[jdx].first;
2569 												string searchText = iterFind4->second[jdx].second;
2570 
2571 												bool foundText = searchAndReplaceTextInFile(parentFile, searchText, newCommonFileName, true);
2572 
2573 												if(foundText == false) {
2574 													string techCommonData = techPath + techName + "/commondata/";
2575 													replaceAll(techCommonData, "//", "/");
2576 
2577 													if(StartsWith(searchText, techCommonData) == true) {
2578 														replaceAll(searchText, techCommonData, "$COMMONDATAPATH/");
2579 														foundText = searchAndReplaceTextInFile(parentFile, searchText, newCommonFileName, true);
2580 
2581 													}
2582 													if(foundText == false) {
2583 
2584 														// Check if the sound file already references commandata
2585 														foundText = searchAndReplaceTextInFile(parentFile, newCommonFileName, newCommonFileName, true);
2586 														if(foundText == false) {
2587 															char szBuf[8096]="";
2588 															snprintf(szBuf,8096,"Line ref = %d, Error finding text\n[%s]\nin file\n[%s]\nnew Common File [%s]\n",__LINE__,searchText.c_str(),parentFile.c_str(),newCommonFileName.c_str());
2589 															printf("\n\n=================================================\n%s",szBuf);
2590 
2591 															throw megaglest_runtime_error(szBuf);
2592 														}
2593 													}
2594 												}
2595 											}
2596 										}
2597 									}
2598 								}
2599 							}
2600 
2601 
2602 							printf("----- END duplicate files [" MG_SIZE_T_SPECIFIER "] first file is [%s]\n",fileList.size(),fileList[0].c_str());
2603 						}
2604 					}
2605 					if(foundDuplicates == true) {
2606 						printf("Duplicates %.2f MB (%d) in files\n",duplicateMegaBytes,duplicateCount);
2607 						printf("Duplicates purged %.2f MB (%d) in files\n",duplicateMegaBytesPurged,duplicateCountPurged);
2608 
2609 						printf("\nWarning, duplicate files were detected - END:\n");
2610 					}
2611 				}
2612 			}
2613 			catch(const megaglest_runtime_error &ex) {
2614 				techtree_errors = true;
2615 				printf("\n\n****ERROR**** detected while validating the techName: %s\nMESSAGE: %s\n",techName.c_str(),ex.what());
2616 			}
2617 
2618 			if(techtree_errors == false) {
2619 				printf("\nValidation found NO ERRORS for techPath [%s] techName [%s] factions checked (count = %d):\n",techPath.c_str(), techName.c_str(),(int)factions.size());
2620 				for ( set<string>::iterator it = factions.begin(); it != factions.end(); ++it ) {
2621 					printf("Faction [%s]\n",(*it).c_str());
2622 				}
2623 			}
2624 		}
2625 		printf("----------------------------------------------------------------");
2626 	}
2627 	else if(folderExists(techTreeFolder) == true) {
2628 		printf("\nWarning, No factions were found for the techtree located in: [%s]\n",techTreeFolder.c_str());
2629 	}
2630 }
2631 
2632 
runTechTranslationExtractionForPath(string techPath,string techName,const std::vector<string> & filteredFactionList,World & world)2633 void runTechTranslationExtractionForPath(string techPath, string techName,
2634 		const std::vector<string> &filteredFactionList, World &world) {
2635 	vector<string> factionsList;
2636 	findDirs(techPath + techName + "/factions/", factionsList, false, false);
2637 
2638 	if(factionsList.empty() == false) {
2639 		Checksum checksum;
2640 		set<string> factions;
2641 		for(int j = 0; j < (int)factionsList.size(); ++j) {
2642 			if(	filteredFactionList.empty() == true ||
2643 				std::find(filteredFactionList.begin(),filteredFactionList.end(),factionsList[j]) != filteredFactionList.end()) {
2644 				factions.insert(factionsList[j]);
2645 			}
2646 		}
2647 
2648 		printf("\n----------------------------------------------------------------");
2649 		printf("\nChecking techPath [%s] techName [%s] total faction count = %d\n",techPath.c_str(), techName.c_str(),(int)factionsList.size());
2650 		for(int j = 0; j < (int)factionsList.size(); ++j) {
2651 			if(	filteredFactionList.empty() == true ||
2652 				std::find(filteredFactionList.begin(),filteredFactionList.end(),factionsList[j]) != filteredFactionList.end()) {
2653 				printf("Using faction [%s]\n",factionsList[j].c_str());
2654 			}
2655 		}
2656 
2657 		if(factions.empty() == false) {
2658 			std::map<string,vector<pair<string, string> >  > loadedFileList;
2659 			vector<string> pathList;
2660 			pathList.push_back(techPath);
2661 			Config &config = Config::getInstance();
2662 			vector<string> otherTechPaths = config.getPathListForType(ptTechs,"");
2663 			pathList.insert(pathList.end(), otherTechPaths.begin(), otherTechPaths.end());
2664 
2665 			try {
2666 				world.loadTech(pathList, techName, factions, &checksum, loadedFileList, true);
2667 
2668 				const TechTree *techtree = world.getTechTree();
2669 				string translationFile = techtree->getPath();
2670 				endPathWithSlash(translationFile);
2671 				translationFile += "lang/" + techName + "_default.lng";
2672 				if(fileExists(translationFile) == false) {
2673 					string txFilePath = extractDirectoryPathFromFile(translationFile);
2674 					createDirectoryPaths(txFilePath);
2675 
2676 #if defined(WIN32) && !defined(__MINGW32__)
2677 					FILE *fp = _wfopen(utf8_decode(translationFile).c_str(), L"w");
2678 					std::ofstream txFile(fp);
2679 #else
2680 					std::ofstream txFile;
2681 					txFile.open(translationFile.c_str(), ios_base::out | ios_base::trunc);
2682 #endif
2683 
2684 					if(txFile.is_open() == true) {
2685 						string _transl_TechTreeName = techName;
2686 						replaceAll(_transl_TechTreeName,"_"," ");
2687 						txFile << "; TechTree" << std::endl;
2688 						txFile << "TechTreeName=" << _transl_TechTreeName << std::endl;
2689 
2690 						txFile << "; -------------------------------------" << std::endl;
2691 						txFile << "; Types of Armor" << std::endl;
2692 						for(int index = 0; index < techtree->getArmorTypeCount(); ++index) {
2693 							const ArmorType *at = techtree->getArmorTypeByIndex(index);
2694 							string _transl_ArmorTypeName = at->getName(false);
2695 							replaceAll(_transl_ArmorTypeName,"_"," ");
2696 							txFile << "ArmorTypeName_" << at->getName(false) << "=" << _transl_ArmorTypeName << std::endl;
2697 						}
2698 
2699 						txFile << "; --------------------" << std::endl;
2700 						txFile << "; Types of Attack" << std::endl;
2701 						for(int index = 0; index < techtree->getAttackTypeCount(); ++index) {
2702 							const AttackType *at = techtree->getAttackTypeByIndex(index);
2703 							string _transl_AttackTypeName = at->getName(false);
2704 							replaceAll(_transl_AttackTypeName,"_"," ");
2705 							txFile << "AttackTypeName_" << at->getName(false) << "=" << _transl_AttackTypeName << std::endl;
2706 						}
2707 
2708 						txFile << "; --------------------" << std::endl;
2709 						txFile << "; Types of Resources" << std::endl;
2710 						for(int index = 0; index < techtree->getResourceTypeCount(); ++index) {
2711 							const ResourceType *rt = techtree->getResourceType(index);
2712 							string _transl_ResourceTypeName = rt->getName(false);
2713 							replaceAll(_transl_ResourceTypeName,"_"," ");
2714 							txFile << "ResourceTypeName_" << rt->getName(false) << "=" << _transl_ResourceTypeName << std::endl;
2715 						}
2716 
2717 						//txFile << "FactionName_" << GameConstants::OBSERVER_SLOTNAME << "=" << GameConstants::OBSERVER_SLOTNAME << std::endl;
2718 						//txFile << "FactionName_" << GameConstants::RANDOMFACTION_SLOTNAME << "=" << GameConstants::RANDOMFACTION_SLOTNAME << std::endl;
2719 						for(int index = 0; index < techtree->getTypeCount(); ++index) {
2720 							const FactionType *ft = techtree->getType(index);
2721 							string _transl_FactionName = ft->getName(false);
2722 							replaceAll(_transl_FactionName,"_"," ");
2723 							txFile << "; -----------------------------------------------------------------------------" << std::endl;
2724 							txFile << "; Faction" << std::endl;
2725 							txFile << "FactionName_" << ft->getName(false) << "=" << _transl_FactionName << std::endl;
2726 
2727 							txFile << "; -------------------------------------" << std::endl;
2728 							txFile << "; Types of Upgrades for this Faction" << std::endl;
2729 							for(int upgradeIndex = 0; upgradeIndex < ft->getUpgradeTypeCount(); ++upgradeIndex) {
2730 								const UpgradeType *upt = ft->getUpgradeType(upgradeIndex);
2731 								string _transl_UpgradeTypeName = upt->getName(false);
2732 								replaceAll(_transl_UpgradeTypeName,"_"," ");
2733 								txFile << "UpgradeTypeName_" << upt->getName(false) << "=" << _transl_UpgradeTypeName << std::endl;
2734 							}
2735 
2736 							for(int unitIndex = 0; unitIndex < ft->getUnitTypeCount(); ++unitIndex) {
2737 								const UnitType *ut = ft->getUnitType(unitIndex);
2738 								string _transl_UnitTypeName = ut->getName(false);
2739 								replaceAll(_transl_UnitTypeName,"_"," ");
2740 								txFile << "; -------------------------------------" << std::endl;
2741 								txFile << "; Unit" << std::endl;
2742 								txFile << "UnitTypeName_" << ut->getName(false) << "=" << _transl_UnitTypeName << std::endl;
2743 
2744 								txFile << "; --------------------" << std::endl;
2745 								txFile << "; Levels for this Unit" << std::endl;
2746 								for(int levelIndex = 0; levelIndex < ut->getLevelCount(); ++levelIndex) {
2747 									const Level *level = ut->getLevel(levelIndex);
2748 									string _transl_LevelName = level->getName(false);
2749 									replaceAll(_transl_LevelName,"_"," ");
2750 									txFile << "LevelName_" << level->getName(false) << "=" << _transl_LevelName << std::endl;
2751 								}
2752 
2753 								txFile << "; --------------------" << std::endl;
2754 								txFile << "; Types of Commands for this Unit" << std::endl;
2755 								for(int commandIndex = 0; commandIndex < ut->getCommandTypeCount(); ++commandIndex) {
2756 									const CommandType *ct = ut->getCommandType(commandIndex);
2757 									string _transl_CommandName = ct->getName(false);
2758 									replaceAll(_transl_CommandName,"_"," ");
2759 									txFile << "CommandName_" << ct->getName(false) << "=" << _transl_CommandName << std::endl;
2760 								}
2761 							}
2762 						}
2763 						txFile << "; -------------------------------------" << std::endl;
2764 					}
2765 					txFile.close();
2766 
2767 #if defined(WIN32) && !defined(__MINGW32__)
2768 				if(fp) {
2769 					fclose(fp);
2770 				}
2771 #endif
2772 
2773 				}
2774 				else {
2775 					printf("\n** Cannot product techtree translation file [%s] for techPath [%s] techName [%s] because the file already exists!\n",translationFile.c_str(),techPath.c_str(), techName.c_str());
2776 				}
2777 			}
2778 			catch(const megaglest_runtime_error &ex) {
2779 				printf("\n\n****ERROR**** detected while loading the techName: %s\nMESSAGE: %s\n",techName.c_str(),ex.what());
2780 			}
2781 
2782 		}
2783 		printf("----------------------------------------------------------------");
2784 	}
2785 }
2786 
runTechTranslationExtraction(int argc,char ** argv)2787 void runTechTranslationExtraction(int argc, char** argv) {
2788 	printf("====== Started Translation Extraction ======\n");
2789 
2790 	Config &config = Config::getInstance();
2791 
2792     // Did the user pass a specific list of factions to validate?
2793     std::vector<string> filteredFactionList;
2794 
2795     vector<string> results;
2796     findDirs(config.getPathListForType(ptTechs), results);
2797     vector<string> techTreeFiles = results;
2798     // Did the user pass a specific list of techtrees to validate?
2799     std::vector<string> filteredTechTreeList;
2800     if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_TRANSLATE_TECHTREES]) + string("=")) == true) {
2801         int foundParamIndIndex = -1;
2802         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_TRANSLATE_TECHTREES]) + string("="),&foundParamIndIndex);
2803         string filterList = argv[foundParamIndIndex];
2804         vector<string> paramPartTokens;
2805         Tokenize(filterList,paramPartTokens,"=");
2806         if(paramPartTokens.size() >= 2) {
2807             string techtreeList = paramPartTokens[1];
2808             Tokenize(techtreeList,filteredTechTreeList,",");
2809 
2810             if(filteredTechTreeList.empty() == false) {
2811                 printf("Filtering techtrees and only looking for the following:\n");
2812                 for(int idx = 0; idx < (int)filteredTechTreeList.size(); ++idx) {
2813                     filteredTechTreeList[idx] = trim(filteredTechTreeList[idx]);
2814                     printf("%s\n",filteredTechTreeList[idx].c_str());
2815                 }
2816             }
2817         }
2818     }
2819 
2820     {
2821     printf("\n---------------- Loading factions inside world ----------------");
2822     World world;
2823 
2824     vector<string> techPaths = config.getPathListForType(ptTechs);
2825     for(int idx = 0; idx < (int)techPaths.size(); idx++) {
2826         string &techPath = techPaths[idx];
2827 		endPathWithSlash(techPath);
2828 
2829         for(int idx2 = 0; idx2 < (int)techTreeFiles.size(); idx2++) {
2830             string &techName = techTreeFiles[idx2];
2831 
2832             if(	filteredTechTreeList.empty() == true ||
2833                 std::find(filteredTechTreeList.begin(),filteredTechTreeList.end(),techName) != filteredTechTreeList.end()) {
2834 
2835             	runTechTranslationExtractionForPath(techPath, techName,
2836             			filteredFactionList,world);
2837             }
2838         }
2839     }
2840 
2841     printf("\n====== Finished Translation ======\n");
2842     }
2843 
2844 }
2845 
2846 
runTechValidationReport(int argc,char ** argv)2847 void runTechValidationReport(int argc, char** argv) {
2848 	printf("====== Started Validation ======\n");
2849 
2850 	bool purgeDuplicateFiles = false;
2851 	bool showDuplicateFiles = true;
2852 	bool purgeUnusedFiles = false;
2853 	bool gitPurgeFiles = false;
2854 
2855 	double purgedMegaBytes=0;
2856 	Config &config = Config::getInstance();
2857 
2858 	// Did the user pass a specific scenario to validate?
2859 	if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_SCENARIO]) + string("=")) == true) {
2860 
2861         int foundParamIndIndex = -1;
2862         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_SCENARIO]) + string("="),&foundParamIndIndex);
2863 
2864         string filterList = argv[foundParamIndIndex];
2865         vector<string> paramPartTokens;
2866         Tokenize(filterList,paramPartTokens,"=");
2867 
2868         if(paramPartTokens.size() >= 2) {
2869             string validateScenarioName = paramPartTokens[1];
2870 
2871 			printf("Filtering scenario: %s\n",validateScenarioName.c_str());
2872 
2873             if(paramPartTokens.size() >= 3) {
2874             	if(paramPartTokens[2] == "purgeunused") {
2875             		purgeUnusedFiles = true;
2876             		printf("*NOTE All unused scenario files will be deleted!\n");
2877             	}
2878             }
2879 
2880             {
2881             printf("\n---------------- Loading scenario inside world ----------------\n");
2882 
2883             bool scenarioFound = false;
2884             World world;
2885             std::vector<string> filteredFactionList;
2886 
2887             vector<string> scenarioPaths = config.getPathListForType(ptScenarios);
2888             for(int idx = 0; idx < (int)scenarioPaths.size(); idx++) {
2889                 string &scenarioPath = scenarioPaths[idx];
2890         		endPathWithSlash(scenarioPath);
2891 
2892         		vector<string> scenarioList;
2893         		findDirs(scenarioPath, scenarioList, false, false);
2894                 for(int idx2 = 0; idx2 < (int)scenarioList.size(); idx2++) {
2895                     string &scenarioName = scenarioList[idx2];
2896 
2897                     if(scenarioName == validateScenarioName) {
2898                     	scenarioFound = true;
2899 
2900                     	string file = scenarioPath + scenarioName + "/" + scenarioName + ".xml";
2901 
2902                         XmlTree xmlTree;
2903                     	xmlTree.load(file,Properties::getTagReplacementValues());
2904                     	const XmlNode *scenarioNode= xmlTree.getRootNode();
2905                     	string techName = scenarioNode->getChild("tech-tree")->getAttribute("value")->getValue();
2906 
2907                     	// Self Contained techtree?
2908                     	string scenarioTechtree = scenarioPath + scenarioName + "/" + techName + "/" + techName + ".xml";
2909 
2910                     	printf("\nFound Scenario [%s] looking for techtree [%s]...\n",scenarioName.c_str(),scenarioTechtree.c_str());
2911 
2912                     	if(fileExists(scenarioTechtree) == true) {
2913                     		string techPath = scenarioPath + scenarioName + "/";
2914 
2915                     		printf("\nFound Scenario [%s] with custom techtree [%s] validating...\n",scenarioName.c_str(),techName.c_str());
2916                     		runTechValidationForPath(techPath, techName, filteredFactionList,
2917                     					world, 	purgeUnusedFiles, showDuplicateFiles, false, false, purgedMegaBytes);
2918                     	}
2919                     	else {
2920                     	    vector<string> techPaths = config.getPathListForType(ptTechs);
2921                     	    for(int idx = 0; idx < (int)techPaths.size(); idx++) {
2922                     	        string &techPath = techPaths[idx];
2923                     			endPathWithSlash(techPath);
2924                     			scenarioTechtree = techPath + "/" + techName + "/" + techName + ".xml";
2925                     			if(fileExists(scenarioTechtree) == true) {
2926                     				printf("\nFound Scenario [%s] with techtree [%s] validating...\n",scenarioName.c_str(),techName.c_str());
2927                     				runTechValidationForPath(techPath, techName, filteredFactionList,
2928                     					world, 	purgeUnusedFiles, showDuplicateFiles, false, false, purgedMegaBytes);
2929 
2930                     				break;
2931                     			}
2932                     	    }
2933                     	}
2934                     }
2935                 }
2936             }
2937 
2938             if(scenarioFound == false) {
2939             	printf("\nWARNING, the scenario [%s] was NOT FOUND!\n",validateScenarioName.c_str());
2940             }
2941             printf("\n====== Finished Validation ======\n");
2942             }
2943             return;
2944         }
2945         else {
2946             printf("\nInvalid missing scenario specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
2947             return;
2948         }
2949     }
2950 
2951     // Did the user pass a specific list of factions to validate?
2952     std::vector<string> filteredFactionList;
2953     if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]) + string("=")) == true) {
2954         int foundParamIndIndex = -1;
2955         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]) + string("="),&foundParamIndIndex);
2956 
2957         string filterList = argv[foundParamIndIndex];
2958         vector<string> paramPartTokens;
2959         Tokenize(filterList,paramPartTokens,"=");
2960 
2961         if(paramPartTokens.size() >= 2) {
2962             string factionList = paramPartTokens[1];
2963             Tokenize(factionList,filteredFactionList,",");
2964 
2965             if(filteredFactionList.empty() == false) {
2966                 printf("Filtering factions and only looking for the following:\n");
2967                 for(int idx = 0; idx < (int)filteredFactionList.size(); ++idx) {
2968                     filteredFactionList[idx] = trim(filteredFactionList[idx]);
2969                     printf("%s\n",filteredFactionList[idx].c_str());
2970                 }
2971             }
2972 
2973             if(paramPartTokens.size() >= 3) {
2974             	if(paramPartTokens[2] == "purgeunused") {
2975             		purgeUnusedFiles = true;
2976             		printf("*NOTE All unused faction files will be deleted!\n");
2977             	}
2978             }
2979         }
2980     }
2981     vector<string> results;
2982     findDirs(config.getPathListForType(ptTechs), results);
2983     vector<string> techTreeFiles = results;
2984     // Did the user pass a specific list of techtrees to validate?
2985     std::vector<string> filteredTechTreeList;
2986     if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_TECHTREES]) + string("=")) == true) {
2987         int foundParamIndIndex = -1;
2988         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_TECHTREES]) + string("="),&foundParamIndIndex);
2989         string filterList = argv[foundParamIndIndex];
2990         vector<string> paramPartTokens;
2991         Tokenize(filterList,paramPartTokens,"=");
2992         if(paramPartTokens.size() >= 2) {
2993             string techtreeList = paramPartTokens[1];
2994             Tokenize(techtreeList,filteredTechTreeList,",");
2995 
2996             if(filteredTechTreeList.empty() == false) {
2997                 printf("Filtering techtrees and only looking for the following:\n");
2998                 for(int idx = 0; idx < (int)filteredTechTreeList.size(); ++idx) {
2999                     filteredTechTreeList[idx] = trim(filteredTechTreeList[idx]);
3000                     printf("%s\n",filteredTechTreeList[idx].c_str());
3001                 }
3002             }
3003 
3004             if(paramPartTokens.size() >= 3) {
3005             	if(paramPartTokens[2] == "purgeunused") {
3006             		purgeUnusedFiles = true;
3007             		printf("*NOTE All unused techtree files will be deleted!\n");
3008             	}
3009             	else if(paramPartTokens[2] == "purgeduplicates") {
3010             		purgeDuplicateFiles = true;
3011             		printf("*NOTE All duplicate techtree files will be merged!\n");
3012             	}
3013             	else if(paramPartTokens[2] == "gitdelete") {
3014             		gitPurgeFiles = true;
3015             		printf("*NOTE All unused / duplicate techtree files will be removed from git!\n");
3016             	}
3017             	else if(paramPartTokens[2] == "hideduplicates") {
3018             		showDuplicateFiles = false;
3019             		printf("*NOTE All duplicate techtree files will NOT be shown!\n");
3020             	}
3021             }
3022             if(paramPartTokens.size() >= 4) {
3023             	if(paramPartTokens[3] == "purgeunused") {
3024             		purgeUnusedFiles = true;
3025             		printf("*NOTE All unused techtree files will be deleted!\n");
3026             	}
3027             	else if(paramPartTokens[3] == "purgeduplicates") {
3028             		purgeDuplicateFiles = true;
3029             		printf("*NOTE All duplicate techtree files will be merged!\n");
3030             	}
3031             	else if(paramPartTokens[3] == "gitdelete") {
3032             		gitPurgeFiles = true;
3033             		printf("*NOTE All unused / duplicate techtree files will be removed from git!\n");
3034             	}
3035             	else if(paramPartTokens[3] == "hideduplicates") {
3036             		showDuplicateFiles = false;
3037             		printf("*NOTE All duplicate techtree files will NOT be shown!\n");
3038             	}
3039             }
3040             if(paramPartTokens.size() >= 5) {
3041             	if(paramPartTokens[4] == "purgeunused") {
3042             		purgeUnusedFiles = true;
3043             		printf("*NOTE All unused techtree files will be deleted!\n");
3044             	}
3045             	else if(paramPartTokens[4] == "purgeduplicates") {
3046             		purgeDuplicateFiles = true;
3047             		printf("*NOTE All duplicate techtree files will be merged!\n");
3048             	}
3049             	else if(paramPartTokens[4] == "gitdelete") {
3050             		gitPurgeFiles = true;
3051             		printf("*NOTE All unused / duplicate techtree files will be removed from git!\n");
3052             	}
3053             	else if(paramPartTokens[4] == "hideduplicates") {
3054             		showDuplicateFiles = false;
3055             		printf("*NOTE All duplicate techtree files will NOT be shown!\n");
3056             	}
3057             }
3058         }
3059     }
3060 
3061     {
3062     printf("\n---------------- Loading factions inside world ----------------");
3063     World world;
3064 
3065     vector<string> techPaths = config.getPathListForType(ptTechs);
3066     for(int idx = 0; idx < (int)techPaths.size(); idx++) {
3067         string &techPath = techPaths[idx];
3068 		endPathWithSlash(techPath);
3069 
3070         for(int idx2 = 0; idx2 < (int)techTreeFiles.size(); idx2++) {
3071             string &techName = techTreeFiles[idx2];
3072 
3073             if(	filteredTechTreeList.empty() == true ||
3074                 std::find(filteredTechTreeList.begin(),filteredTechTreeList.end(),techName) != filteredTechTreeList.end()) {
3075 
3076             	runTechValidationForPath(techPath, techName, filteredFactionList,
3077             			world, 	purgeUnusedFiles,purgeDuplicateFiles,
3078             			showDuplicateFiles,gitPurgeFiles,purgedMegaBytes);
3079             }
3080         }
3081     }
3082 
3083     printf("\n====== Finished Validation ======\n");
3084     }
3085 
3086 }
3087 
runTilesetValidationReport(int argc,char ** argv)3088 void runTilesetValidationReport(int argc, char** argv) {
3089 	printf("====== Started Validation ======\n");
3090 
3091 	Config &config = Config::getInstance();
3092 
3093 	// Did the user pass a specific tileset to validate?
3094 	if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_TILESET]) + string("=")) == true) {
3095         int foundParamIndIndex = -1;
3096         hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_VALIDATE_TILESET]) + string("="),&foundParamIndIndex);
3097 
3098         string filterList = argv[foundParamIndIndex];
3099         vector<string> paramPartTokens;
3100         Tokenize(filterList,paramPartTokens,"=");
3101 
3102         if(paramPartTokens.size() >= 2) {
3103             string validateTilesetName = paramPartTokens[1];
3104 
3105 			printf("Filtering tileset: %s\n",validateTilesetName.c_str());
3106 
3107 			bool purgeUnusedFiles = false;
3108             if(paramPartTokens.size() >= 3) {
3109             	if(paramPartTokens[2] == "purgeunused") {
3110             		purgeUnusedFiles = true;
3111             		printf("*NOTE All unused tileset files will be deleted!\n");
3112             	}
3113             }
3114 
3115             {
3116             printf("\n---------------- Loading tileset inside world ----------------\n");
3117 
3118             World world;
3119             double purgedMegaBytes=0;
3120     		bool showDuplicateFiles = true;
3121 
3122             bool tilesetFound = false;
3123 
3124             vector<string> tilesetPaths = config.getPathListForType(ptTilesets);
3125             for(int idx = 0; idx < (int)tilesetPaths.size(); idx++) {
3126                 string &tilesetPath = tilesetPaths[idx];
3127         		endPathWithSlash(tilesetPath);
3128 
3129         		vector<string> tilesetList;
3130         		findDirs(tilesetPath, tilesetList, false, false);
3131                 for(int idx2 = 0; idx2 < (int)tilesetList.size(); idx2++) {
3132                     string &tilesetName = tilesetList[idx2];
3133                     if(tilesetName == validateTilesetName) {
3134                     	tilesetFound = true;
3135 						runTilesetValidationForPath(tilesetPath, tilesetName,
3136 									world, 	purgeUnusedFiles, showDuplicateFiles,
3137 									false, false, purgedMegaBytes);
3138                     }
3139                 }
3140             }
3141 
3142             if(tilesetFound == false) {
3143             	printf("*ERROR The specified tileset [%s] was NOT FOUND!\n",validateTilesetName.c_str());
3144             }
3145             printf("\n====== Finished Validation ======\n");
3146             }
3147             return;
3148         }
3149         else {
3150             printf("\nInvalid missing tileset specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3151             return;
3152         }
3153     }
3154 	else {
3155         printf("\nInvalid missing tileset specified on commandline\n\n");
3156         return;
3157 	}
3158 }
3159 
ShowINISettings(int argc,char ** argv,Config & config,Config & configKeys)3160 void ShowINISettings(int argc, char **argv,Config &config,Config &configKeys) {
3161     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_INI_SETTINGS]) == true) {
3162         vector<string> filteredPropertyList;
3163         if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_INI_SETTINGS]) + string("=")) == true) {
3164             int foundParamIndIndex = -1;
3165             hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_INI_SETTINGS]) + string("="),&foundParamIndIndex);
3166             string filterList = argv[foundParamIndIndex];
3167             vector<string> paramPartTokens;
3168             Tokenize(filterList,paramPartTokens,"=");
3169             if(paramPartTokens.size() >= 2) {
3170                 string tokenList = paramPartTokens[1];
3171                 Tokenize(tokenList,filteredPropertyList,",");
3172 
3173                 if(filteredPropertyList.empty() == false) {
3174                     printf("Filtering properties and only looking for the following:\n");
3175                     for(int idx = 0; idx < (int)filteredPropertyList.size(); ++idx) {
3176                         filteredPropertyList[idx] = trim(filteredPropertyList[idx]);
3177                         printf("%s\n",filteredPropertyList[idx].c_str());
3178                     }
3179                 }
3180             }
3181         }
3182 
3183         printf("\nMain settings report\n");
3184         printf("====================\n");
3185         vector<pair<string,string> > mergedMainSettings = config.getMergedProperties();
3186         vector<pair<string,string> > mergedKeySettings = configKeys.getMergedProperties();
3187 
3188         // Figure out the max # of tabs we need to format display nicely
3189         int tabCount = 1;
3190         for(int i = 0; i < (int)mergedMainSettings.size(); ++i) {
3191             const pair<string,string> &nameValue = mergedMainSettings[i];
3192 
3193             bool displayProperty = false;
3194             if(filteredPropertyList.empty() == false) {
3195                 if(find(filteredPropertyList.begin(),filteredPropertyList.end(),nameValue.first) != filteredPropertyList.end()) {
3196                     displayProperty = true;
3197                 }
3198             }
3199             else {
3200                 displayProperty = true;
3201             }
3202 
3203             if(displayProperty == true) {
3204                 int requredTabs = ((int)nameValue.first.length() / 8)+1;
3205                 if(nameValue.first.length() % 8) {
3206                     requredTabs++;
3207                 }
3208                 if(requredTabs > tabCount) {
3209                     tabCount = requredTabs;
3210                 }
3211             }
3212         }
3213         for(int i = 0; i < (int)mergedKeySettings.size(); ++i) {
3214             const pair<string,string> &nameValue = mergedKeySettings[i];
3215 
3216             bool displayProperty = false;
3217             if(filteredPropertyList.empty() == false) {
3218                 if(find(filteredPropertyList.begin(),filteredPropertyList.end(),nameValue.first) != filteredPropertyList.end()) {
3219                     displayProperty = true;
3220                 }
3221             }
3222             else {
3223                 displayProperty = true;
3224             }
3225 
3226             if(displayProperty == true) {
3227                 int requredTabs = ((int)nameValue.first.length() / 8)+1;
3228                 if(nameValue.first.length() % 8) {
3229                     requredTabs++;
3230                 }
3231                 if(requredTabs > tabCount) {
3232                     tabCount = requredTabs;
3233                 }
3234             }
3235         }
3236 
3237         // Output the properties
3238         for(int i = 0; i < (int)mergedMainSettings.size(); ++i) {
3239             const pair<string,string> &nameValue = mergedMainSettings[i];
3240 
3241             bool displayProperty = false;
3242             if(filteredPropertyList.empty() == false) {
3243                 if(find(filteredPropertyList.begin(),filteredPropertyList.end(),nameValue.first) != filteredPropertyList.end()) {
3244                     displayProperty = true;
3245                 }
3246             }
3247             else {
3248                 displayProperty = true;
3249             }
3250 
3251             if(displayProperty == true) {
3252                 printf("Property Name [%s]",nameValue.first.c_str());
3253 
3254                 int tabs = ((int)nameValue.first.length() / 8) + 1;
3255                 for(int j = 0; j < (tabCount - tabs); ++j) {
3256                     printf("\t");
3257                 }
3258 
3259                 string displayValue = nameValue.second;
3260                 if(nameValue.first == "TranslationGetURLPassword") {
3261                 	displayValue = "*****";
3262                 }
3263 
3264                 printf("Value [%s]\n",displayValue.c_str());
3265             }
3266         }
3267 
3268         printf("\n\nMain key binding settings report\n");
3269         printf("====================================\n");
3270 
3271         for(int i = 0; i < (int)mergedKeySettings.size(); ++i) {
3272             const pair<string,string> &nameValue = mergedKeySettings[i];
3273 
3274             bool displayProperty = false;
3275             if(filteredPropertyList.empty() == false) {
3276                 if(find(filteredPropertyList.begin(),filteredPropertyList.end(),nameValue.first) != filteredPropertyList.end()) {
3277                     displayProperty = true;
3278                 }
3279             }
3280             else {
3281                 displayProperty = true;
3282             }
3283 
3284             if(displayProperty == true) {
3285                 printf("Property Name [%s]",nameValue.first.c_str());
3286 
3287                 int tabs = ((int)nameValue.first.length() / 8) + 1;
3288                 for(int j = 0; j < (tabCount - tabs); ++j) {
3289                     printf("\t");
3290                 }
3291 
3292                 printf("Value [%s]\n",nameValue.second.c_str());
3293             }
3294         }
3295     }
3296 }
3297 
CheckForDuplicateData()3298 void CheckForDuplicateData() {
3299     Config &config = Config::getInstance();
3300 
3301     string duplicateWarnings="";
3302 
3303     try {
3304 
3305 
3306     {
3307 
3308   	string scenarioDir = "";
3309   	vector<string> pathList = config.getPathListForType(ptMaps,scenarioDir);
3310   	vector<string> invalidMapList;
3311   	vector<string> maps = MapPreview::findAllValidMaps(pathList,scenarioDir,false,true,&invalidMapList);
3312 	std::sort(maps.begin(),maps.end());
3313 
3314 	if(maps.empty() == true) {
3315         throw megaglest_runtime_error("No maps were found!",true);
3316     }
3317 	else if(invalidMapList.empty() == false) {
3318 		string errorMsg = "Warning invalid maps were detected (will be ignored):\n";
3319 		for(int i = 0; i < (int)invalidMapList.size(); ++i) {
3320 			char szBuf[8096]="";
3321 			snprintf(szBuf,8096,"map [%s]\n",invalidMapList[i].c_str());
3322 
3323 			errorMsg += szBuf;
3324 		}
3325 		duplicateWarnings += errorMsg;
3326 	}
3327 
3328 	vector<string> duplicateMapsToRename;
3329 	for(int i = 0; i < (int)maps.size(); ++i) {
3330 	    string map1 = maps[i];
3331 	    for(int j = 0; j < (int)maps.size(); ++j) {
3332 	        if(i != j) {
3333                 string map2 = maps[j];
3334 
3335                 if(map1 == map2) {
3336                 	if(std::find(duplicateMapsToRename.begin(),duplicateMapsToRename.end(),map1) == duplicateMapsToRename.end()) {
3337                 		duplicateMapsToRename.push_back(map1);
3338                 	}
3339                 }
3340 	        }
3341 	    }
3342 	}
3343 	if(duplicateMapsToRename.empty() == false) {
3344 		string errorMsg = "Warning duplicate maps were detected and renamed:\n";
3345 		for(int i = 0; i < (int)duplicateMapsToRename.size(); ++i) {
3346 			string currentPath = pathList[1];
3347 			endPathWithSlash(currentPath);
3348 
3349 			string oldFile = currentPath + duplicateMapsToRename[i];
3350 			string newFile = currentPath + duplicateMapsToRename[i];
3351 			string ext = extractExtension(newFile);
3352 			newFile = newFile.substr( 0, newFile.length()-ext.length()-1);
3353 			newFile = newFile + "_custom." + ext;
3354 
3355 			char szBuf[8096]="";
3356 			int result = rename(oldFile.c_str(),newFile.c_str());
3357 			if(result != 0) {
3358 				char *errmsg = strerror(errno);
3359 				snprintf(szBuf,8096,"Error [%s]\nCould not rename [%s] to [%s]!",errmsg,oldFile.c_str(),newFile.c_str());
3360 				throw megaglest_runtime_error(szBuf,true);
3361 			}
3362 			else {
3363 				snprintf(szBuf,8096,"map [%s] in [%s]\nwas renamed to [%s]",duplicateMapsToRename[i].c_str(),oldFile.c_str(),newFile.c_str());
3364 			}
3365 			errorMsg += szBuf;
3366 		}
3367 		duplicateWarnings += errorMsg;
3368 	}
3369     }
3370 
3371     {
3372 	//tilesets
3373 	std::vector<std::string> tileSets;
3374     vector<string> tilesetPaths = config.getPathListForType(ptTilesets);
3375     findDirs(tilesetPaths, tileSets, false, true);
3376 
3377 	if (tileSets.empty()) {
3378         throw megaglest_runtime_error("No tilesets were found!",true);
3379     }
3380 
3381 	vector<string> duplicateTilesetsToRename;
3382 	for(int i = 0; i < (int)tileSets.size(); ++i) {
3383 	    string tileSet1 = tileSets[i];
3384 	    for(int j = 0; j < (int)tileSets.size(); ++j) {
3385 	        if(i != j) {
3386                 string tileSet2= tileSets[j];
3387                 if(tileSet1 == tileSet2) {
3388                 	if(std::find(duplicateTilesetsToRename.begin(),duplicateTilesetsToRename.end(),tileSet1) == duplicateTilesetsToRename.end()) {
3389                 		duplicateTilesetsToRename.push_back(tileSet1);
3390                 	}
3391                 }
3392 	        }
3393 	    }
3394 	}
3395 	if(duplicateTilesetsToRename.empty() == false) {
3396 		string errorMsg = "Warning duplicate tilesets were detected and renamed:\n";
3397 
3398 		for(int i = 0; i < (int)duplicateTilesetsToRename.size(); ++i) {
3399 			string currentPath = tilesetPaths[1];
3400 			endPathWithSlash(currentPath);
3401 
3402 			string oldFile = currentPath + duplicateTilesetsToRename[i];
3403 			string newFile = currentPath + duplicateTilesetsToRename[i];
3404 			newFile = newFile + "_custom";
3405 
3406 			char szBuf[8096]="";
3407 			int result = rename(oldFile.c_str(),newFile.c_str());
3408 			if(result != 0) {
3409 				char *errmsg = strerror(errno);
3410 				snprintf(szBuf,8096,"Error [%s]\nCould not rename [%s] to [%s]!",errmsg,oldFile.c_str(),newFile.c_str());
3411 				throw megaglest_runtime_error(szBuf,true);
3412 			}
3413 			else {
3414 				snprintf(szBuf,8096,"tileset [%s] in [%s]\nwas renamed to [%s]",duplicateTilesetsToRename[i].c_str(),oldFile.c_str(),newFile.c_str());
3415 
3416 				string tilesetName = extractFileFromDirectoryPath(oldFile);
3417 				oldFile = newFile + "/" + tilesetName + ".xml";
3418 				newFile = newFile + "/" + tilesetName + "_custom.xml";
3419 
3420 				result = rename(oldFile.c_str(),newFile.c_str());
3421 
3422 				if(result != 0) {
3423 					char *errmsg = strerror(errno);
3424 					snprintf(szBuf,8096,"Error [%s]\nCould not rename [%s] to [%s]!",errmsg,oldFile.c_str(),newFile.c_str());
3425 					throw megaglest_runtime_error(szBuf,true);
3426 				}
3427 
3428 			}
3429 			errorMsg += szBuf;
3430 		}
3431 		duplicateWarnings += errorMsg;
3432 	}
3433     }
3434 
3435     {
3436     vector<string> techPaths = config.getPathListForType(ptTechs);
3437     vector<string> techTrees;
3438     findDirs(techPaths, techTrees, false, true);
3439 	if(techTrees.empty()) {
3440         throw megaglest_runtime_error("No tech-trees were found (dup)!",true);
3441 	}
3442 
3443 	vector<string> duplicateTechtreesToRename;
3444 	for(int i = 0; i < (int)techTrees.size(); ++i) {
3445 	    string techtree1 = techTrees[i];
3446 	    for(int j = 0; j < (int)techTrees.size(); ++j) {
3447 	        if(i != j) {
3448                 string techtree2 = techTrees[j];
3449                 if(techtree1 == techtree2) {
3450                 	if(std::find(duplicateTechtreesToRename.begin(),duplicateTechtreesToRename.end(),techtree1) == duplicateTechtreesToRename.end()) {
3451                 		duplicateTechtreesToRename.push_back(techtree1);
3452                 	}
3453                 }
3454 	        }
3455 	    }
3456 	}
3457 	if(duplicateTechtreesToRename.empty() == false) {
3458 		string errorMsg = "Warning duplicate techtrees were detected and renamed:\n";
3459 
3460 		for(int i = 0; i < (int)duplicateTechtreesToRename.size(); ++i) {
3461 			string currentPath = techPaths[1];
3462 			endPathWithSlash(currentPath);
3463 
3464 			string oldFile = currentPath + duplicateTechtreesToRename[i];
3465 			string newFile = currentPath + duplicateTechtreesToRename[i];
3466 			newFile = newFile + "_custom";
3467 
3468 			char szBuf[8096]="";
3469 			int result = rename(oldFile.c_str(),newFile.c_str());
3470 			if(result != 0) {
3471 				char *errmsg = strerror(errno);
3472 				snprintf(szBuf,8096,"Error [%s]\nCould not rename [%s] to [%s]!",errmsg,oldFile.c_str(),newFile.c_str());
3473 				throw megaglest_runtime_error(szBuf,true);
3474 			}
3475 			else {
3476 				snprintf(szBuf,8096,"techtree [%s] in [%s]\nwas renamed to [%s]",duplicateTechtreesToRename[i].c_str(),oldFile.c_str(),newFile.c_str());
3477 
3478 				string tilesetName = extractFileFromDirectoryPath(oldFile);
3479 				oldFile = newFile + "/" + tilesetName + ".xml";
3480 				newFile = newFile + "/" + tilesetName + "_custom.xml";
3481 
3482 				int rename_result = rename(oldFile.c_str(),newFile.c_str());
3483 				if(rename_result != 0) {
3484 					printf("Error renaming [%s] to [%s]\n",oldFile.c_str(),newFile.c_str());
3485 				}
3486 			}
3487 			errorMsg += szBuf;
3488 		}
3489 		duplicateWarnings += errorMsg;
3490 	}
3491     }
3492 
3493     }
3494     catch(const megaglest_runtime_error &ex) {
3495 		if(mainProgram) {
3496 			mainProgram->getState()->setForceMouseRender(true);
3497 		}
3498 		ExceptionHandler::DisplayMessage(ex.what(), false);
3499     }
3500 
3501     if(duplicateWarnings != "") {
3502 		if(mainProgram) {
3503 			mainProgram->getState()->setForceMouseRender(true);
3504 		}
3505 		ExceptionHandler::DisplayMessage(duplicateWarnings.c_str(), false);
3506     }
3507 }
3508 
handleCreateDataArchivesCommand(int argc,char ** argv)3509 int handleCreateDataArchivesCommand(int argc, char** argv) {
3510 	int return_value = 1;
3511 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]) == true) {
3512 		int foundParamIndIndex = -1;
3513 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]) + string("="),&foundParamIndIndex);
3514 		if(foundParamIndIndex < 0) {
3515 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]),&foundParamIndIndex);
3516 		}
3517 		string paramValue = argv[foundParamIndIndex];
3518 		vector<string> paramPartTokens;
3519 		Tokenize(paramValue,paramPartTokens,"=");
3520 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3521 			string compress_item = paramPartTokens[1];
3522 			bool includeMainData = false;
3523 			if(paramPartTokens.size() >= 3 && paramPartTokens[2] == "include_main") {
3524 				includeMainData = true;
3525 			}
3526 
3527 			Config &config = Config::getInstance();
3528 			string fileArchiveExtension = config.getString("FileArchiveExtension","");
3529 			string fileArchiveCompressCommand = config.getString("FileArchiveCompressCommand","");
3530 			string fileArchiveCompressCommandParameters = config.getString("FileArchiveCompressCommandParameters","");
3531 			int32 fileArchiveCompressCommandSuccessResult = config.getInt("FileArchiveCompressCommandSuccessResult","0");
3532 
3533 		    string userData = config.getString("UserData_Root","");
3534 		    if(userData != "") {
3535 		    	endPathWithSlash(userData);
3536 		    }
3537 
3538 			int typesSelected = 0;
3539 			if(compress_item == "techtrees" || compress_item == "all") {
3540 				typesSelected++;
3541 
3542 				vector<string> pathList = config.getPathListForType(ptTechs,"");
3543 				vector<string> results;
3544 				findDirs(pathList, results);
3545 
3546 				printf("Techtrees found:\n===========================================\n");
3547 				for(unsigned int i = 0; i < results.size(); ++i) {
3548 					string name = results[i];
3549 
3550 					for(unsigned int j = 0; j < pathList.size(); ++j) {
3551 						string techPath = pathList[j];
3552 						if(techPath != "") {
3553 							endPathWithSlash(techPath);
3554 						}
3555 
3556 						vector<string> results2;
3557 						findDirs(techPath + name + "/factions", results2, false,true);
3558 						if(results2.empty() == false) {
3559 							string techtreePath = techPath + name;
3560 							if(includeMainData == false) {
3561 								if(techtreePath.find(userData) == techPath.npos) {
3562 									printf("Skipping techtree: [%s]\n",techtreePath.c_str());
3563 									continue;
3564 								}
3565 							}
3566 
3567 							string downloadArchive = techtreePath + fileArchiveExtension;
3568 
3569 							if(fileExists(downloadArchive) == true) {
3570 								bool removed = removeFile(downloadArchive);
3571 								if(removed == false) {
3572 									printf("Error could not remove old file: [%s]\n",downloadArchive.c_str());
3573 								}
3574 							}
3575 							string compressCmd = getFullFileArchiveCompressCommand(
3576 									fileArchiveCompressCommand,
3577 									fileArchiveCompressCommandParameters,
3578 									downloadArchive,techtreePath );
3579 
3580 							printf("Running compression command: %s\n",compressCmd.c_str());
3581 
3582 							if(executeShellCommand(compressCmd,fileArchiveCompressCommandSuccessResult) == false) {
3583 								printf("Error could not create new file: [%s]\n",downloadArchive.c_str());
3584 							}
3585 
3586 							if(fileExists(downloadArchive) == true) {
3587 								off_t fileSize = getFileSize(downloadArchive);
3588 								// convert to MB
3589 								double megaBytes = ((double)fileSize / 1048576.0);
3590 								printf("%s [download archive %.2fMB]\n",name.c_str(),megaBytes);
3591 							}
3592 						}
3593 					}
3594 				}
3595 				printf("===========================================\nTotal: " MG_SIZE_T_SPECIFIER "\n",results.size());
3596 			}
3597 			if(compress_item == "tilesets" || compress_item == "all") {
3598 				typesSelected++;
3599 
3600 				vector<string> pathList = config.getPathListForType(ptTilesets,"");
3601 				vector<string> results;
3602 				findDirs(pathList, results);
3603 
3604 				printf("Tilesets found:\n===========================================\n");
3605 				for(unsigned int i = 0; i < results.size(); ++i) {
3606 					string name = results[i];
3607 
3608 					for(unsigned int j = 0; j < pathList.size(); ++j) {
3609 						string tilesetPath = pathList[j];
3610 						if(tilesetPath != "") {
3611 							endPathWithSlash(tilesetPath);
3612 						}
3613 
3614 						if(fileExists(tilesetPath + name + "/" + name + ".xml") == true) {
3615 							string tilesetDataPath = tilesetPath + name;
3616 							if(includeMainData == false) {
3617 								if(tilesetPath.find(userData) == tilesetPath.npos) {
3618 									printf("Skipping tileset data: [%s]\n",tilesetDataPath.c_str());
3619 									continue;
3620 								}
3621 							}
3622 
3623 							string downloadArchive = tilesetDataPath + fileArchiveExtension;
3624 
3625 							if(fileExists(downloadArchive) == true) {
3626 								bool removed = removeFile(downloadArchive);
3627 								if(removed == false) {
3628 									printf("Error could not remove old file: [%s]\n",downloadArchive.c_str());
3629 								}
3630 							}
3631 							string compressCmd = getFullFileArchiveCompressCommand(
3632 									fileArchiveCompressCommand,
3633 									fileArchiveCompressCommandParameters,
3634 									downloadArchive,tilesetDataPath );
3635 
3636 							printf("Running compression command: %s\n",compressCmd.c_str());
3637 
3638 							if(executeShellCommand(compressCmd,fileArchiveCompressCommandSuccessResult) == false) {
3639 								printf("Error could not create new file: [%s]\n",downloadArchive.c_str());
3640 							}
3641 
3642 							if(fileExists(downloadArchive) == true) {
3643 								off_t fileSize = getFileSize(downloadArchive);
3644 								// convert to MB
3645 								double megaBytes = ((double)fileSize / 1048576.0);
3646 								printf("%s [download archive %.2fMB]\n",name.c_str(),megaBytes);
3647 							}
3648 
3649 							break;
3650 						}
3651 					}
3652 				}
3653 				printf("===========================================\nTotal: " MG_SIZE_T_SPECIFIER "\n",results.size());
3654 
3655 			}
3656 			if(typesSelected == 0) {
3657 				printf("Compress item [%s] is not valid!\n",compress_item.c_str());
3658 				return_value = 1;
3659 			}
3660 			else
3661 				return_value = 0;
3662 		}
3663 		else {
3664 			printf("\nInvalid missing map specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3665 
3666 			return_value = 1;
3667 		}
3668 	}
3669 
3670 	return return_value;
3671 }
3672 
handleShowCRCValuesCommand(int argc,char ** argv)3673 int handleShowCRCValuesCommand(int argc, char** argv) {
3674 	int return_value = 1;
3675 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_MAP_CRC]) == true) {
3676 		int foundParamIndIndex = -1;
3677 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_MAP_CRC]) + string("="),&foundParamIndIndex);
3678 		if(foundParamIndIndex < 0) {
3679 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_MAP_CRC]),&foundParamIndIndex);
3680 		}
3681 		string paramValue = argv[foundParamIndIndex];
3682 		vector<string> paramPartTokens;
3683 		Tokenize(paramValue,paramPartTokens,"=");
3684 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3685 			string itemName = paramPartTokens[1];
3686 
3687 			string file = Config::getMapPath(itemName,"",false);
3688 			if(file != "") {
3689 				Checksum checksum;
3690 				checksum.addFile(file);
3691 				uint32 crcValue = checksum.getSum();
3692 
3693 				printf("CRC value for map [%s] file [%s] is [%u]\n",itemName.c_str(),file.c_str(),crcValue);
3694 
3695 				return_value = 0;
3696 			}
3697 			else {
3698 				printf("Map [%s] was NOT FOUND\n",itemName.c_str());
3699 				return_value = 1;
3700 			}
3701 		}
3702 		else {
3703 			printf("\nInvalid missing map specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3704 
3705 			return_value = 1;
3706 		}
3707 	}
3708 
3709 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_TILESET_CRC]) == true) {
3710 		int foundParamIndIndex = -1;
3711 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_TILESET_CRC]) + string("="),&foundParamIndIndex);
3712 		if(foundParamIndIndex < 0) {
3713 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_TILESET_CRC]),&foundParamIndIndex);
3714 		}
3715 		string paramValue = argv[foundParamIndIndex];
3716 		vector<string> paramPartTokens;
3717 		Tokenize(paramValue,paramPartTokens,"=");
3718 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3719 			string itemName = paramPartTokens[1];
3720 
3721 			Config &config = Config::getInstance();
3722 			uint32 crcValue = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTilesets,""), string("/") + itemName + string("/*"), ".xml", NULL, true);
3723 			if(crcValue != 0) {
3724 				printf("CRC value for tileset [%s] is [%u]\n",itemName.c_str(),crcValue);
3725 
3726 				return_value = 0;
3727 			}
3728 			else {
3729 				printf("Tileset [%s] was NOT FOUND\n",itemName.c_str());
3730 				return_value = 1;
3731 			}
3732 		}
3733 		else {
3734 			printf("\nInvalid missing tileset specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3735 
3736 			return_value = 1;
3737 		}
3738 	}
3739 
3740 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_TECHTREE_CRC]) == true) {
3741 		int foundParamIndIndex = -1;
3742 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_TECHTREE_CRC]) + string("="),&foundParamIndIndex);
3743 		if(foundParamIndIndex < 0) {
3744 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_TECHTREE_CRC]),&foundParamIndIndex);
3745 		}
3746 		string paramValue = argv[foundParamIndIndex];
3747 		vector<string> paramPartTokens;
3748 		Tokenize(paramValue,paramPartTokens,"=");
3749 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3750 			string itemName = paramPartTokens[1];
3751 
3752 			Config &config = Config::getInstance();
3753 			uint32 crcValue = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptTechs,""), "/" + itemName + "/*", ".xml", NULL, true);
3754 			if(crcValue != 0) {
3755 				printf("CRC value for techtree [%s] is [%u]\n",itemName.c_str(),crcValue);
3756 
3757 				return_value = 0;
3758 			}
3759 			else {
3760 				printf("Techtree [%s] was NOT FOUND\n",itemName.c_str());
3761 
3762 				return_value = 1;
3763 			}
3764 		}
3765 		else {
3766 			printf("\nInvalid missing techtree specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3767 
3768 			return_value = 1;
3769 		}
3770 	}
3771 
3772 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_SCENARIO_CRC]) == true) {
3773 		int foundParamIndIndex = -1;
3774 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_SCENARIO_CRC]) + string("="),&foundParamIndIndex);
3775 		if(foundParamIndIndex < 0) {
3776 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_SCENARIO_CRC]),&foundParamIndIndex);
3777 		}
3778 		string paramValue = argv[foundParamIndIndex];
3779 		vector<string> paramPartTokens;
3780 		Tokenize(paramValue,paramPartTokens,"=");
3781 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3782 			string itemName = paramPartTokens[1];
3783 
3784 			Config &config = Config::getInstance();
3785 			uint32 crcValue = getFolderTreeContentsCheckSumRecursively(config.getPathListForType(ptScenarios,""), "/" + itemName + "/*", ".xml", NULL, true);
3786 			if(crcValue != 0) {
3787 				printf("CRC value for scenario [%s] is [%u]\n",itemName.c_str(),crcValue);
3788 
3789 				return_value = 0;
3790 			}
3791 			else {
3792 				printf("Scenario [%s] was NOT FOUND\n",itemName.c_str());
3793 				return_value = 1;
3794 			}
3795 		}
3796 		else {
3797 			printf("\nInvalid missing scenario specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3798 
3799 			return_value = 0;
3800 		}
3801 	}
3802 
3803 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_PATH_CRC]) == true) {
3804 		int foundParamIndIndex = -1;
3805 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_PATH_CRC]) + string("="),&foundParamIndIndex);
3806 		if(foundParamIndIndex < 0) {
3807 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SHOW_PATH_CRC]),&foundParamIndIndex);
3808 		}
3809 
3810 		string paramValue = argv[foundParamIndIndex];
3811 		vector<string> paramPartTokens;
3812 		Tokenize(paramValue,paramPartTokens,"=");
3813 		if(paramPartTokens.size() >= 3 && paramPartTokens[1].length() > 0) {
3814 			string itemName = paramPartTokens[1];
3815 			string itemNameFilter = paramPartTokens[2];
3816 			uint32 crcValue = getFolderTreeContentsCheckSumRecursively(itemName, itemNameFilter, NULL, true);
3817 
3818 			printf("CRC value for path [%s] filter [%s] is [%u]\n",itemName.c_str(),itemNameFilter.c_str(),crcValue);
3819 
3820 			return_value = 0;
3821 		}
3822 		else {
3823 			if(paramPartTokens.size() < 2) {
3824 				printf("\nInvalid missing path and filter specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
3825 			}
3826 			if(paramPartTokens.size() < 3) {
3827 				printf("\nInvalid missing filter specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 3 ? paramPartTokens[2].c_str() : NULL));
3828 			}
3829 
3830 			return_value = 1;
3831 		}
3832 	}
3833 
3834 	return return_value;
3835 }
3836 
handleListDataCommand(int argc,char ** argv)3837 int handleListDataCommand(int argc, char** argv) {
3838 	int return_value = 1;
3839 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_MAPS]) == true) {
3840 		int foundParamIndIndex = -1;
3841 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_MAPS]) + string("="),&foundParamIndIndex);
3842 		if(foundParamIndIndex < 0) {
3843 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_MAPS]),&foundParamIndIndex);
3844 		}
3845 
3846 		Config &config = Config::getInstance();
3847 	  	vector<string> pathList = config.getPathListForType(ptMaps,"");
3848 	  	vector<string> maps = MapPreview::findAllValidMaps(pathList,"",false,true);
3849 		std::sort(maps.begin(),maps.end());
3850 
3851 		string paramValue = argv[foundParamIndIndex];
3852 		vector<string> paramPartTokens;
3853 		Tokenize(paramValue,paramPartTokens,"=");
3854 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3855 			string itemNameFilter = paramPartTokens[1];
3856 			printf("Using filter for maps list [%s]\n",itemNameFilter.c_str());
3857 
3858 			vector<string> filteredMaps;
3859 			for(unsigned int i = 0; i < maps.size(); ++i) {
3860 				string mapName = maps[i];
3861 				if(itemNameFilter.find("*") != itemNameFilter.npos) {
3862 					if(StartsWith(mapName, itemNameFilter.substr(0,itemNameFilter.find("*"))) == true) {
3863 						filteredMaps.push_back(mapName);
3864 					}
3865 				}
3866 				else if(mapName == itemNameFilter) {
3867 					filteredMaps.push_back(mapName);
3868 				}
3869 			}
3870 			maps = filteredMaps;
3871 		}
3872 
3873 		printf("Maps found:\n===========================================\n");
3874 		for(unsigned int i = 0; i < maps.size(); ++i) {
3875 			string mapName = maps[i];
3876 			printf("%s\n",mapName.c_str());
3877 		}
3878 		printf("===========================================\nTotal: " MG_SIZE_T_SPECIFIER "\n",maps.size());
3879 
3880 		return_value = 0;
3881 	}
3882 
3883 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TECHTRESS]) == true) {
3884 		int foundParamIndIndex = -1;
3885 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_TECHTRESS]) + string("="),&foundParamIndIndex);
3886 		if(foundParamIndIndex < 0) {
3887 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_TECHTRESS]),&foundParamIndIndex);
3888 		}
3889 
3890 		Config &config = Config::getInstance();
3891 	  	vector<string> pathList = config.getPathListForType(ptTechs,"");
3892 	  	vector<string> results;
3893 	  	findDirs(pathList, results);
3894 
3895 	  	bool showfactions=false;
3896 		string paramValue = argv[foundParamIndIndex];
3897 		vector<string> paramPartTokens;
3898 		Tokenize(paramValue,paramPartTokens,"=");
3899 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3900 			string cmd = paramPartTokens[1];
3901 			if(cmd == "showfactions") {
3902 				showfactions = true;
3903 			}
3904 			else {
3905 				throw megaglest_runtime_error("unknown command for techtreelist [" + cmd + "]");
3906 			}
3907 			printf("Using special command for techtree list [%s]\n",cmd.c_str());
3908 		}
3909 
3910 		printf("Techtrees found:\n===========================================\n");
3911 		for(unsigned int i = 0; i < results.size(); ++i) {
3912 			string name = results[i];
3913 
3914 			for(unsigned int j = 0; j < pathList.size(); ++j) {
3915 				string techPath = pathList[j];
3916 				if(techPath != "") {
3917 					endPathWithSlash(techPath);
3918 				}
3919 				vector<string> results2;
3920 				findDirs(techPath + name + "/factions", results2, false,true);
3921 				if(results2.empty() == false) {
3922 					string downloadArchive = techPath + name + ".7z";
3923 
3924 					if(fileExists(downloadArchive) == true) {
3925 						off_t fileSize = getFileSize(downloadArchive);
3926 						// convert to MB
3927 						double megaBytes = ((double)fileSize / 1048576.0);
3928 						printf("%s [download archive %.2fMB]\n",name.c_str(),megaBytes);
3929 					}
3930 					else {
3931 						printf("%s\n",name.c_str());
3932 					}
3933 
3934 					if(showfactions == true) {
3935 						printf("--> Factions:\n");
3936 						for(unsigned int k = 0; k < results2.size(); ++k) {
3937 							string name2 = results2[k];
3938 							printf("--> %s\n",name2.c_str());
3939 						}
3940 						printf("--> Total Factions: " MG_SIZE_T_SPECIFIER "\n",results2.size());
3941 						break;
3942 					}
3943 				}
3944 			}
3945 		}
3946 		printf("===========================================\nTotal Techtrees: " MG_SIZE_T_SPECIFIER "\n",results.size());
3947 
3948 		return_value = 0;
3949 	}
3950 
3951 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_SCENARIOS]) == true) {
3952 		int foundParamIndIndex = -1;
3953 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_SCENARIOS]) + string("="),&foundParamIndIndex);
3954 		if(foundParamIndIndex < 0) {
3955 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_SCENARIOS]),&foundParamIndIndex);
3956 		}
3957 
3958 		Config &config = Config::getInstance();
3959 	  	vector<string> pathList = config.getPathListForType(ptScenarios,"");
3960 	  	vector<string> results;
3961 	  	findDirs(pathList, results);
3962 
3963 		string paramValue = argv[foundParamIndIndex];
3964 		vector<string> paramPartTokens;
3965 		Tokenize(paramValue,paramPartTokens,"=");
3966 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
3967 			string itemNameFilter = paramPartTokens[1];
3968 			printf("Using filter for scenarios list [%s]\n",itemNameFilter.c_str());
3969 
3970 			vector<string> filtered;
3971 			for(unsigned int i = 0; i < results.size(); ++i) {
3972 				string name = results[i];
3973 				if(itemNameFilter.find("*") != itemNameFilter.npos) {
3974 					if(StartsWith(name, itemNameFilter.substr(0,itemNameFilter.find("*"))) == true) {
3975 						filtered.push_back(name);
3976 					}
3977 				}
3978 				else if(name == itemNameFilter) {
3979 					filtered.push_back(name);
3980 				}
3981 			}
3982 			results = filtered;
3983 		}
3984 
3985 		printf("Scenarios found:\n===========================================\n");
3986 		for(unsigned int i = 0; i < results.size(); ++i) {
3987 			string name = results[i];
3988 			printf("%s\n",name.c_str());
3989 		}
3990 		printf("===========================================\nTotal: " MG_SIZE_T_SPECIFIER "\n",results.size());
3991 
3992 		return_value = 0;
3993 	}
3994 
3995 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TILESETS]) == true) {
3996 		int foundParamIndIndex = -1;
3997 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_TILESETS]) + string("="),&foundParamIndIndex);
3998 		if(foundParamIndIndex < 0) {
3999 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_TILESETS]),&foundParamIndIndex);
4000 		}
4001 
4002 		Config &config = Config::getInstance();
4003 	  	vector<string> pathList = config.getPathListForType(ptTilesets,"");
4004 	  	vector<string> results;
4005 	  	findDirs(pathList, results);
4006 
4007 		string paramValue = argv[foundParamIndIndex];
4008 		vector<string> paramPartTokens;
4009 		Tokenize(paramValue,paramPartTokens,"=");
4010 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4011 			string itemNameFilter = paramPartTokens[1];
4012 			printf("Using filter for tilesets list [%s]\n",itemNameFilter.c_str());
4013 
4014 			vector<string> filtered;
4015 			for(unsigned int i = 0; i < results.size(); ++i) {
4016 				string name = results[i];
4017 				if(itemNameFilter.find("*") != itemNameFilter.npos) {
4018 					if(StartsWith(name, itemNameFilter.substr(0,itemNameFilter.find("*"))) == true) {
4019 						filtered.push_back(name);
4020 					}
4021 				}
4022 				else if(name == itemNameFilter) {
4023 					filtered.push_back(name);
4024 				}
4025 			}
4026 			results = filtered;
4027 		}
4028 
4029 		printf("Tilesets found:\n===========================================\n");
4030 		for(unsigned int i = 0; i < results.size(); ++i) {
4031 			string name = results[i];
4032 
4033 			for(unsigned int j = 0; j < pathList.size(); ++j) {
4034 				string tilesetPath = pathList[j];
4035 				if(tilesetPath != "") {
4036 					endPathWithSlash(tilesetPath);
4037 				}
4038 				if(fileExists(tilesetPath + name + "/" + name + ".xml") == true) {
4039 					string downloadArchive = tilesetPath + name + ".7z";
4040 					if(fileExists(downloadArchive) == true) {
4041 						off_t fileSize = getFileSize(downloadArchive);
4042 						// convert to MB
4043 						double megaBytes = ((double)fileSize / 1048576.0);
4044 						printf("%s [download archive %.2fMB]\n",name.c_str(),megaBytes);
4045 					}
4046 					else {
4047 						printf("%s\n",name.c_str());
4048 					}
4049 
4050 					break;
4051 				}
4052 			}
4053 		}
4054 		printf("===========================================\nTotal: " MG_SIZE_T_SPECIFIER "\n",results.size());
4055 
4056 		return_value = 0;
4057 	}
4058 
4059 	else if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TUTORIALS]) == true) {
4060 		int foundParamIndIndex = -1;
4061 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_TUTORIALS]) + string("="),&foundParamIndIndex);
4062 		if(foundParamIndIndex < 0) {
4063 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LIST_TUTORIALS]),&foundParamIndIndex);
4064 		}
4065 
4066 		Config &config = Config::getInstance();
4067 	  	vector<string> pathList = config.getPathListForType(ptTutorials,"");
4068 	  	vector<string> results;
4069 	  	findDirs(pathList, results);
4070 
4071 		string paramValue = argv[foundParamIndIndex];
4072 		vector<string> paramPartTokens;
4073 		Tokenize(paramValue,paramPartTokens,"=");
4074 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4075 			string itemNameFilter = paramPartTokens[1];
4076 			printf("Using filter for tutorials list [%s]\n",itemNameFilter.c_str());
4077 
4078 			vector<string> filtered;
4079 			for(unsigned int i = 0; i < results.size(); ++i) {
4080 				string name = results[i];
4081 				if(itemNameFilter.find("*") != itemNameFilter.npos) {
4082 					if(StartsWith(name, itemNameFilter.substr(0,itemNameFilter.find("*"))) == true) {
4083 						filtered.push_back(name);
4084 					}
4085 				}
4086 				else if(name == itemNameFilter) {
4087 					filtered.push_back(name);
4088 				}
4089 			}
4090 			results = filtered;
4091 		}
4092 
4093 		printf("Tutorials found:\n===========================================\n");
4094 		for(unsigned int i = 0; i < results.size(); ++i) {
4095 			string name = results[i];
4096 
4097 			for(unsigned int j = 0; j < pathList.size(); ++j) {
4098 				string tutorialsPath = pathList[j];
4099 				if(tutorialsPath != "") {
4100 					endPathWithSlash(tutorialsPath);
4101 				}
4102 				if(fileExists(tutorialsPath + name + "/" + name + ".xml") == true) {
4103 					string downloadArchive = tutorialsPath + name + ".7z";
4104 					if(fileExists(downloadArchive) == true) {
4105 						off_t fileSize = getFileSize(downloadArchive);
4106 						// convert to MB
4107 						double megaBytes = ((double)fileSize / 1048576.0);
4108 						printf("%s [download archive %.2fMB]\n",name.c_str(),megaBytes);
4109 					}
4110 					else {
4111 						printf("%s\n",name.c_str());
4112 					}
4113 
4114 					break;
4115 				}
4116 			}
4117 		}
4118 		printf("===========================================\nTotal: " MG_SIZE_T_SPECIFIER "\n",results.size());
4119 
4120 		return_value = 0;
4121 	}
4122 
4123 	return return_value;
4124 }
4125 
glestMain(int argc,char ** argv)4126 int glestMain(int argc, char** argv) {
4127 #ifdef SL_LEAK_DUMP
4128 	//AllocInfo::set_application_binary(executable_path(argv[0],true));
4129 	string &app = AllocInfo::get_application_binary();
4130 	app = executable_path(argv[0],true);
4131 	//want_full_leak_stacktrace = true;
4132 	//want_full_leak_stacktrace_line_numbers = true;
4133 
4134 #endif
4135 
4136 	Thread::setMainThreadId();
4137 //	printf("START ALLOC char 200\n");
4138 	//char *ptr = new char[200];
4139 //	printf("END ALLOC char 200\n");
4140 //	return -1;
4141     SystemFlags::VERBOSE_MODE_ENABLED  = false;
4142     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VERBOSE_MODE]) == true) {
4143         SystemFlags::VERBOSE_MODE_ENABLED  = true;
4144         Thread::setEnableVerboseMode(true);
4145         //LuaScript::setDebugModeEnabled(true);
4146     }
4147     // DEbug testing threads
4148     //Thread::setEnableVerboseMode(true);
4149 
4150 	PlatformExceptionHandler::application_binary= executable_path(argv[0],true);
4151 	mg_app_name = GameConstants::application_name;
4152 	mailStringSupport = mailString;
4153     SystemFlags::ENABLE_THREADED_LOGGING = false;
4154     disableBacktrace = false;
4155 	bool foundInvalidArgs = false;
4156 	preCacheThread=NULL;
4157 
4158 	Properties::setApplicationPath(executable_path(argv[0]));
4159 	Properties::setApplicationDataPath(executable_path(argv[0]));
4160 	Properties::setGameVersion(glestVersionString);
4161 
4162     ServerSocket::setMaxPlayerCount(GameConstants::maxPlayers);
4163 
4164     if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DISABLE_BACKTRACE]) == true) {
4165         disableBacktrace = true;
4166     }
4167     PlatformExceptionHandler::disableBacktrace= disableBacktrace;
4168 
4169 #if defined(CUSTOM_DATA_INSTALL_PATH)
4170     if(SystemFlags::VERBOSE_MODE_ENABLED) printf("\n\nCUSTOM_DATA_INSTALL_PATH = [%s]\n\n",formatPath(TOSTRING(CUSTOM_DATA_INSTALL_PATH)).c_str());
4171 #endif
4172 
4173 	const int knownArgCount = sizeof(GAME_ARGS) / sizeof(GAME_ARGS[0]);
4174 	for(int idx = 1; idx < argc; ++idx) {
4175 		if( hasCommandArgument(knownArgCount, (char **)&GAME_ARGS[0], argv[idx], NULL, 0, true) == false) {
4176 			foundInvalidArgs = true;
4177 			printf("\nInvalid argument: %s",argv[idx]);
4178 		}
4179 	}
4180 
4181 	if( hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_HELP]) == true ||
4182 		foundInvalidArgs == true) {
4183 
4184 		printParameterHelp(argv[0],foundInvalidArgs);
4185 		return 2;
4186 	}
4187 
4188 
4189 
4190 
4191     if( hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE])) == true) {
4192     	//isMasterServerModeEnabled = true;
4193     	//Window::setMasterserverMode(isMasterServerModeEnabled);
4194     	GlobalStaticFlags::setIsNonGraphicalModeEnabled(true);
4195 
4196     	int foundParamIndIndex = -1;
4197 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE]) + string("="),&foundParamIndIndex);
4198 		if(foundParamIndIndex < 0) {
4199 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE]),&foundParamIndIndex);
4200 		}
4201 		string paramValue = argv[foundParamIndIndex];
4202 		vector<string> paramPartTokens;
4203 		Tokenize(paramValue,paramPartTokens,"=");
4204 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4205 			string headless_command_list = paramPartTokens[1];
4206 
4207 			vector<string> paramHeadlessCommandList;
4208 			Tokenize(headless_command_list,paramHeadlessCommandList,",");
4209 
4210 			for(unsigned int i = 0; i < paramHeadlessCommandList.size(); ++i) {
4211 				string headless_command = paramHeadlessCommandList[i];
4212 				if(headless_command == "exit") {
4213 					printf("Forcing quit after game has completed [%s]\n",headless_command.c_str());
4214 					Program::setWantShutdownApplicationAfterGame(true);
4215 				}
4216 				else if(headless_command == "vps") {
4217 					printf("Disabled reading from console [%s]\n",headless_command.c_str());
4218 					disableheadless_console = true;
4219 				}
4220 				else if(headless_command == "lan") {
4221 					printf("Forcing local LAN mode [%s]\n",headless_command.c_str());
4222 					GlobalStaticFlags::setFlag(gsft_lan_mode);
4223 				}
4224 			}
4225 		}
4226     }
4227 
4228 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SERVER_TITLE]) == true) {
4229 		int foundParamIndIndex = -1;
4230 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SERVER_TITLE]) + string("="),&foundParamIndIndex);
4231 		if(foundParamIndIndex < 0) {
4232 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SERVER_TITLE]),&foundParamIndIndex);
4233 		}
4234 		string paramValue = argv[foundParamIndIndex];
4235 		vector<string> paramPartTokens;
4236 		Tokenize(paramValue,paramPartTokens,"=");
4237 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4238 			Config &config = Config::getInstance();
4239 			string serverTitle = paramPartTokens[1];
4240 			printf("Forcing serverTitle[%s]\n",serverTitle.c_str());
4241 
4242 			config.setString("ServerTitle",serverTitle,true);
4243 		}
4244         else {
4245             printf("\nInvalid missing server title specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4246 
4247             return 1;
4248         }
4249 	}
4250 
4251 
4252 
4253 //#ifdef WIN32
4254 	//SocketManager winSockManager;
4255 //#endif
4256 
4257     bool haveSpecialOutputCommandLineOption = false;
4258 
4259 	if( hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_OPENGL_INFO]) 			== true ||
4260 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SDL_INFO]) 			== true ||
4261 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LUA_INFO]) 			== true ||
4262         hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CURL_INFO]) 			== true ||
4263         hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_XERCES_INFO]) 			== true ||
4264 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VERSION]) 				== true ||
4265         hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_INI_SETTINGS])    == true ||
4266 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TECHTREES]) 	== true ||
4267 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]) 	== true ||
4268 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_SCENARIO]) 	== true ||
4269 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TILESET]) 	== true ||
4270 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_TRANSLATE_TECHTREES]) 	== true ||
4271 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_MAPS]) 			== true ||
4272 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TECHTRESS]) 		== true ||
4273 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_SCENARIOS]) 		== true ||
4274 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TILESETS]) 		== true ||
4275 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TUTORIALS]) 		== true ||
4276 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]) == true) {
4277 		haveSpecialOutputCommandLineOption = true;
4278 	}
4279 
4280 	if( haveSpecialOutputCommandLineOption == false ||
4281 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VERSION]) == true) {
4282 		printf("%s %s",extractFileFromDirectoryPath(argv[0]).c_str(),getNetworkPlatformFreeVersionString().c_str());
4283 //		printf("\nCompiled using: %s on: %s platform: %s endianness: %s",getCompilerNameString().c_str(),getCompileDateTime().c_str(),getPlatformNameString().c_str(),(::Shared::PlatformByteOrder::isBigEndian() == true ? "big" : "little"));
4284 		printf("\nCompiled using: %s platform: %s endianness: %s",getCompilerNameString().c_str(),getPlatformNameString().c_str(),(::Shared::PlatformByteOrder::isBigEndian() == true ? "big" : "little"));
4285 
4286 //		printf("\n\nData type sizes int8 = " MG_SIZE_T_SPECIFIER " int16 = " MG_SIZE_T_SPECIFIER " int32 = " MG_SIZE_T_SPECIFIER " int64 = " MG_SIZE_T_SPECIFIER "\n\n",sizeof(int8),sizeof(int16),sizeof(int32),sizeof(int64));
4287 //
4288 //		Config::getInstance().setBool("DebugNetworkPackets",true,true);
4289 //		NetworkMessageIntro data(424336, "mg_version_x","player_x", 3, nmgstOk,444444, 555555, "english");
4290 //		unsigned char *buf = data.packMessage();
4291 //		printf("\nSend packet size = %u\n%s\n",data.getPackedSize(),data.toString().c_str());
4292 //		data.dump_packet("Send data", buf, data.getPackedSize());
4293 //		//delete [] buf;
4294 //
4295 //		NetworkMessageIntro data2;
4296 //		data2.unpackMessage(buf);
4297 //		printf("\nReceive packet size = %u\n%s\n",data2.getPackedSize(),data2.toString().c_str());
4298 //		data2.dump_packet("nReceive data", buf, data2.getPackedSize());
4299 //		delete [] buf;
4300 
4301 //		SwitchSetupRequest data("factionname", 3,-1,2,"softcoder",10, 11,"eng");
4302 //
4303 //		unsigned char *buf = data.packMessage();
4304 //		printf("\nSend packet size = %u\n%s\nTeam = %d faction [%s] currentFactionIndex = %d toFactionIndex = %d [%s] [%s] %d %d\n",data.getPackedSize(),buf,data.getToTeam(),data.getSelectedFactionName().c_str(),data.getCurrentFactionIndex(),data.getToFactionIndex(),data.getNetworkPlayerLanguage().c_str(),data.getNetworkPlayerName().c_str(),data.getNetworkPlayerStatus(),data.getSwitchFlags());
4305 //		//delete [] buf;
4306 //
4307 //		data.unpackMessage(buf);
4308 //		printf("\nGot packet size = %u\n%s\nTeam = %d faction [%s] currentFactionIndex = %d toFactionIndex = %d [%s] [%s] %d %d\n",data.getPackedSize(),buf,data.getToTeam(),data.getSelectedFactionName().c_str(),data.getCurrentFactionIndex(),data.getToFactionIndex(),data.getNetworkPlayerLanguage().c_str(),data.getNetworkPlayerName().c_str(),data.getNetworkPlayerStatus(),data.getSwitchFlags());
4309 //		delete [] buf;
4310 
4311 //		int8 a = 1;
4312 //		uint8 b = 2;
4313 //		int16 c = 3;
4314 //		uint16 d = 4;
4315 //		int32 e = 5;
4316 //		uint32 f = 6;
4317 //
4318 //		printf("\nPack test #1: [%d][%u][%d][%u][%d][%u]\n,",a,b,c,d,e,f);
4319 //
4320 //		unsigned char *buf = new unsigned char[100];
4321 //		unsigned int packedsize = pack(buf, "cChHlL",
4322 //				a,
4323 //				b,
4324 //				c,
4325 //				d,
4326 //				e,
4327 //				f);
4328 //
4329 //		printf("Pack test #2: [%u][%s]\n,",packedsize,buf);
4330 //
4331 //		int8 a1 = 0;
4332 //		uint8 b1 = 0;
4333 //		int16 c1 = 0;
4334 //		uint16 d1 = 0;
4335 //		int32 e1 = 0;
4336 //		uint32 f1 = 0;
4337 //
4338 //		unpack(buf, "cChHlL",
4339 //				&a1,
4340 //				&b1,
4341 //				&c1,
4342 //				&d1,
4343 //				&e1,
4344 //				&f1);
4345 //
4346 //		printf("UnPack test #3: [%d][%u][%d][%u][%d][%u]\n,",a1,b1,c1,d1,e1,f1);
4347 
4348 		if(SystemFlags::VERBOSE_MODE_ENABLED == true) {
4349 			int8 testVar = 111;
4350 			printf("\nEndian value = %d",testVar);
4351 			testVar = ::Shared::PlatformByteOrder::toCommonEndian(testVar);
4352 			printf("\nEndian to common value = %d",testVar);
4353 			testVar = ::Shared::PlatformByteOrder::fromCommonEndian(testVar);
4354 			printf("\nEndian from common value = %d",testVar);
4355 
4356 			printf("\nint8 sizeof = " MG_SIZE_T_SPECIFIER "",sizeof(int8));
4357 			printf("\nSwitchSetupRequest sizeof = " MG_SIZE_T_SPECIFIER "",SwitchSetupRequest().getDataSize());
4358 		}
4359 
4360 		printf("\nGIT: [%s]",getGITRevisionString().c_str());
4361 
4362 #ifdef USE_STREFLOP
4363 
4364 #if defined(STREFLOP_SSE)
4365 		const char *instruction_set = "[SSE]";
4366 #elif defined(STREFLOP_X87)
4367 		const char *instruction_set = "[X87]";
4368 #elif defined(STREFLOP_SOFT)
4369 		const char *instruction_set = "[SOFTFLOAT]";
4370 #else
4371 		const char *instruction_set = "[none]";
4372 #endif
4373 
4374 #if defined(STREFLOP_NO_DENORMALS)
4375 		const char *denormals = "[no-denormals]";
4376 #else
4377 		const char *denormals = "[denormals]";
4378 #endif
4379 
4380 		printf(" - using STREFLOP %s - %s\n",instruction_set,denormals);
4381 
4382 #else
4383 		printf("\n");
4384 #endif
4385 	}
4386 
4387     setGameVersion(glestVersionString);
4388     setGameGITVersion(getRAWGITRevisionString());
4389 
4390 #ifdef WIN32
4391 	CheckPacketThrottling();
4392 #endif
4393 
4394 	if( hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_OPENGL_INFO]) 			== true ||
4395 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SDL_INFO]) 			== true ||
4396 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LUA_INFO]) 			== true ||
4397         hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CURL_INFO]) 			== true ||
4398         hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_XERCES_INFO]) 			== true ||
4399 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VERSION]) 				== true ||
4400         hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_INI_SETTINGS])    == true ||
4401 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TECHTREES]) 	== true ||
4402 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]) 	== true ||
4403 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_SCENARIO]) 	== true ||
4404 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TILESET]) 	== true ||
4405 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_TRANSLATE_TECHTREES]) 	== true ||
4406 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_MAPS]) 			== true ||
4407 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TECHTRESS]) 		== true ||
4408 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_SCENARIOS]) 		== true ||
4409 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TILESETS]) 		== true ||
4410 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TUTORIALS]) 		== true ||
4411 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]) == true) {
4412 		VideoPlayer::setDisabled(true);
4413 	}
4414 
4415 	//throw megaglest_runtime_error("Test!");
4416 
4417 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SDL_INFO]) == true) {
4418 		SDL_version ver;
4419 
4420         // Prints the compile time version
4421         SDL_VERSION(&ver);
4422 		print_SDL_version("SDL compile-time version", &ver);
4423 
4424         // Prints the run-time version
4425 		SDL_GetVersion(&ver);
4426         print_SDL_version("SDL runtime version", &ver);
4427         //const SDL_VideoInfo *vidInfo = SDL_GetVideoInfo();
4428         //printf("Video card Memory: %u\n",vidInfo->video_mem);
4429 	}
4430 
4431 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LUA_INFO]) == true) {
4432 		printf("LUA version: %s\n", LUA_RELEASE);
4433 	}
4434 
4435 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CURL_INFO]) == true) {
4436 	    curl_version_info_data *curlVersion= curl_version_info(CURLVERSION_NOW);
4437 		printf("CURL version: %s [%s] SSL enabled: %d\n", curlVersion->version,(curlVersion->ssl_version != NULL ? curlVersion->ssl_version : ""),((curlVersion->features & CURL_VERSION_SSL) == CURL_VERSION_SSL ? true : false));
4438 		if(curlVersion->protocols != NULL && curlVersion->protocols[0] != NULL) {
4439 			printf("protocols: ");
4440 			for(unsigned int i = 0; curlVersion->protocols != NULL && curlVersion->protocols[i] != NULL; ++i) {
4441 					printf("%s ", curlVersion->protocols[i]);
4442 					if(i > 0 && i % 10 == 0) {
4443 						printf("\n           ");
4444 					}
4445 			}
4446 			printf("\n");
4447 		}
4448 	}
4449 
4450 #if defined(WANT_XERCES)
4451 
4452 	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_XERCES_INFO]) == true) {
4453 		printf("XERCES version: %s\n", XERCES_FULLVERSIONDOT);
4454 	}
4455 
4456 #endif
4457 
4458 	if( (hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VERSION]) 		  == true ||
4459 		 hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SDL_INFO]) 		  == true ||
4460 		 hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LUA_INFO]) 		  == true ||
4461          hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CURL_INFO]) 		  == true ||
4462          hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_XERCES_INFO])       == true) &&
4463 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_OPENGL_INFO]) 		  == false &&
4464 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TECHTREES]) == false &&
4465 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS])  == false &&
4466 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_SCENARIO])  == false &&
4467 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TILESET])   == false &&
4468 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_TRANSLATE_TECHTREES]) 	== false &&
4469 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_MAPS]) 		== false &&
4470 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TECHTRESS]) 	== false &&
4471 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_SCENARIOS]) 	== false &&
4472 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TILESETS]) 	== false &&
4473 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TUTORIALS]) 	== false &&
4474 		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]) == false) {
4475 		return 0;
4476 	}
4477 
4478 	if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MOD])) == true) {
4479 
4480 		int foundParamIndIndex = -1;
4481 		hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MOD]) + string("="),&foundParamIndIndex);
4482 		if(foundParamIndIndex < 0) {
4483 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MOD]),&foundParamIndIndex);
4484 		}
4485 		string scenarioName = argv[foundParamIndIndex];
4486 		vector<string> paramPartTokens;
4487 		Tokenize(scenarioName,paramPartTokens,"=");
4488 		if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4489 			string autoloadModName = paramPartTokens[1];
4490 			if(Properties::applyTagsToValue(autoloadModName) == true) {
4491 				if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Property key [%s] now has value [%s]\n",Config::ACTIVE_MOD_PROPERTY_NAME,autoloadModName.c_str());
4492 			}
4493 
4494 			Config::setCustomRuntimeProperty(Config::ACTIVE_MOD_PROPERTY_NAME,autoloadModName);
4495 
4496 			printf("Setting mod active [%s]\n",autoloadModName.c_str());
4497 		}
4498 		else {
4499 			printf("\nInvalid mod pathname specified on commandline [%s] mod [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4500 			printParameterHelp(argv[0],foundInvalidArgs);
4501 			return 1;
4502 		}
4503 	}
4504 
4505 	SystemFlags::init(haveSpecialOutputCommandLineOption);
4506 	//SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled  = true;
4507 	//SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled = true;
4508 
4509 	MainWindow *mainWindow= NULL;
4510 	Program *program= NULL;
4511 	ExceptionHandler exceptionHandler;
4512 	exceptionHandler.install( getCrashDumpFileName() );
4513 
4514 	int shutdownFadeSoundMilliseconds = 1000;
4515 	Chrono chronoshutdownFadeSound;
4516 	SimpleTaskThread *soundThreadManager = NULL;
4517 
4518 	try {
4519         // Setup paths to game items (like data, logs, ini etc)
4520         int setupResult = setupGameItemPaths(argc, argv, NULL);
4521         if(setupResult != 0) {
4522             return setupResult;
4523         }
4524 
4525 		// Attempt to read ini files
4526 		Config &config = Config::getInstance();
4527 		setupGameItemPaths(argc, argv, &config);
4528 
4529 		if(config.getString("PlayerId","") == "") {
4530 			char  uuid_str[38];
4531 			get_uuid_string(uuid_str,sizeof(uuid_str));
4532 
4533 			config.setString("PlayerId",uuid_str);
4534 			config.save();
4535 		}
4536 		//printf("Players UUID: [%s]\n",config.getString("PlayerId","").c_str());
4537 
4538 		if(config.getBool("DisableLuaSandbox","false") == true) {
4539 			LuaScript::setDisableSandbox(true);
4540 		}
4541 
4542 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DEBUG_NETWORK_PACKETS]) == true) {
4543 			printf("*NOTE: debugging network packets.\n");
4544 			config.setBool("DebugNetworkPackets",true,true);
4545 		}
4546 
4547 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DEBUG_NETWORK_PACKET_SIZES]) == true) {
4548 			printf("*NOTE: debugging network packet SIZES.\n");
4549 			config.setBool("DebugNetworkPacketSizes",true,true);
4550 		}
4551 
4552 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DEBUG_NETWORK_PACKET_STATS]) == true) {
4553 			printf("*NOTE: debugging network packet STATISTICS.\n");
4554 			config.setBool("DebugNetworkPacketStats",true,true);
4555 		}
4556 
4557 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_ENABLE_NEW_PROTOCOL]) == true) {
4558 			printf("*NOTE: enabling new newtork protocol.\n");
4559 			NetworkMessage::useOldProtocol = false;
4560 		}
4561 
4562 		Socket::setBroadCastPort(config.getInt("BroadcastPort",intToStr(Socket::getBroadCastPort()).c_str()));
4563 
4564 		Socket::disableNagle = config.getBool("DisableNagle","false");
4565 		if(Socket::disableNagle) {
4566 			printf("*WARNING users wants to disable the socket nagle algorithm.\n");
4567 		}
4568 		Socket::DEFAULT_SOCKET_SENDBUF_SIZE = config.getInt("DefaultSocketSendBufferSize",intToStr(Socket::DEFAULT_SOCKET_SENDBUF_SIZE).c_str());
4569 		if(Socket::DEFAULT_SOCKET_SENDBUF_SIZE >= 0) {
4570 			printf("*WARNING users wants to set default socket send buffer size to: %d\n",Socket::DEFAULT_SOCKET_SENDBUF_SIZE);
4571 		}
4572 		Socket::DEFAULT_SOCKET_RECVBUF_SIZE = config.getInt("DefaultSocketReceiveBufferSize",intToStr(Socket::DEFAULT_SOCKET_RECVBUF_SIZE).c_str());
4573 		if(Socket::DEFAULT_SOCKET_RECVBUF_SIZE >= 0) {
4574 			printf("*WARNING users wants to set default socket receive buffer size to: %d\n",Socket::DEFAULT_SOCKET_RECVBUF_SIZE);
4575 		}
4576 
4577 		shutdownFadeSoundMilliseconds = config.getInt("ShutdownFadeSoundMilliseconds",intToStr(shutdownFadeSoundMilliseconds).c_str());
4578 
4579 	    string userData = config.getString("UserData_Root","");
4580 		if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
4581 			userData = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey);
4582 		}
4583         if(userData != "") {
4584         	endPathWithSlash(userData);
4585         }
4586 
4587         string data_path_check = getGameReadWritePath(GameConstants::path_data_CacheLookupKey);
4588         string userDataPath_check = getGameCustomCoreDataPath(data_path_check, "");
4589         if(data_path_check == userDataPath_check) {
4590         	printf("****WARNING**** your game data path and user data path are the same.\nThis will likely create problems: %s\n",data_path_check.c_str());
4591         	throw megaglest_runtime_error("Regular and User data paths cannot have the same value [" + userDataPath_check + "]");
4592         }
4593 
4594 	    if(userData != "") {
4595 	        if(isdir(userData.c_str()) == false) {
4596 	        	createDirectoryPaths(userData);
4597 	        }
4598 	    }
4599 	    string crcCachePath = userData + "cache/";
4600         if(isdir(crcCachePath.c_str()) == false) {
4601         	createDirectoryPaths(crcCachePath);
4602         }
4603 	    setCRCCacheFilePath(crcCachePath);
4604 
4605 	    string savedGamePath = userData + "saved/";
4606         if(isdir(savedGamePath.c_str()) == false) {
4607         	createDirectoryPaths(savedGamePath);
4608         }
4609 
4610 	    string tempDataPath = userData + "temp/";
4611 	    tempDataLocation = tempDataPath;
4612         if(isdir(tempDataPath.c_str()) == true) {
4613         	removeFolder(tempDataPath);
4614         }
4615         createDirectoryPaths(tempDataPath);
4616 
4617         string binaryNameOld = Properties::getApplicationPath() + extractFileFromDirectoryPath(PlatformExceptionHandler::application_binary) + "__REMOVE";
4618         if(fileExists(binaryNameOld)) {
4619         	removeFile(binaryNameOld);
4620         }
4621 
4622         string netInterfaces = config.getString("NetworkInterfaces","");
4623         if(netInterfaces != "") {
4624         	//printf("Using network interfaces: %s\n",netInterfaces.c_str());
4625     		std::vector<std::string> intfList;
4626     		Tokenize(netInterfaces,intfList,",");
4627         	Socket::setIntfTypes(intfList);
4628         }
4629 
4630     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_PORTS]) == true) {
4631 			int foundParamIndIndex = -1;
4632 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_PORTS]) + string("="),&foundParamIndIndex);
4633 			if(foundParamIndIndex < 0) {
4634 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_PORTS]),&foundParamIndIndex);
4635 			}
4636 			string paramValue = argv[foundParamIndIndex];
4637 			vector<string> paramPartTokens;
4638 			Tokenize(paramValue,paramPartTokens,"=");
4639 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4640 				string portsToUse = paramPartTokens[1];
4641 
4642 				vector<string> paramPartPortsTokens;
4643 				Tokenize(portsToUse,paramPartPortsTokens,",");
4644 				if(paramPartPortsTokens.size() >= 2 && paramPartPortsTokens[1].length() > 0) {
4645 					int internalPort = strToInt(paramPartPortsTokens[0]);
4646 					int externalPort = strToInt(paramPartPortsTokens[1]);
4647 
4648 					printf("Forcing internal port# %d, external port# %d\n",internalPort,externalPort);
4649 
4650 					config.setInt("PortServer",internalPort,true);
4651 					config.setInt("PortExternal",externalPort,true);
4652 					config.setInt("FTPServerPort",internalPort+1,true);
4653 
4654 					if(paramPartPortsTokens.size() >= 3 && paramPartPortsTokens[2].length() > 0) {
4655 						int statusPort = strToInt(paramPartPortsTokens[2]);
4656 
4657 						printf("Forcing status port# %d\n",statusPort);
4658 
4659 						config.setInt("ServerAdminPort",statusPort,true);
4660 					}
4661 				}
4662 				else {
4663 		            printf("\nInvalid ports specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4664 		            return 1;
4665 				}
4666 			}
4667 	        else {
4668 	            printf("\nInvalid missing ports specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4669 	            return 1;
4670 	        }
4671     	}
4672 
4673         if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_STATUS])) == true) {
4674         	Ip ip("localhost");
4675         	int port = Config::getInstance().getInt("ServerAdminPort", intToStr(GameConstants::serverAdminPort).c_str());
4676         	ClientSocket clientSocket;
4677         	clientSocket.setBlock(false);
4678         	clientSocket.connect(ip, port);
4679         	if(clientSocket.isConnected() == true) {
4680         		clientSocket.setBlock(true);
4681 
4682         		char szBuf[8096]="";
4683         		clientSocket.receive(&szBuf[0],8095,false);
4684         		std::cout << szBuf << std::endl;
4685         	}
4686         	else {
4687         		std::cout << "Could not connect (possibly no clients connected) to host: " << ip.getString() << " port: " << port << std::endl;
4688         	}
4689 
4690         	return 0;
4691         }
4692 
4693 	    if( hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DISABLE_SOUND]) == true ||
4694 	    	hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE])) == true) {
4695 	    	config.setString("FactorySound","None",true);
4696 	    	if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE])) == true) {
4697 	    		//Logger::getInstance().setMasterserverMode(true);
4698 	    		//Model::setMasterserverMode(true);
4699 	    		//Shared::Sound::Sound::setMasterserverMode(true);
4700 	    	}
4701 	    }
4702 
4703 	    if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DISABLE_OPENGL_CAPS_CHECK]) == true ||
4704 	    		config.getBool("CheckGlCaps") == false) {
4705 	    	printf("**WARNING** disabling opengl capability checking...\n");
4706 	    	config.setBool("CheckGlCaps",false,true);
4707 	    }
4708 
4709 	    bool enableATIHacks = config.getBool("EnableATIHacks","false");
4710 	    if(enableATIHacks == true) {
4711 	    	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("**WARNING** Enabling ATI video card hacks\n");
4712 	    	TextureGl::setEnableATIHacks(enableATIHacks);
4713 	    }
4714 
4715        	Renderer::renderText3DEnabled = config.getBool("Enable3DFontRendering",intToStr(Renderer::renderText3DEnabled).c_str());
4716 
4717         if(config.getBool("EnableLegacyFonts","false") == true || hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_ENABLE_LEGACYFONTS]) == true) {
4718         	::Shared::Graphics::Font::forceLegacyFonts = true;
4719         	Renderer::renderText3DEnabled = false;
4720         	printf("**WARNING** Forcing Legacy Fonts Enabled\n");
4721         }
4722         else {
4723         	Renderer::renderText3DEnabled = config.getBool("Enable3DFontRendering",intToStr(Renderer::renderText3DEnabled).c_str());
4724         }
4725 
4726         if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_RESOLUTION]) == true) {
4727 			int foundParamIndIndex = -1;
4728 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_RESOLUTION]) + string("="),&foundParamIndIndex);
4729 			if(foundParamIndIndex < 0) {
4730 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_RESOLUTION]),&foundParamIndIndex);
4731 			}
4732 			string paramValue = argv[foundParamIndIndex];
4733 			vector<string> paramPartTokens;
4734 			Tokenize(paramValue,paramPartTokens,"=");
4735 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4736 				string settings = paramPartTokens[1];
4737 				printf("Forcing resolution [%s]\n",settings.c_str());
4738 
4739 				paramPartTokens.clear();
4740 				Tokenize(settings,paramPartTokens,"x");
4741 				if(paramPartTokens.size() >= 2) {
4742 					int newScreenWidth 	= strToInt(paramPartTokens[0]);
4743 					config.setInt("ScreenWidth",newScreenWidth,true);
4744 
4745 					int newScreenHeight = strToInt(paramPartTokens[1]);
4746 					config.setInt("ScreenHeight",newScreenHeight,true);
4747 				}
4748 				else {
4749 		            printf("\nInvalid missing resolution settings specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4750 		            return 1;
4751 				}
4752 			}
4753 	        else {
4754 	            printf("\nInvalid missing resolution setting specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4755 	            return 1;
4756 	        }
4757         }
4758 
4759 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_COLORBITS]) == true) {
4760 			int foundParamIndIndex = -1;
4761 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_COLORBITS]) + string("="),&foundParamIndIndex);
4762 			if(foundParamIndIndex < 0) {
4763 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_COLORBITS]),&foundParamIndIndex);
4764 			}
4765 			string paramValue = argv[foundParamIndIndex];
4766 			vector<string> paramPartTokens;
4767 			Tokenize(paramValue,paramPartTokens,"=");
4768 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4769 				string settings = paramPartTokens[1];
4770 				printf("Forcing colorbits [%s]\n",settings.c_str());
4771 
4772 				int newColorBits = strToInt(settings);
4773 				config.setInt("ColorBits",newColorBits,true);
4774 			}
4775 			else {
4776 				printf("\nInvalid missing colorbits settings specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4777 				return 1;
4778 			}
4779 		}
4780 
4781 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_DEPTHBITS]) == true) {
4782 			int foundParamIndIndex = -1;
4783 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_DEPTHBITS]) + string("="),&foundParamIndIndex);
4784 			if(foundParamIndIndex < 0) {
4785 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_DEPTHBITS]),&foundParamIndIndex);
4786 			}
4787 			string paramValue = argv[foundParamIndIndex];
4788 			vector<string> paramPartTokens;
4789 			Tokenize(paramValue,paramPartTokens,"=");
4790 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4791 				string settings = paramPartTokens[1];
4792 				printf("Forcing depthbits [%s]\n",settings.c_str());
4793 
4794 				int newDepthBits = strToInt(settings);
4795 				config.setInt("DepthBits",newDepthBits,true);
4796 			}
4797 			else {
4798 				printf("\nInvalid missing depthbits setting specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4799 				return 1;
4800 			}
4801 		}
4802 
4803 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_FULLSCREEN]) == true) {
4804 			int foundParamIndIndex = -1;
4805 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_FULLSCREEN]) + string("="),&foundParamIndIndex);
4806 			if(foundParamIndIndex < 0) {
4807 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_FULLSCREEN]),&foundParamIndIndex);
4808 			}
4809 			string paramValue = argv[foundParamIndIndex];
4810 			vector<string> paramPartTokens;
4811 			Tokenize(paramValue,paramPartTokens,"=");
4812 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4813 				string settings = paramPartTokens[1];
4814 				printf("Forcing fullscreen [%s]\n",settings.c_str());
4815 
4816 				bool newFullScreenMode = strToBool(settings);
4817 				config.setBool("Windowed",!newFullScreenMode,true);
4818 			}
4819 			else {
4820 				printf("\nInvalid missing fullscreen setting specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4821 				return 1;
4822 			}
4823 		}
4824 
4825 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SET_GAMMA]) == true) {
4826 			int foundParamIndIndex = -1;
4827 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SET_GAMMA]) + string("="),&foundParamIndIndex);
4828 			if(foundParamIndIndex < 0) {
4829 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_SET_GAMMA]),&foundParamIndIndex);
4830 			}
4831 			string paramValue = argv[foundParamIndIndex];
4832 			vector<string> paramPartTokens;
4833 			Tokenize(paramValue,paramPartTokens,"=");
4834 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4835 				string settings = paramPartTokens[1];
4836 				printf("Forcing gamma [%s]\n",settings.c_str());
4837 
4838 				float newGammaValue = strToFloat(settings);
4839 				config.setFloat("GammaValue",newGammaValue,true);
4840 			}
4841 			else {
4842 				printf("\nInvalid missing gamma setting specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4843 				return 1;
4844 			}
4845 		}
4846 
4847 
4848 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DISABLE_VIDEOS]) == true) {
4849 			VideoPlayer::setDisabled(true);
4850 		}
4851 		else if(config.getBool("EnableVideos","true") == false) {
4852 			VideoPlayer::setDisabled(true);
4853 		}
4854 
4855         // Set some statics based on ini entries
4856 		SystemFlags::ENABLE_THREADED_LOGGING = config.getBool("ThreadedLogging","true");
4857 		FontGl::setDefault_fontType(config.getString("DefaultFont",FontGl::getDefault_fontType().c_str()));
4858 		UPNP_Tools::isUPNP = !config.getBool("DisableUPNP","false");
4859 		Texture::useTextureCompression = config.getBool("EnableTextureCompression","false");
4860 
4861 		// 256 for English
4862 		// 30000 for Chinese
4863 		::Shared::Graphics::Font::charCount    		= config.getInt("FONT_CHARCOUNT",intToStr(::Shared::Graphics::Font::charCount).c_str());
4864 		::Shared::Graphics::Font::fontTypeName 		= config.getString("FONT_TYPENAME",::Shared::Graphics::Font::fontTypeName.c_str());
4865 		::Shared::Graphics::Font::fontIsMultibyte 	= config.getBool("FONT_MULTIBYTE",intToStr(::Shared::Graphics::Font::fontIsMultibyte).c_str());
4866 		::Shared::Graphics::Font::fontIsRightToLeft	= config.getBool("FONT_RIGHTTOLEFT",intToStr(::Shared::Graphics::Font::fontIsRightToLeft).c_str());
4867 		::Shared::Graphics::Font::baseSize			= config.getInt("FONT_BASE_SIZE",intToStr(::Shared::Graphics::Font::baseSize).c_str());
4868 		::Shared::Graphics::Font::scaleFontValue				= config.getFloat("FONT_SCALE_SIZE",floatToStr(::Shared::Graphics::Font::scaleFontValue).c_str());
4869 		::Shared::Graphics::Font::scaleFontValueCenterHFactor	= config.getFloat("FONT_SCALE_CENTERH_FACTOR",floatToStr(::Shared::Graphics::Font::scaleFontValueCenterHFactor).c_str());
4870 		::Shared::Graphics::Font::langHeightText				= config.getString("FONT_HEIGHT_TEXT",::Shared::Graphics::Font::langHeightText.c_str());
4871 		::Shared::Graphics::Font::fontSupportMixedRightToLeft = config.getBool("FONT_RIGHTTOLEFT_MIXED_SUPPORT",intToStr(::Shared::Graphics::Font::fontSupportMixedRightToLeft).c_str());
4872 
4873 		// Example values:
4874 		// DEFAULT_CHARSET (English) = 1
4875 		// GB2312_CHARSET (Chinese)  = 134
4876 		::Shared::Platform::PlatformContextGl::charSet = config.getInt("FONT_CHARSET",intToStr(::Shared::Platform::PlatformContextGl::charSet).c_str());
4877 		if(config.getBool("No2DMouseRendering","false") == false) {
4878 			showCursor(false);
4879 			//showWindowCursorState = false;
4880 		}
4881 		if(config.getInt("DEFAULT_HTTP_TIMEOUT",intToStr(SystemFlags::DEFAULT_HTTP_TIMEOUT).c_str()) >= 0) {
4882 			SystemFlags::DEFAULT_HTTP_TIMEOUT = config.getInt("DEFAULT_HTTP_TIMEOUT",intToStr(SystemFlags::DEFAULT_HTTP_TIMEOUT).c_str());
4883 		}
4884 
4885 		bool allowAltEnterFullscreenToggle = config.getBool("AllowAltEnterFullscreenToggle",boolToStr(::Shared::Platform::Window::getAllowAltEnterFullscreenToggle()).c_str());
4886 		::Shared::Platform::Window::setAllowAltEnterFullscreenToggle(allowAltEnterFullscreenToggle);
4887 
4888 		if(config.getBool("noTeamColors","false") == true) {
4889 			MeshCallbackTeamColor::noTeamColors = true;
4890 		}
4891 
4892 
4893 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LUA_DEBUG]) == true) {
4894 			printf("Forcing LUA debugging enabled!\n");
4895 			config.setBool("DebugLUA",true, true);
4896 		}
4897 
4898         // Setup debug logging etc
4899 		setupLogging(config, haveSpecialOutputCommandLineOption);
4900 
4901         SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Font::charCount = %d, Font::fontTypeName [%s] Shared::Platform::PlatformContextGl::charSet = %d, Font::fontIsMultibyte = %d, fontIsRightToLeft = %d\n",__FILE__,__FUNCTION__,__LINE__,::Shared::Graphics::Font::charCount,::Shared::Graphics::Font::fontTypeName.c_str(),::Shared::Platform::PlatformContextGl::charSet,::Shared::Graphics::Font::fontIsMultibyte, ::Shared::Graphics::Font::fontIsRightToLeft);
4902 
4903 		NetworkInterface::setDisplayMessageFunction(ExceptionHandler::DisplayMessage);
4904 		MenuStateMasterserver::setDisplayMessageFunction(ExceptionHandler::DisplayMessage);
4905 
4906 #ifdef USE_STREFLOP
4907 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s, STREFLOP enabled.\n",getNetworkVersionString().c_str());
4908 #else
4909 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"%s, STREFLOP NOT enabled.\n",getNetworkVersionString().c_str());
4910 #endif
4911 
4912 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
4913 		SystemFlags::OutputDebug(SystemFlags::debugUnitCommands,"START\n");
4914 		SystemFlags::OutputDebug(SystemFlags::debugPathFinder,"START\n");
4915 
4916         // Setup hotkeys from key ini files
4917 		Config &configKeys = Config::getInstance(
4918 				std::pair<ConfigType,ConfigType>(cfgMainKeys,cfgUserKeys),
4919 				std::pair<string,string>(Config::glestkeys_ini_filename,Config::glestuserkeys_ini_filename),
4920 				std::pair<bool,bool>(true,false),config.getString("GlestKeysIniPath",""));
4921 
4922         SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
4923 
4924         if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_INI_SETTINGS]) == true) {
4925             ShowINISettings(argc,argv,config,configKeys);
4926             return 0;
4927         }
4928 
4929         // Explicitly disable VBO's
4930         if(config.getBool("DisableVBO","false") == true || hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_DISABLE_VBO]) == true) {
4931         	setVBOSupported(false);
4932         	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("**INFO** Disabling VBOs\n");
4933         }
4934 
4935 	if(config.getBool("DisableVertexInterpolation","false") || hasCommandArgument(argc, argv, GAME_ARGS[GAME_ARG_DISABLE_VERTEX_INTERPOLATION])) {
4936 		InterpolationData::setEnableInterpolation(false);
4937 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("**INFO** Disabling Interpolation\n");
4938 	}
4939 
4940 
4941         if(config.getBool("EnableVSynch","false") == true) {
4942         	::Shared::Platform::Window::setTryVSynch(true);
4943         	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("**ENABLED OPENGL VSYNCH**\n");
4944         }
4945 
4946 		//float pingTime = Socket::getAveragePingMS("soft-haus.com");
4947 		//printf("Ping time = %f\n",pingTime);
4948 
4949         // Load the language strings
4950         Lang &lang= Lang::getInstance();
4951         string language = config.getString("Lang");
4952     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_LANGUAGE]) == true) {
4953 			int foundParamIndIndex = -1;
4954 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_LANGUAGE]) + string("="),&foundParamIndIndex);
4955 			if(foundParamIndIndex < 0) {
4956 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_LANGUAGE]),&foundParamIndIndex);
4957 			}
4958 			string paramValue = argv[foundParamIndIndex];
4959 			vector<string> paramPartTokens;
4960 			Tokenize(paramValue,paramPartTokens,"=");
4961 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
4962 				language = paramPartTokens[1];
4963 				printf("Forcing language [%s]\n",language.c_str());
4964 			}
4965 	        else {
4966 	            printf("\nInvalid missing language specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
4967 	            return 1;
4968 	        }
4969     	}
4970     	else {
4971 
4972 #ifdef _WIN32
4973 			int localeBufferSize = GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SISO639LANGNAME, NULL, 0);
4974 			wchar_t *sysLocale = new wchar_t[localeBufferSize];
4975 			GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SISO639LANGNAME, sysLocale,localeBufferSize);
4976 
4977 			//String langValue(sysLocale);
4978 			//const char *lang_locale = langValue.c_str();
4979 		    char langValue[1024]="";
4980 		    wcstombs(langValue,sysLocale, 1023);
4981 			const char *lang_locale = &langValue[0];
4982 
4983 			delete [] sysLocale;
4984 #else
4985 			const char *lang_locale = setlocale(LC_ALL,"");
4986 #endif
4987 
4988     		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Locale is: [%s]\n", lang_locale);
4989 
4990     		if(lang_locale != NULL && strlen(lang_locale) >= 2) {
4991     			if(config.getBool("AutoLocaleLanguageDetect","true") == true) {
4992     				language = lang_locale;
4993     				language = language.substr(0,2);
4994     				printf("Auto setting language [%s]\n",language.c_str());
4995 
4996     				config.setString("AutoLocaleLanguageDetect","false");
4997 					config.save();
4998     			}
4999     		}
5000     	}
5001 
5002     	if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTO_TEST])) == true ||
5003     		Config::getInstance().getBool("AutoTest","false") == true) {
5004     		printf("Running in auto test mode\n");
5005     	}
5006 		if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTO_TEST])) == true) {
5007 			Config::getInstance().setBool("AutoTest",true,true);
5008 
5009 			int foundParamIndIndex = -1;
5010 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTO_TEST]) + string("="),&foundParamIndIndex);
5011 			if(foundParamIndIndex < 0) {
5012 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTO_TEST]),&foundParamIndIndex);
5013 			}
5014 			string paramValue = argv[foundParamIndIndex];
5015 			vector<string> paramPartTokens;
5016 			Tokenize(paramValue,paramPartTokens,"=");
5017 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5018 				vector<string> paramPartTokens2;
5019 				Tokenize(paramPartTokens[1],paramPartTokens2,",");
5020 				if(paramPartTokens2.empty() == false && paramPartTokens2[0].length() > 0) {
5021 					string newMaxSeconds = paramPartTokens2[0];
5022 					time_t newTimeMaxSeconds = strToInt(newMaxSeconds);
5023 					AutoTest::setMaxGameTime(newTimeMaxSeconds);
5024 					printf("Forcing maximum game time to [%ld] seconds (%.2f minutes)\n",(long int)newTimeMaxSeconds,((double)newTimeMaxSeconds / 60.0));
5025 				}
5026 				if(paramPartTokens2.size() >= 3 && paramPartTokens2[2].length() > 0) {
5027 					string autoTestCmd = paramPartTokens2[2];
5028 					if(autoTestCmd == "exit") {
5029 						printf("Detected auto test command [%s], will exit after game.\n",autoTestCmd.c_str());
5030 
5031 						AutoTest::setWantExitGameWhenDone(true);
5032 					}
5033 					else {
5034 						printf("WARNING: Detected and UNKNOWN auto test command [%s].\n",autoTestCmd.c_str());
5035 					}
5036 				}
5037 
5038 				if(paramPartTokens2.size() >= 2 && paramPartTokens2[1].length() > 0) {
5039 					string newGameSettingsFileToLoad = paramPartTokens2[1];
5040 
5041 					printf("About to auto test using game settings file [%s]\n",newGameSettingsFileToLoad.c_str());
5042 					AutoTest::setLoadGameSettingsFile(newGameSettingsFileToLoad);
5043 				}
5044 			}
5045 		}
5046 
5047     	Renderer &renderer= Renderer::getInstance();
5048         lang.loadGameStrings(language,false, true);
5049 
5050         if(	lang.hasString("FONT_HEIGHT_TEXT")) {
5051         	::Shared::Graphics::Font::langHeightText = config.getString("FONT_HEIGHT_TEXT",::Shared::Graphics::Font::langHeightText.c_str());
5052         }
5053 
5054     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_FONT_BASESIZE]) == true) {
5055 			int foundParamIndIndex = -1;
5056 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_FONT_BASESIZE]) + string("="),&foundParamIndIndex);
5057 			if(foundParamIndIndex < 0) {
5058 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_FONT_BASESIZE]),&foundParamIndIndex);
5059 			}
5060 			string paramValue = argv[foundParamIndIndex];
5061 			vector<string> paramPartTokens;
5062 			Tokenize(paramValue,paramPartTokens,"=");
5063 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5064 				string newfontBaseSize = paramPartTokens[1];
5065 				printf("Forcing font base size[%s]\n",newfontBaseSize.c_str());
5066 
5067 				::Shared::Graphics::Font::baseSize = strToInt(newfontBaseSize);
5068 			}
5069 	        else {
5070 	            printf("\nInvalid missing font base size specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5071 
5072 	            return 1;
5073 	        }
5074     	}
5075 
5076         SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] Font::charCount = %d, Font::fontTypeName [%s] Shared::Platform::PlatformContextGl::charSet = %d, Font::fontIsMultibyte = %d, Font::fontIsRightToLeft = %d\n",__FILE__,__FUNCTION__,__LINE__,::Shared::Graphics::Font::charCount,::Shared::Graphics::Font::fontTypeName.c_str(),::Shared::Platform::PlatformContextGl::charSet,::Shared::Graphics::Font::fontIsMultibyte,::Shared::Graphics::Font::fontIsRightToLeft);
5077         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Using Font::charCount = %d, Font::fontTypeName [%s] Shared::Platform::PlatformContextGl::charSet = %d, Font::fontIsMultibyte = %d, Font::fontIsRightToLeft = %d\n",::Shared::Graphics::Font::charCount,::Shared::Graphics::Font::fontTypeName.c_str(),::Shared::Platform::PlatformContextGl::charSet,::Shared::Graphics::Font::fontIsMultibyte,::Shared::Graphics::Font::fontIsRightToLeft);
5078 
5079     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_USE_FONT]) == true) {
5080 			int foundParamIndIndex = -1;
5081 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_FONT]) + string("="),&foundParamIndIndex);
5082 			if(foundParamIndIndex < 0) {
5083 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_USE_FONT]),&foundParamIndIndex);
5084 			}
5085 			string paramValue = argv[foundParamIndIndex];
5086 			vector<string> paramPartTokens;
5087 			Tokenize(paramValue,paramPartTokens,"=");
5088 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5089 				string newfont = paramPartTokens[1];
5090 
5091 				Properties::applyTagsToValue(newfont);
5092 				printf("Forcing font [%s]\n",newfont.c_str());
5093 
5094 #if defined(WIN32)
5095 				string newEnvValue = "MEGAGLEST_FONT=" + newfont;
5096 				_putenv(newEnvValue.c_str());
5097 #else
5098         		setenv("MEGAGLEST_FONT",newfont.c_str(),1);
5099 #endif
5100 			}
5101 	        else {
5102 	            printf("\nInvalid missing font specified on commandline [%s] value [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5103 	            return 1;
5104 	        }
5105     	}
5106 
5107     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CREATE_DATA_ARCHIVES]) == true) {
5108     		return handleCreateDataArchivesCommand(argc, argv);
5109     	}
5110 
5111     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_MAP_CRC]) == true ||
5112     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_TILESET_CRC]) == true ||
5113     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_TECHTREE_CRC]) == true ||
5114     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_SCENARIO_CRC]) == true ||
5115     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SHOW_PATH_CRC]) == true) {
5116     		return handleShowCRCValuesCommand(argc, argv);
5117     	}
5118 
5119     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_MAPS]) == true ||
5120     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TECHTRESS]) == true ||
5121     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_SCENARIOS]) == true ||
5122     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TILESETS]) == true ||
5123     		hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_LIST_TUTORIALS]) == true) {
5124     		return handleListDataCommand(argc, argv);
5125 
5126     	}
5127 
5128 		program= new Program();
5129 		mainProgram = program;
5130 		renderer.setProgram(program);
5131 
5132 		if(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled == true) {
5133 			renderer.setAllowRenderUnitTitles(SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled);
5134 			SystemFlags::OutputDebug(SystemFlags::debugPathFinder,"In [%s::%s Line: %d] renderer.setAllowRenderUnitTitles = %d\n",__FILE__,__FUNCTION__,__LINE__,SystemFlags::getSystemSettingType(SystemFlags::debugPathFinder).enabled);
5135 		}
5136 		renderer.setAllowRenderUnitTitles(true);
5137 
5138 		string screenShotsPath = userData + GameConstants::folder_path_screenshots;
5139         if(isdir(screenShotsPath.c_str()) == false) {
5140         	createDirectoryPaths(screenShotsPath);
5141         }
5142 
5143         // Cache Player textures - START
5144         string data_path = getGameReadWritePath(GameConstants::path_data_CacheLookupKey);
5145 		std::map<int,Texture2D *> &crcPlayerTextureCache = CacheManager::getCachedItem< std::map<int,Texture2D *> >(GameConstants::playerTextureCacheLookupKey);
5146         for(int index = 0; index < GameConstants::maxPlayers; ++index) {
5147         	string playerTexture = getGameCustomCoreDataPath(data_path, "data/core/faction_textures/faction" + intToStr(index) + ".tga");
5148         	if(fileExists(playerTexture) == true) {
5149         		Texture2D *texture = Renderer::getInstance().newTexture2D(rsGlobal);
5150         		if(texture) {
5151         			texture->load(playerTexture);
5152         		}
5153         		crcPlayerTextureCache[index] = texture;
5154         	}
5155         	else {
5156         		crcPlayerTextureCache[index] = NULL;
5157         	}
5158         }
5159         // Cache Player textures - END
5160 
5161 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5162 
5163 		mainWindow= new MainWindow(program);
5164 
5165         SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5166 
5167         GameSettings startupGameSettings;
5168 
5169 		//parse command line
5170 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_SERVER]) == true) {
5171 			program->initServer(mainWindow,false,true);
5172 			gameInitialized = true;
5173 		}
5174 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_MASTERSERVER_MODE])) == true) {
5175 			program->initServer(mainWindow,false,true,true);
5176 			gameInitialized = true;
5177 		}
5178 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTOSTART_LASTGAME])) == true) {
5179 			program->initServer(mainWindow,true,false);
5180 			gameInitialized = true;
5181 		}
5182 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTOSTART_LAST_SAVED_GAME])) == true) {
5183 			string fileName = "";
5184 			int foundParamIndIndex = -1;
5185 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_AUTOSTART_LAST_SAVED_GAME]) + string("="),&foundParamIndIndex);
5186 			if(foundParamIndIndex >= 0) {
5187 				string loadfileName = argv[foundParamIndIndex];
5188 				vector<string> paramPartTokens;
5189 				Tokenize(loadfileName,paramPartTokens,"=");
5190 				if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5191 					fileName = paramPartTokens[1];
5192 
5193 					if(fileExists(fileName) == false) {
5194 						// Save the file now
5195 						string saveGameFile = "saved/" + fileName;
5196 						if(getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) != "") {
5197 							saveGameFile = getGameReadWritePath(GameConstants::path_logs_CacheLookupKey) + saveGameFile;
5198 						}
5199 						else {
5200 							saveGameFile = userData + saveGameFile;
5201 						}
5202 						if(fileExists(saveGameFile) == true) {
5203 							fileName = saveGameFile;
5204 						}
5205 					}
5206 
5207 					if(fileExists(fileName) == false) {
5208 						char szBuf[8096]="";
5209 						snprintf(szBuf,8096,"File specified for loading a saved game cannot be found: [%s]",fileName.c_str());
5210 						printf("\n\n======================================================================================\n%s\n======================================================================================\n\n\n",szBuf);
5211 
5212 						throw megaglest_runtime_error(szBuf);
5213 					}
5214 				}
5215 			}
5216 			program->initSavedGame(mainWindow,false,fileName);
5217 			gameInitialized = true;
5218 		}
5219 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_PREVIEW_MAP])) == true) {
5220 			int foundParamIndIndex = -1;
5221 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_PREVIEW_MAP]) + string("="),&foundParamIndIndex);
5222 			if(foundParamIndIndex < 0) {
5223 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_PREVIEW_MAP]),&foundParamIndIndex);
5224 			}
5225 			string mapName = argv[foundParamIndIndex];
5226 			vector<string> paramPartTokens;
5227 			Tokenize(mapName,paramPartTokens,"=");
5228 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5229 				vector<string> paramPartTokens2;
5230 				string tileset="forest";
5231 				Tokenize(paramPartTokens[1],paramPartTokens2,",");
5232 				if(paramPartTokens2.size() >= 2 && paramPartTokens2[1].length() > 0) {
5233 					tileset = paramPartTokens2[1];
5234 				}
5235 				string autoloadMapName = paramPartTokens2[0];
5236 
5237 				GameSettings *gameSettings = &startupGameSettings;
5238 				gameSettings->setMap(autoloadMapName);
5239 				gameSettings->setTileset(tileset);
5240 				gameSettings->setTech("megapack");
5241 				gameSettings->setDefaultUnits(false);
5242 				gameSettings->setDefaultResources(false);
5243 				gameSettings->setDefaultVictoryConditions(true);
5244 				gameSettings->setFogOfWar(false);
5245 				gameSettings->setAllowObservers(true);
5246 				gameSettings->setPathFinderType(pfBasic);
5247 
5248 				for(int i = 0; i < GameConstants::maxPlayers; ++i) {
5249 					ControlType ct= ctClosed;
5250 
5251 					gameSettings->setNetworkPlayerStatuses(i, npst_None);
5252 					gameSettings->setFactionControl(i, ct);
5253 					gameSettings->setStartLocationIndex(i, i);
5254 					gameSettings->setResourceMultiplierIndex(i, 10);
5255 					gameSettings->setNetworkPlayerName(i, GameConstants::NETWORK_SLOT_CLOSED_SLOTNAME);
5256 				}
5257 
5258 				ControlType ct= ctHuman;
5259 
5260 				gameSettings->setNetworkPlayerStatuses(0, npst_None);
5261 				gameSettings->setFactionControl(0, ct);
5262 				gameSettings->setFactionTypeName(0, formatString(GameConstants::OBSERVER_SLOTNAME));
5263 				gameSettings->setTeam(0, GameConstants::maxPlayers + fpt_Observer - 1);
5264 				gameSettings->setStartLocationIndex(0, 0);
5265 				gameSettings->setNetworkPlayerName(0, GameConstants::OBSERVER_SLOTNAME);
5266 
5267 				gameSettings->setFactionCount(1);
5268 
5269 				Config &config = Config::getInstance();
5270 				gameSettings->setEnableServerControlledAI(config.getBool("ServerControlledAI","true"));
5271 				gameSettings->setNetworkFramePeriod(config.getInt("NetworkSendFrameCount","20"));
5272 
5273 				program->initServer(mainWindow,gameSettings);
5274 				gameInitialized = true;
5275 			}
5276 			else {
5277 				printf("\nInvalid map name specified on commandline [%s] map [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5278 				printParameterHelp(argv[0],foundInvalidArgs);
5279 				delete mainWindow;
5280 				mainWindow=NULL;
5281 				return 1;
5282 			}
5283 		}
5284 
5285 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CONNECT])) == true) {
5286 			int foundParamIndIndex = -1;
5287 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CONNECT]) + string("="),&foundParamIndIndex);
5288 			if(foundParamIndIndex < 0) {
5289 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CONNECT]),&foundParamIndIndex);
5290 			}
5291 			string serverToConnectTo = argv[foundParamIndIndex];
5292 			vector<string> paramPartTokens;
5293 			Tokenize(serverToConnectTo,paramPartTokens,"=");
5294 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5295 				string autoConnectServer = paramPartTokens[1];
5296 
5297 				int port = config.getInt("PortServer",intToStr(GameConstants::serverPort).c_str());
5298 				vector<string> paramPartTokens2;
5299 				Tokenize(autoConnectServer,paramPartTokens2,":");
5300 				autoConnectServer = paramPartTokens2[0];
5301 				if(paramPartTokens2.size() >= 2 && paramPartTokens2[1].length() > 0) {
5302 					port = strToInt(paramPartTokens2[1]);
5303 				}
5304 
5305 				printf("Connecting to host [%s] using port: %d\n",autoConnectServer.c_str(),port);
5306 				if(autoConnectServer == "auto-connect") {
5307 					program->initClientAutoFindHost(mainWindow);
5308 				}
5309 				else {
5310 					program->initClient(mainWindow, autoConnectServer,port);
5311 				}
5312 				gameInitialized = true;
5313 			}
5314 			else {
5315 
5316 				printf("\nInvalid host specified on commandline [%s] host [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5317 				printParameterHelp(argv[0],foundInvalidArgs);
5318 				delete mainWindow;
5319 				mainWindow=NULL;
5320 				return 1;
5321 			}
5322 		}
5323 
5324 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CLIENT])) == true) {
5325 			int foundParamIndIndex = -1;
5326 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CLIENT]) + string("="),&foundParamIndIndex);
5327 			if(foundParamIndIndex < 0) {
5328 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CLIENT]),&foundParamIndIndex);
5329 			}
5330 			string serverToConnectTo = argv[foundParamIndIndex];
5331 			vector<string> paramPartTokens;
5332 			Tokenize(serverToConnectTo,paramPartTokens,"=");
5333 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5334 				string autoConnectServer = paramPartTokens[1];
5335 
5336 				if(autoConnectServer == "auto-connect") {
5337 					program->initClientAutoFindHost(mainWindow);
5338 				}
5339 				else {
5340 					program->initClient(mainWindow, autoConnectServer);
5341 				}
5342 				gameInitialized = true;
5343 			}
5344 			else {
5345 
5346 				printf("\nInvalid host specified on commandline [%s] host [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5347 				printParameterHelp(argv[0],foundInvalidArgs);
5348 				delete mainWindow;
5349 				mainWindow=NULL;
5350 				return 1;
5351 			}
5352 		}
5353 		else if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LOADSCENARIO])) == true) {
5354 
5355 			int foundParamIndIndex = -1;
5356 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LOADSCENARIO]) + string("="),&foundParamIndIndex);
5357 			if(foundParamIndIndex < 0) {
5358 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_LOADSCENARIO]),&foundParamIndIndex);
5359 			}
5360 			string scenarioName = argv[foundParamIndIndex];
5361 			vector<string> paramPartTokens;
5362 			Tokenize(scenarioName,paramPartTokens,"=");
5363 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5364 				string autoloadScenarioName = paramPartTokens[1];
5365 
5366 				program->initScenario(mainWindow, autoloadScenarioName);
5367 				gameInitialized = true;
5368 			}
5369 			else {
5370 				printf("\nInvalid scenario name specified on commandline [%s] scenario [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5371 				printParameterHelp(argv[0],foundInvalidArgs);
5372 				delete mainWindow;
5373 				mainWindow=NULL;
5374 				return 1;
5375 			}
5376 		}
5377 		else {
5378 			program->initNormal(mainWindow);
5379 		}
5380 
5381 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5382 
5383 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] OpenGL Info:\n%s\n",__FILE__,__FUNCTION__,__LINE__,renderer.getGlInfo().c_str());
5384 
5385 		if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_OPENGL_INFO]) == true) {
5386 			printf("%s",renderer.getGlInfo().c_str());
5387 			printf("%s",renderer.getGlMoreInfo().c_str());
5388 
5389 			delete mainWindow;
5390 			mainWindow=NULL;
5391 			return 0;
5392 		}
5393 
5394     	if(hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_CONVERT_MODELS]) == true) {
5395 			int foundParamIndIndex = -1;
5396 			hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CONVERT_MODELS]) + string("="),&foundParamIndIndex);
5397 			if(foundParamIndIndex < 0) {
5398 				hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_CONVERT_MODELS]),&foundParamIndIndex);
5399 			}
5400 			string paramValue = argv[foundParamIndIndex];
5401 			vector<string> paramPartTokens;
5402 			Tokenize(paramValue,paramPartTokens,"=");
5403 			if(paramPartTokens.size() >= 2 && paramPartTokens[1].length() > 0) {
5404 				string modelFile = paramPartTokens[1];
5405 				printf("About to convert model(s) [%s]\n",modelFile.c_str());
5406 
5407 				string textureFormat = "";
5408 				if(paramPartTokens.size() >= 3 && paramPartTokens[1].length() > 0) {
5409 					textureFormat = paramPartTokens[2];
5410 					printf("About to convert using texture format [%s]\n",textureFormat.c_str());
5411 				}
5412 
5413 				bool keepsmallest = false;
5414 				if(paramPartTokens.size() >= 4 && paramPartTokens[1].length() > 0) {
5415 					keepsmallest = (paramPartTokens[3] == "keepsmallest");
5416 					printf("About to convert using keepsmallest = %d\n",keepsmallest);
5417 				}
5418 
5419 				showCursor(true);
5420 
5421 				const Metrics &metrics= Metrics::getInstance();
5422 				renderer.clearBuffers();
5423 				renderer.clearZBuffer();
5424 				renderer.reset2d();
5425 
5426 				if(CoreData::getInstance().getMenuFontBig3D() != NULL) {
5427 					renderer.renderText3D(
5428 							"Please wait, converting models...",
5429 							CoreData::getInstance().getMenuFontBig3D(),
5430 							Vec3f(1.f, 1.f, 0.f), (metrics.getScreenW() / 2) - 400,
5431 							(metrics.getScreenH() / 2), true);
5432 				}
5433 				else {
5434 					renderer.renderText(
5435 							"Please wait, converting models...",
5436 							CoreData::getInstance().getMenuFontBig(),
5437 							Vec3f(1.f, 1.f, 0.f), (metrics.getScreenW() / 2) - 400,
5438 							(metrics.getScreenH() / 2), true);
5439 				}
5440 			    renderer.swapBuffers();
5441 
5442 				std::vector<string> models;
5443 				if(isdir(modelFile.c_str()) == true) {
5444 					models = getFolderTreeContentsListRecursively(modelFile, ".g3d");
5445 				}
5446 				else {
5447 					models.push_back(modelFile);
5448 				}
5449 
5450 			    sleep(0);
5451 			    ::Shared::Platform::Window::handleEvent();
5452 				SDL_PumpEvents();
5453 
5454 				int result = 0;
5455 				char szTextBuf[8096]="";
5456 				for(unsigned int i =0; i < models.size(); ++i) {
5457 					string &file = models[i];
5458 
5459 					renderer.clearBuffers();
5460 					renderer.clearZBuffer();
5461 					renderer.reset2d();
5462 				    snprintf(szTextBuf,8096,"Please wait, converting models [%u of " MG_SIZE_T_SPECIFIER "] ...",i,models.size());
5463 
5464 				    if(CoreData::getInstance().getMenuFontBig3D() != NULL) {
5465 						renderer.renderText3D(
5466 								szTextBuf,
5467 								CoreData::getInstance().getMenuFontBig3D(),
5468 								Vec3f(1.f, 1.f, 0.f), (metrics.getScreenW() / 2) - 400,
5469 								(metrics.getScreenH() / 2), true);
5470 				    }
5471 				    else {
5472 						renderer.renderText(
5473 								szTextBuf,
5474 								CoreData::getInstance().getMenuFontBig(),
5475 								Vec3f(1.f, 1.f, 0.f), (metrics.getScreenW() / 2) - 400,
5476 								(metrics.getScreenH() / 2), true);
5477 				    }
5478 				    renderer.swapBuffers();
5479 
5480 				    sleep(0);
5481 				    ::Shared::Platform::Window::handleEvent();
5482 					SDL_PumpEvents();
5483 
5484 					try {
5485 						printf("About to load model [%s] [%u of " MG_SIZE_T_SPECIFIER "]\n",file.c_str(),i,models.size());
5486 						Model *model = renderer.newModel(rsGlobal, file);
5487 						printf("About to save converted model [%s]\n",file.c_str());
5488 						model->save(file,textureFormat,keepsmallest);
5489                         Renderer::getInstance().endModel(rsGlobal, model);
5490 					}
5491 					catch(const exception &ex) {
5492 						result = 1;
5493 						printf("ERROR loading model [%s] message [%s]\n",file.c_str(),ex.what());
5494                     }
5495 
5496 				}
5497 
5498 				delete mainWindow;
5499 				mainWindow=NULL;
5500 				return result;
5501 			}
5502 			else {
5503 				printf("\nInvalid model specified on commandline [%s] texture [%s]\n\n",argv[foundParamIndIndex],(paramPartTokens.size() >= 2 ? paramPartTokens[1].c_str() : NULL));
5504 				printParameterHelp(argv[0],foundInvalidArgs);
5505 				delete mainWindow;
5506 				mainWindow=NULL;
5507 				return 1;
5508 			}
5509     	}
5510 
5511 		if(	hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TECHTREES]) 	== true ||
5512 			hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_FACTIONS]) 	== true ||
5513 			hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_SCENARIO])    == true) {
5514 			runTechValidationReport(argc, argv);
5515 
5516 		    delete mainWindow;
5517 		    mainWindow=NULL;
5518 		    return 0;
5519 		}
5520 
5521 		if(	hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_TRANSLATE_TECHTREES]) == true) {
5522 			runTechTranslationExtraction(argc, argv);
5523 		    delete mainWindow;
5524 		    mainWindow=NULL;
5525 		    return 0;
5526 		}
5527 
5528 		if(	hasCommandArgument(argc, argv,GAME_ARGS[GAME_ARG_VALIDATE_TILESET]) == true) {
5529 			runTilesetValidationReport(argc, argv);
5530 
5531 		    delete mainWindow;
5532 		    mainWindow=NULL;
5533 		    return 0;
5534 		}
5535 
5536 		gameInitialized = true;
5537 
5538 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5539 
5540         CheckForDuplicateData();
5541 
5542         SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5543 
5544 		//throw "BLAH!";
5545 
5546         // START Test out SIGSEGV error handling
5547         //int *foo = (int*)-1; // make a bad pointer
5548         //printf("%d\n", *foo);       // causes segfault
5549         // END
5550 
5551         bool startCRCPrecacheThread = config.getBool("PreCacheCRCThread","true");
5552         //printf("### In [%s::%s Line: %d] precache thread enabled = %d SystemFlags::VERBOSE_MODE_ENABLED = %d\n",__FILE__,__FUNCTION__,__LINE__,startCRCPrecacheThread,SystemFlags::VERBOSE_MODE_ENABLED);
5553         if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] precache thread enabled = %d\n",__FILE__,__FUNCTION__,__LINE__,startCRCPrecacheThread);
5554 		if (startCRCPrecacheThread == true
5555 				&& GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5556 			static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__);
5557 			vector<string> techDataPaths = config.getPathListForType(ptTechs);
5558 
5559 			FileCRCPreCacheThread::setPreCacheThreadCacheLookupKey(GameConstants::preCacheThreadCacheLookupKey);
5560 			FileCRCPreCacheThread * &preCacheCRCThreadPtr = CacheManager::getCachedItem< FileCRCPreCacheThread * >(GameConstants::preCacheThreadCacheLookupKey);
5561 			if(preCacheCRCThreadPtr == NULL) {
5562 				preCacheCRCThreadPtr = new FileCRCPreCacheThread();
5563 			}
5564 			preCacheThread = preCacheCRCThreadPtr;
5565 			preCacheThread->setUniqueID(mutexOwnerId);
5566 			preCacheThread->setTechDataPaths(techDataPaths);
5567 			//preCacheThread->setFileCRCPreCacheThreadCallbackInterface(&preCacheThreadGame);
5568 			preCacheThread->start();
5569 		}
5570 
5571 		auto_ptr<NavtiveLanguageNameListCacheGenerator> lngCacheGen;
5572 		auto_ptr<SimpleTaskThread> languageCacheGen;
5573 
5574 		bool startNativeLanguageNamesPrecacheThread = config.getBool("PreCacheNativeLanguageNamesThread","true");
5575 		if(startNativeLanguageNamesPrecacheThread == true &&
5576 				GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5577 			lngCacheGen.reset(new NavtiveLanguageNameListCacheGenerator());
5578 			languageCacheGen.reset(new SimpleTaskThread(lngCacheGen.get(),1));
5579 
5580 			languageCacheGen->start();
5581 		}
5582 
5583         // test
5584         //Shared::Platform::MessageBox(NULL,"Mark's test.","Test",0);
5585         //throw megaglest_runtime_error("test!");
5586         //ExceptionHandler::DisplayMessage("test!", false);
5587 
5588 		// Check for commands being input from stdin
5589 		string command="";
5590 
5591 #ifndef WIN32
5592 		pollfd cinfd[1];
5593 #else
5594 		HANDLE h = 0;
5595 #endif
5596 		if(disableheadless_console == false) {
5597 #ifndef WIN32
5598 			// Theoretically this should always be 0, but one fileno call isn't going to hurt, and if
5599 			// we try to run somewhere that stdin isn't fd 0 then it will still just work
5600 			cinfd[0].fd = fileno(stdin);
5601 			cinfd[0].events = POLLIN;
5602 #else
5603 			h = GetStdHandle(STD_INPUT_HANDLE);
5604 			//DWORD dwMode;
5605 			//GetConsoleMode(h, &dwMode);
5606 			//SetConsoleMode(h, dwMode & ~ENABLE_MOUSE_INPUT);
5607 			FlushConsoleInputBuffer(h);
5608 #endif
5609 		}
5610 
5611 	    if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
5612 	    	printf("Headless server is now running...\n");
5613 	    	printf("To shutdown type: quit\n");
5614 	    	printf("All commands require you to press ENTER\n");
5615 	    }
5616 
5617 	    //throw megaglest_runtime_error("Test!");
5618 		//printf("About to throw an exception...\n");
5619 		//throw 123;
5620 
5621 		//main loop
5622 		while(program->isShutdownApplicationEnabled() == false && ::Shared::Platform::Window::handleEvent()) {
5623 			if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
5624 
5625 				if(disableheadless_console == false) {
5626 				#ifndef WIN32
5627 					int pollresult = poll(cinfd, 1, 0);
5628 					int pollerror = errno;
5629 					if(pollresult)
5630 				#else
5631 					// This is problematic because input on Windows is not line-buffered so this will return
5632 					// even if getline may block.  I haven't found a good way to fix it, so for the moment
5633 					// I just strongly suggest only running the server from the Python frontend, which does
5634 					// line buffer input.  This does work okay as long as the user doesn't enter characters
5635 					// without pressing enter, and then try to end the server another way (say a remote
5636 					// console command), in which case we'll still be waiting for the stdin EOL and hang.
5637 
5638 					DWORD   saveMode;
5639 					GetConsoleMode(h, &saveMode);
5640 					DWORD dwMode = saveMode;
5641 					dwMode &= ~ENABLE_MOUSE_INPUT;
5642 					dwMode &= ~ENABLE_WINDOW_INPUT;
5643 					SetConsoleMode(h, dwMode);
5644 
5645 					bool gotData = (WaitForSingleObject(h, 0) == WAIT_OBJECT_0);
5646 					SetConsoleMode(h, saveMode);
5647 					if(gotData == true)
5648 				#endif
5649 					{
5650 
5651 
5652 #ifdef WIN32
5653 						bool skip = true;
5654 						DWORD nNumberOfCharsToRead = 1024;
5655 						DWORD nRead = 0;
5656 						INPUT_RECORD irInRec[1025];
5657 
5658 						PeekConsoleInput(h,&irInRec[0],nNumberOfCharsToRead,&nRead);
5659 						for(int i = 0; i < nRead; ++i) {
5660 							INPUT_RECORD &inr = irInRec[i];
5661 
5662 							//printf("inr.EventType = %d\n",inr.EventType);
5663 							if(inr.EventType == KEY_EVENT) {
5664 							  if(inr.Event.KeyEvent.bKeyDown) {
5665 								char cHoldKey = inr.Event.KeyEvent.uChar.AsciiChar;
5666 								if(cHoldKey == '\r') {
5667 									skip = false;
5668 									break;
5669 								}
5670 							  }
5671 							}
5672 						}
5673 #else
5674 						bool skip = false;
5675 #endif
5676 						if(skip == false) {
5677 							getline(cin, command);
5678 							cin.clear();
5679 
5680 							printf("server command [%s]\n",command.c_str());
5681 							if(command == "quit") {
5682 								break;
5683 							}
5684 
5685 #ifndef WIN32
5686 							if (cinfd[0].revents & POLLNVAL) {
5687 								printf("invalid file descriptor\n");
5688 							}
5689 							if (cinfd[0].revents & POLLERR) {
5690 								printf("error in file descriptor\n");
5691 							}
5692 							if (cinfd[0].revents & POLLHUP) {
5693 								printf("hang up in file descriptor\n");
5694 							}
5695 
5696 							if(pollresult < 0) {
5697 								printf("pollresult = %d errno = %d [%s]\n",pollresult,pollerror,strerror(pollerror));
5698 
5699 								cinfd[0].fd = fileno(stdin);
5700 								cinfd[0].events = POLLIN;
5701 							}
5702 #endif
5703 						}
5704 					}
5705 				}
5706 				//printf("looping\n");
5707 			}
5708 
5709 			program->loop();
5710 
5711 			// Because OpenGL really doesn't do multi-threading well
5712 //			if(difftime(time(NULL),lastTextureLoadEvent) >= 3) {
5713 //				lastTextureLoadEvent = time(NULL);
5714 //				vector<Texture2D *> textureList = preCacheThread->getPendingTextureList(1);
5715 //				for(unsigned int i = 0; i < textureList.size(); ++i) {
5716 //					Texture2D * factionLogo = textureList[i];
5717 //					if(factionLogo != NULL) {
5718 //						printf("\n\n\n\n|||||||||||||||||||||||||| Load texture [%s]\n",factionLogo->getPath().c_str());
5719 //						//Renderer::findTexture(factionLogo);
5720 //						renderer.initTexture(rsGlobal,factionLogo);
5721 //					}
5722 //				}
5723 //			}
5724 		}
5725 
5726 	    if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == true) {
5727 	    	printf("\nHeadless server is about to quit...\n");
5728 	    }
5729 
5730 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] starting normal application shutdown\n",__FILE__,__FUNCTION__,__LINE__);
5731 
5732 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5733 			soundThreadManager = program->getSoundThreadManager(true);
5734 			if(soundThreadManager) {
5735 				SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5736 				soundRenderer.stopAllSounds(shutdownFadeSoundMilliseconds);
5737 				chronoshutdownFadeSound.start();
5738 			}
5739 		}
5740 
5741 		cleanupCRCThread();
5742 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5743 
5744 	    showCursor(true);
5745 	    //showWindowCursorState = true;
5746 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5747 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5748 	}
5749 	catch(const megaglest_runtime_error &e) {
5750 
5751 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5752 			soundThreadManager = (program != NULL ? program->getSoundThreadManager(true) : NULL);
5753 			if(soundThreadManager) {
5754 				SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5755 				soundRenderer.stopAllSounds(shutdownFadeSoundMilliseconds);
5756 				chronoshutdownFadeSound.start();
5757 			}
5758 			if(program != NULL &&
5759 				program->getTryingRendererInit() == true &&
5760 				program->getRendererInitOk() == false) {
5761 
5762 				message(e.what(),GlobalStaticFlags::getIsNonGraphicalModeEnabled(),tempDataLocation);
5763 			}
5764 		}
5765 
5766 		if(program == NULL || program->getTryingRendererInit() == false ||
5767 			(program->getTryingRendererInit() == true &&
5768 				program->getRendererInitOk() == true)) {
5769 
5770 			ExceptionHandler::handleRuntimeError(e);
5771 		}
5772 	}
5773 	catch(const exception &e) {
5774 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5775 			soundThreadManager = (program != NULL ? program->getSoundThreadManager(true) : NULL);
5776 			if(soundThreadManager) {
5777 				SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5778 				soundRenderer.stopAllSounds(shutdownFadeSoundMilliseconds);
5779 				chronoshutdownFadeSound.start();
5780 			}
5781 		}
5782 
5783 		ExceptionHandler::handleRuntimeError(e.what(),true);
5784 	}
5785 	catch(const char *e) {
5786 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5787 			soundThreadManager = (program != NULL ? program->getSoundThreadManager(true) : NULL);
5788 			if(soundThreadManager) {
5789 				SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5790 				soundRenderer.stopAllSounds(shutdownFadeSoundMilliseconds);
5791 				chronoshutdownFadeSound.start();
5792 			}
5793 		}
5794 
5795 		ExceptionHandler::handleRuntimeError(e,true);
5796 	}
5797 	catch(const string &ex) {
5798 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5799 			soundThreadManager = (program != NULL ? program->getSoundThreadManager(true) : NULL);
5800 			if(soundThreadManager) {
5801 				SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5802 				soundRenderer.stopAllSounds(shutdownFadeSoundMilliseconds);
5803 				chronoshutdownFadeSound.start();
5804 			}
5805 		}
5806 
5807 		ExceptionHandler::handleRuntimeError(ex.c_str(),true);
5808 	}
5809 #if !defined(HAVE_GOOGLE_BREAKPAD)
5810 	catch(...) {
5811 		if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5812 			soundThreadManager = (program != NULL ? program->getSoundThreadManager(true) : NULL);
5813 			if(soundThreadManager) {
5814 				SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5815 				soundRenderer.stopAllSounds(shutdownFadeSoundMilliseconds);
5816 				chronoshutdownFadeSound.start();
5817 			}
5818 		}
5819 
5820 		ExceptionHandler::handleRuntimeError("Unknown error [main]!",true);
5821 	}
5822 #endif
5823 
5824 	cleanupCRCThread();
5825 
5826 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5827 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5828 
5829 	delete mainWindow;
5830 	mainWindow = NULL;
5831 
5832 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5833 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5834 
5835 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5836 	GraphicComponent::clearRegisteredComponents();
5837 
5838 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5839 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5840 
5841 	if(soundThreadManager) {
5842 		SoundRenderer &soundRenderer= SoundRenderer::getInstance();
5843 		if( Config::getInstance().getString("FactorySound","") != "None" &&
5844 			soundRenderer.isVolumeTurnedOff() == false) {
5845 
5846 			if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5847 			SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5848 
5849 			for(;chronoshutdownFadeSound.getMillis() <= shutdownFadeSoundMilliseconds;) {
5850 				sleep(10);
5851 			}
5852 		}
5853 
5854 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5855 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5856 
5857 		BaseThread::shutdownAndWait(soundThreadManager);
5858 
5859 		if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5860 		SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5861 
5862 		delete soundThreadManager;
5863 		soundThreadManager = NULL;
5864 	}
5865 
5866 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5867 	SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5868 
5869 	return 0;
5870 }
5871 
5872 #if defined(__GNUC__)  && !defined(__DragonFly__) && !defined(BSD)
handleSIGSEGV(int sig)5873 void handleSIGSEGV(int sig) {
5874     char szBuf[8096]="";
5875     snprintf(szBuf, 8096,"In [%s::%s Line: %d] Error detected: signal %d:\n",__FILE__,__FUNCTION__,__LINE__, sig);
5876     printf("%s",szBuf);
5877     //abort();
5878 
5879     ExceptionHandler::handleRuntimeError(szBuf,true);
5880 }
5881 #endif
5882 
5883 #if defined(HAVE_GOOGLE_BREAKPAD)
5884 
5885 #if defined(WIN32)
5886 // Callback when minidump written.
MinidumpCallback(const wchar_t * dump_path,const wchar_t * minidump_id,void * context,EXCEPTION_POINTERS * exinfo,MDRawAssertionInfo * assertion,bool succeeded)5887 static bool MinidumpCallback(const wchar_t *dump_path,
5888                              const wchar_t *minidump_id,
5889                              void *context,
5890                              EXCEPTION_POINTERS* exinfo,
5891                              MDRawAssertionInfo* assertion,
5892                              bool succeeded) {
5893   printf("\n======= In MinidumpCallback...\n");
5894   wprintf(L"\n***ERROR details captured:\nCrash minidump folder: %s\nfile: %s.dmp\nSucceeded: %d\n", (dump_path != NULL ? dump_path : L"(null)"),(minidump_id != NULL ? minidump_id : L"(null)"),succeeded);
5895 
5896   if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5897 	  wchar_t szBuf[8096];
5898 	  int bufBytes = _snwprintf(szBuf,8096,L"An unhandled error was detected.\n\nA crash dump file has been created in the folder:\n%s\nCrash dump filename is: %s.dmp",dump_path,minidump_id);
5899 	  szBuf[bufBytes] = '\0';
5900 	  MessageBox(NULL, szBuf, L"Unhandled error", MB_OK|MB_SYSTEMMODAL);
5901   }
5902 
5903   return succeeded;
5904 }
5905 
5906 #else
5907 
5908 // Callback when minidump written.
MinidumpCallback(const google_breakpad::MinidumpDescriptor & descriptor,void * context,bool succeeded)5909 static bool MinidumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
5910 							void* context,
5911 							bool succeeded) {
5912   printf("\n======= In MinidumpCallback...\n");
5913   printf("\n***ERROR details captured:\nCrash minidump folder: %s\nfile: %s\nSucceeded: %d\n", descriptor.directory().c_str(),descriptor.path(),succeeded);
5914 
5915   if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) {
5916 	  char szBuf[8096];
5917 	  snprintf(szBuf,8096,"An unhandled error was detected.\n\nA crash dump file has been created in the folder:\n%s\nCrash dump filename is: %s",descriptor.directory().c_str(),descriptor.path());
5918 	  message(szBuf,GlobalStaticFlags::getIsNonGraphicalModeEnabled(),tempDataLocation);
5919   }
5920 
5921   return succeeded;
5922 }
5923 
5924 #endif
5925 
5926 #endif
5927 
5928 #ifdef WIN32
EnableCrashingOnCrashes()5929 void EnableCrashingOnCrashes() {
5930     typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags);
5931     typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags);
5932     const DWORD EXCEPTION_SWALLOWING = 0x1;
5933 
5934     HMODULE kernel32 = LoadLibraryA("kernel32.dll");
5935 	if(kernel32 != 0) {
5936 		tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, "GetProcessUserModeExceptionPolicy");
5937 		tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, "SetProcessUserModeExceptionPolicy");
5938 		if (pGetPolicy && pSetPolicy) {
5939 			DWORD dwFlags;
5940 			if (pGetPolicy(&dwFlags)) {
5941 				// Turn off the filter
5942 				pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING);
5943 			}
5944 		}
5945 	}
5946 }
5947 #endif
5948 
glestMainSEHWrapper(int argc,char ** argv)5949 int glestMainSEHWrapper(int argc, char** argv) {
5950 
5951 #ifdef WIN32_STACK_TRACE
5952 	//printf("Hooking up WIN32_STACK_TRACE...\n");
5953 __try {
5954 #endif
5955 
5956     //application_binary= executable_path(argv[0],true);
5957     //printf("\n\nargv0 [%s] application_binary [%s]\n\n",argv[0],application_binary.c_str());
5958 
5959 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__DragonFly__) && !defined(BSD)
5960 
5961 	if(hasCommandArgument(argc, argv,string(GAME_ARGS[GAME_ARG_DISABLE_SIGSEGV_HANDLER])) == false) {
5962 		signal(SIGSEGV, handleSIGSEGV);
5963 	}
5964 
5965     // http://developerweb.net/viewtopic.php?id=3013
5966     //signal(SIGPIPE, SIG_IGN);
5967 #endif
5968 
5969 	initSpecialStrings();
5970 	int result = 0;
5971 
5972 	IRCThread::setGlobalCacheContainerName(GameConstants::ircClientCacheLookupKey);
5973 	result = glestMain(argc, argv);
5974 
5975 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5976 	cleanupProcessObjects();
5977 
5978 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5979 
5980 #ifdef WIN32
5981 		//delete winSockManager;
5982 		//winSockManager = NULL;
5983 #endif
5984 
5985     if(sdl_quitCalled == false) {
5986     	sdl_quitCalled = true;
5987     	SDL_Quit();
5988     }
5989 
5990 	if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__);
5991 	return result;
5992 #ifdef WIN32_STACK_TRACE
5993 } __except(stackdumper(0, GetExceptionInformation(),true), EXCEPTION_CONTINUE_SEARCH) { return 0; }
5994 #endif
5995 
5996 }
5997 
glestMainWrapper(int argc,char ** argv)5998 int glestMainWrapper(int argc, char** argv) {
5999 	//setlocale(LC_ALL, "zh_TW.UTF-8");
6000 	//setlocale(LC_ALL, "");
6001 
6002 #ifdef WIN32
6003 	EnableCrashingOnCrashes();
6004 #endif
6005 
6006 #if defined(HAVE_GOOGLE_BREAKPAD)
6007 /*
6008 	handler = new ExceptionHandler(const wstring& dump_path,
6009                                                               FilterCallback filter,
6010                                                               MinidumpCallback callback,
6011                                                               void* callback_context,
6012                                                               int handler_types,
6013                                                               MINIDUMP_TYPE dump_type,
6014                                                               const wchar_t* pipe_name,
6015                                                               const CustomClientInfo* custom_info);
6016 */
6017 
6018 	// See this link about swallowed exceptions in Win 7: http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/
6019 	//DWORD dwFlags;
6020 	//if (GetProcessUserModeExceptionPolicy(&dwFlags)) {
6021 	//	SetProcessUserModeExceptionPolicy(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); // turn off bit 1
6022 	//}
6023 
6024 	//if(SystemFlags::VERBOSE_MODE_ENABLED) printf("Hooking up google_breakpad::ExceptionHandler...\n");
6025 
6026 #if defined(WIN32)
6027 	wstring dumpfilepath = utf8_decode(".");
6028 	//google_breakpad::ExceptionHandler handler(dumpfilepath, NULL, MinidumpCallback, NULL, true);
6029 	errorHandlerPtr.reset(new google_breakpad::ExceptionHandler(dumpfilepath, NULL, MinidumpCallback,
6030 											  NULL, google_breakpad::ExceptionHandler::HANDLER_ALL));
6031 #else
6032 	google_breakpad::MinidumpDescriptor descriptor(".");
6033 	errorHandlerPtr.reset(new google_breakpad::ExceptionHandler(descriptor, NULL, MinidumpCallback, NULL, true,-1));
6034 #endif
6035 
6036 //  ExceptionHandler(const wstring& dump_path,
6037 //                   FilterCallback filter,
6038 //                   MinidumpCallback callback,
6039 //                   void* callback_context,
6040 //                   int handler_types);
6041 
6042 #endif
6043 
6044 #if defined(__GNUC__) && !defined(__MINGW32__) && !defined(__DragonFly__) && !defined(BSD)
6045 //#ifdef DEBUG
6046 	  //printf("MTRACE will be called...\n");
6047       //mtrace ();
6048 //#endif
6049 #endif
6050 
6051 #ifdef WIN32
6052 	//winSockManager = new SocketManager();
6053 	SocketManager winSockManager;
6054 #endif
6055 
6056 	int result = glestMainSEHWrapper(argc, argv);
6057 	return result;
6058 }
6059 
6060 }}//end namespace
6061 
6062 MAIN_FUNCTION(Glest::Game::glestMainWrapper)
6063