[springlobby] 01/03: New upstream version 0.264+dfsg

Markus Koschany apo at moszumanska.debian.org
Sat Mar 3 16:19:42 UTC 2018


This is an automated email from the git hooks/post-receive script.

apo pushed a commit to branch master
in repository springlobby.

commit 6cc765fc8179438b55945763dc3e80ef5a87fb4b
Author: Markus Koschany <apo at debian.org>
Date:   Sat Mar 3 17:07:35 2018 +0100

    New upstream version 0.264+dfsg
---
 CMakeLists.txt                                     |   4 +-
 ChangeLog                                          |   8 +
 VERSION                                            |   2 +-
 buildbot/master.cfg                                |   4 +-
 cmake/compat_flags.cmake                           |  28 +---
 doc/UseDoxygen.cmake                               |   6 +-
 springlobby_config.h                               |   2 +-
 src/CMakeLists.txt                                 |   4 +-
 src/address.cpp                                    | 109 ++++++++++++
 src/address.h                                      |   5 +
 src/autohost.cpp                                   |   2 +-
 src/autohostmanager.cpp                            |  10 ++
 src/autohostmanager.h                              |   3 +
 src/battle.cpp                                     |  12 +-
 src/channel.cpp                                    |   2 +-
 src/downloader/lib/CMakeLists.txt                  |  34 ++--
 src/downloader/lib/src/CMakeLists.txt              |   9 +-
 src/downloader/lib/src/Downloader/CurlWrapper.cpp  |   7 +-
 .../lib/src/Downloader/Rapid/RapidDownloader.cpp   |   3 +-
 src/downloader/lib/src/Downloader/Rapid/Sdp.cpp    |   8 +-
 src/downloader/lib/src/Logger.cpp                  |  90 ++++++----
 src/downloader/lib/src/Logger.h                    |  27 +--
 src/downloader/lib/src/Util.cpp                    |   7 -
 src/downloader/lib/src/Util.h                      |   5 -
 .../lib/src/lsl/lslextract/CMakeLists.txt          |   5 +-
 src/downloader/lib/src/lsl/lslextract/index.html   |   2 +-
 .../lib/src/lsl/lslextract/lslextract.cpp          |   2 +-
 src/downloader/lib/src/lsl/lslunitsync/image.cpp   |   4 +-
 src/downloader/lib/src/lsl/lslutils/logging.h      |  31 ++--
 src/downloader/lib/src/main.cpp                    |   3 +-
 src/downloader/lib/test/CMakeLists.txt             |   2 +
 src/downloader/lib/test/lsl/usync.cpp              |  13 +-
 src/downloader/prdownloader.cpp                    |  13 +-
 src/gui/aboutbox.cpp                               |   7 +-
 src/gui/chatpanel.cpp                              |   2 +-
 src/gui/hosting/battleroomtab.cpp                  | 107 ++++++++----
 src/gui/hosting/battleroomtab.h                    |   1 +
 src/gui/hosting/hostbattledialog.cpp               |  42 +++--
 src/gui/hosting/hostbattledialog.h                 |   4 +-
 src/gui/mainwindow.cpp                             |  15 +-
 src/gui/mapctrl.cpp                                |   3 +-
 src/gui/mapgridctrl.cpp                            |   6 +-
 src/gui/notifications/libnotify.cpp                |   4 +-
 src/gui/options/lobbyoptionstab.cpp                |  16 +-
 src/gui/options/mainoptionstab.cpp                 |   5 +-
 src/gui/options/springoptionstab.cpp               |  17 +-
 src/gui/playback/playbacktab.cpp                   |   4 +
 src/gui/singleplayertab.cpp                        |  50 +++---
 src/gui/singleplayertab.h                          |   4 +-
 src/gui/statusbar.cpp                              |   2 +-
 src/gui/ui.cpp                                     |  57 +++----
 src/gui/ui.h                                       |   2 +-
 src/ibattle.cpp                                    |  86 +++++-----
 src/ibattle.h                                      |   5 +-
 src/log.cpp                                        | 186 +++++++++++----------
 src/log.h                                          |   4 +
 src/socket.cpp                                     | 110 +-----------
 src/springlobbyapp.cpp                             |   6 +-
 src/springlobbyapp.h                               |  13 +-
 src/springsettings/frame.cpp                       |   4 +-
 src/sysinfo.cpp                                    |  12 +-
 src/tasserver.cpp                                  |  29 ++--
 src/tests/CMakeLists.txt                           |   6 +
 src/tests/lobbyid.cpp                              |   9 +
 src/updatehelper.cpp                               |  30 ++++
 src/updatehelper.h                                 |   4 +
 src/utils/conversion.cpp                           |   3 +
 src/utils/platform.cpp                             |   4 +
 src/utils/slpaths.cpp                              |   6 +-
 src/utils/version.cpp                              |  12 +-
 src/utils/version.h                                |   6 +-
 tools/mxe_create_builddir.sh                       |   6 +-
 72 files changed, 765 insertions(+), 590 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 42d276b..7a45199 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,7 +1,7 @@
 PROJECT(springlobby)
 
 #set minimum cmake version
-cmake_minimum_required(VERSION 2.8.11)
+cmake_minimum_required(VERSION 3.1)
 
 SET(CMAKE_COLOR_MAKEFILE ON)
 set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
@@ -35,6 +35,8 @@ endif()
 #----------------------------------------------------------------------------------------------------
 SET( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
 
+INCLUDE(compat_flags)
+
 #----------------------------------------------------------------------------------------------------
 # Load needed Modules
 #----------------------------------------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 3364dea..fd925ce 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 ChangeLog of Springlobby
 
+## 0.264
+ - improved the start button in battleroom
+ - log everything into springlobby.log (added downloader + unitsync handling)
+ - cmake 3.1 at least is required to compile springlobby
+ - replace boost:: with std:: in some places
+ - fix crash when re-selecting no map / no game in singleplayer tab
+ - updated buildslave to latest mxe (wxwidgets 3.0.3, etc)
+
 ## 0.263
  - more verbose logging to track down crashes
 
diff --git a/VERSION b/VERSION
index b1b695c..4c42f43 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.263
+0.264
diff --git a/buildbot/master.cfg b/buildbot/master.cfg
index 6a4a043..d10aa17 100644
--- a/buildbot/master.cfg
+++ b/buildbot/master.cfg
@@ -436,8 +436,8 @@ class MXEFactory(BuildFactory):
 
 
 win32buildenv = {
-		'CMAKE': '/home/buildbot/slaves/springlobby/mxe/build/mxe/usr/bin/i686-w64-mingw32.static-cmake',
-		'CMAKE_PARAMS': '-DCMAKE_STRIP:PATH=/home/buildbot/slaves/springlobby/mxe/build/mxe/usr/bin/i686-w64-mingw32.static-strip'
+		'CMAKE':                           '/home/buildbot/slaves/springlobby/mxe/build/mxe/usr/bin/i686-w64-mingw32.static.posix-cmake',
+		'CMAKE_PARAMS': '-DCMAKE_STRIP:PATH=/home/buildbot/slaves/springlobby/mxe/build/mxe/usr/bin/i686-w64-mingw32.static.posix-strip'
 	}
 
 c['builders'].append({'name': 'develop',
diff --git a/cmake/compat_flags.cmake b/cmake/compat_flags.cmake
index 741c19d..8496750 100644
--- a/cmake/compat_flags.cmake
+++ b/cmake/compat_flags.cmake
@@ -1,32 +1,22 @@
+
 include(TestCXXAcceptsFlag)
-execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
-				OUTPUT_VARIABLE GCC_VERSION)
 
-# try to use compiler flag -std=c++11
+CHECK_CXX_ACCEPTS_FLAG("-std=c++11" ACCEPTSFLAGCXX11)
+CHECK_CXX_ACCEPTS_FLAG("-std=c++17" ACCEPTSFLAGCXX17)
+
 MACRO(AddSTDFlag FLAG)
 	set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAG} ")
 	set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG} ")
 	set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${FLAG} ")
 	set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAG} ")
 	set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${FLAG} ")
-	set(CXX_STD0X_FLAGS "${FLAG}" )
 ENDMACRO(AddSTDFlag FLAG)
 
-# try to use compiler flag -std=c++11
-
-set(CXX_STD0X_FLAGS FALSE)
-set(i 0)
-foreach(f -std=gnu++11 -std=c++11 -std=c++0x)
-	MATH(EXPR i "${i}+1") #cmake has working unset :-|
-	CHECK_CXX_ACCEPTS_FLAG("${f}" ACCEPTSFLAG${i})
-	if(${ACCEPTSFLAG${i}} AND NOT CXX_STD0X_FLAGS)
-		message(STATUS "Using ${f}")
-		AddSTDFlag("${f}")
-		set(CXX_STD0X_FLAGS TRUE)
-	endif()
-endforeach()
-
-if(NOT CXX_STD0X_FLAGS)
+if (ACCEPTSFLAGCXX17)
+	AddSTDFlag("-std=c++17")
+elseif(ACCEPTSFLAGCXX11)
+	AddSTDFlag("-std=c++11")
+else()
 	message(FATAL_ERROR "you need a c++11 compatible compiler")
 endif()
 
diff --git a/doc/UseDoxygen.cmake b/doc/UseDoxygen.cmake
index 05760ae..5975962 100644
--- a/doc/UseDoxygen.cmake
+++ b/doc/UseDoxygen.cmake
@@ -109,10 +109,6 @@ if(DOXYGEN_FOUND AND DOXYFILE_IN)
 
 	configure_file(${DOXYFILE_IN} Doxyfile ESCAPE_QUOTES IMMEDIATE @ONLY)
 
-	get_target_property(DOC_TARGET doc TYPE)
-	if(NOT DOC_TARGET)
-		add_custom_target(doc)
-	endif()
-		
+	add_custom_target(doc)
 	add_dependencies(doc doxygen)
 endif()
diff --git a/springlobby_config.h b/springlobby_config.h
index 69dfa26..6093947 100644
--- a/springlobby_config.h
+++ b/springlobby_config.h
@@ -6,6 +6,6 @@
 #undef VERSION
 
 /* the git tag / commit we build from */
-#define VERSION "0.263"
+#define VERSION "0.264"
 
 #endif	/* SPRINGLOBBY_HEADERGUARD_CONFIG_H */
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 55e64bd..21c54c1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,5 +1,3 @@
-INCLUDE(compat_flags)
-
 
 # Add Definitions, Compiler-Switches, etc.: -Wall -O2 -g3 ...
 # MSVC compiler (cl.exe) does not accept the same switches as gcc, although preprocessor definitions in the -D form will work for both
@@ -161,6 +159,7 @@ ENDIF( OPTION_NOTIFY AND NOT WIN32 )
 
 
 set(springlobbySrc
+	address.cpp
 	autohost.cpp
 	autohostmanager.cpp
 	battlelist.cpp
@@ -301,7 +300,6 @@ set(springlobbySrc
 
 
 	downloader/lib/src/lsl/lsl/battle/tdfcontainer.cpp #FIXME
-	downloader/lib/src/lsl/lslutils/conversion.cpp #FIXME
 
 	gui/uiutils.cpp
 	gui/controls.cpp
diff --git a/src/address.cpp b/src/address.cpp
new file mode 100644
index 0000000..1c80f58
--- /dev/null
+++ b/src/address.cpp
@@ -0,0 +1,109 @@
+/* This file is part of the Springlobby (GPL v2 or later), see COPYING */
+
+#include "address.h"
+
+#ifdef _WIN32
+#include <iphlpapi.h>
+#elif defined(linux)
+#include <sys/ioctl.h>
+#include <net/if.h>
+#endif
+
+#if defined(WIN32) || defined(_WIN32)
+
+bool GetMacType(std::vector<unsigned char>& mac, const unsigned int mactype)
+{
+	IP_ADAPTER_INFO AdapterInfo[16];      // Allocate information for 16 cards
+	DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
+
+	DWORD dwStatus = GetAdaptersInfo(AdapterInfo, &dwBufLen); // Get info
+	if (dwStatus == ERROR_BUFFER_OVERFLOW) {
+		return false;
+	}
+	if (dwStatus != NO_ERROR)
+		return false; // Check status
+
+	for (size_t i = 0; i < dwBufLen / sizeof(AdapterInfo); i++) {
+		if ((mactype != 0) && (AdapterInfo[i].Type != mactype)) //skip not wanted type
+			continue;
+		if (AdapterInfo[i].AddressLength == 0) {
+			continue;
+		}
+		mac.resize(AdapterInfo[i].AddressLength);
+		mac.assign(AdapterInfo[i].Address, AdapterInfo[i].Address + AdapterInfo[i].AddressLength);
+		for (size_t j = 0; j < mac.size(); j++) {
+			if (mac[j] != 0) {
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+
+bool GetMac(std::vector<unsigned char>& mac)
+{
+	if (GetMacType(mac, MIB_IF_TYPE_ETHERNET))
+		return true;
+	if (GetMacType(mac, IF_TYPE_IEEE80211))
+		return true;
+	return (GetMacType(mac, 0));
+}
+
+#elif defined(__APPLE__)
+
+bool GetMac(std::vector<unsigned char>& mac)
+{
+	//FIXME: implement this, http://lists.freebsd.org/pipermail/freebsd-hackers/2004-June/007415.html
+	return false;
+}
+
+#else
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include <ifaddrs.h>
+
+bool GetMac(std::vector<unsigned char>& mac)
+{
+	ifaddrs* ifap = 0;
+	if (getifaddrs(&ifap) == 0) {
+		ifaddrs* iter = ifap;
+		while (iter) {
+			sockaddr_ll* sal = reinterpret_cast<sockaddr_ll*>(iter->ifa_addr);
+			if (sal->sll_family == AF_PACKET) {
+				mac.resize(sal->sll_halen);
+				mac.assign(sal->sll_addr, sal->sll_addr + sal->sll_halen);
+				for (size_t i = 0; i < mac.size(); i++) {
+					if (mac[i] != 0) {
+						freeifaddrs(ifap);
+						return true;
+					}
+				}
+			}
+			iter = iter->ifa_next;
+		}
+		freeifaddrs(ifap);
+	}
+	return false;
+}
+
+#endif
+
+std::string MacToString(std::vector<unsigned char>& mac)
+{
+	std::string res;
+	for (size_t i = 0; i < mac.size(); i++) {
+		char buf[3];
+		snprintf(buf, sizeof(buf), "%02X", mac[i]);
+		if (!res.empty())
+			res += ":";
+		res.append(buf, 2);
+	}
+	return res;
+}
+
diff --git a/src/address.h b/src/address.h
new file mode 100644
index 0000000..207b5b9
--- /dev/null
+++ b/src/address.h
@@ -0,0 +1,5 @@
+#include <string>
+#include <vector>
+
+bool GetMac(std::vector<unsigned char>& mac);
+std::string MacToString(std::vector<unsigned char>& mac);
diff --git a/src/autohost.cpp b/src/autohost.cpp
index 64677e6..54a479c 100644
--- a/src/autohost.cpp
+++ b/src/autohost.cpp
@@ -225,7 +225,7 @@ void AutoHost::OnUserAdded(User& user)
 	// do nothing if autohost functionality is disabled
 	if (!m_enabled)
 		return;
-	m_battle.DoAction(stdprintf("Hi %s, this battle is in %s autohost mode. For help say !help", user.GetNick().c_str(), getSpringlobbyVersion().c_str()));
+	m_battle.DoAction(stdprintf("Hi %s, this battle is in %s autohost mode. For help say !help", user.GetNick().c_str(), GetSpringlobbyVersion().c_str()));
 }
 
 
diff --git a/src/autohostmanager.cpp b/src/autohostmanager.cpp
index 5ac5bd9..e1e3a5b 100644
--- a/src/autohostmanager.cpp
+++ b/src/autohostmanager.cpp
@@ -87,6 +87,11 @@ void SpringieHandler::Promote()
 	// TODO
 }
 
+void SpringieHandler::Ring()
+{
+	Send("!ring");
+}
+
 void SpringieHandler::Start()
 {
 	Send("!start");
@@ -139,6 +144,11 @@ void SpadsHandler::Promote()
 	Send("!promote");
 }
 
+void SpadsHandler::Ring()
+{
+	Send("!ring");
+}
+
 void SpadsHandler::Start()
 {
 	Send("!start");
diff --git a/src/autohostmanager.h b/src/autohostmanager.h
index 342471f..0c5dcde 100644
--- a/src/autohostmanager.h
+++ b/src/autohostmanager.h
@@ -20,6 +20,7 @@ public:
 	virtual void AddStartBox(int /*posx*/, int /*posy*/, int /*w*/, int /*h*/){};
 	virtual void Notify(){};
 	virtual void Promote(){};
+	virtual void Ring(){};
 	virtual void Start(){};
 	void SetBattle(IBattle* battle);
 
@@ -47,6 +48,7 @@ public:
 	void AddStartBox(int posx, int posy, int w, int h) override;
 	void Notify() override;
 	void Promote() override;
+	void Ring() override;
 	void Start() override;
 };
 
@@ -63,6 +65,7 @@ public:
 	void AddStartBox(int posx, int posy, int w, int h) override;
 	void Notify() override;
 	void Promote() override;
+	void Ring() override;
 	void Start() override;
 };
 
diff --git a/src/battle.cpp b/src/battle.cpp
index ab15f51..4ccc331 100644
--- a/src/battle.cpp
+++ b/src/battle.cpp
@@ -331,13 +331,11 @@ void Battle::RingNotSyncedPlayers()
 
 void Battle::RingNotSyncedAndNotReadyPlayers()
 {
-	for (user_map_t::size_type i = 0; i < GetNumUsers(); i++) {
-		User& u = GetUser(i);
-		UserBattleStatus& bs = u.BattleStatus();
-		if (bs.IsBot())
-			continue;
-		if ((!bs.sync || !bs.ready) && !bs.spectator)
-			m_serv.Ring(u.GetNick());
+	if (IsFounderMe()) {
+		RingNotReadyPlayers();
+		RingNotSyncedPlayers();
+	} else {
+		m_autohost_manager->GetAutohostHandler().Ring();
 	}
 }
 
diff --git a/src/channel.cpp b/src/channel.cpp
index c47bc89..65ad1d3 100644
--- a/src/channel.cpp
+++ b/src/channel.cpp
@@ -222,7 +222,7 @@ bool Channel::ExecuteSayCommand(const std::string& in)
 		return true;
 	} else if (param == _T("/sayver")) {
 		//!this instance is not replaced with GetAppname for sake of help/debug online
-		DoAction("is using SpringLobby v" + getSpringlobbyVersion());
+		DoAction("is using " + GetSpringlobbyAgent());
 		return true;
 	} else if (subcmd == _T("/userban")) {
 		m_banned_users.insert(params);
diff --git a/src/downloader/lib/CMakeLists.txt b/src/downloader/lib/CMakeLists.txt
index 112efc5..a897566 100644
--- a/src/downloader/lib/CMakeLists.txt
+++ b/src/downloader/lib/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 2.8.11)
+cmake_minimum_required(VERSION 3.1)
 project(pr-downloader)
 
 
@@ -46,16 +46,8 @@ if(PRD_CLEAR_COMPILER_FLAGS)
 	SET(CMAKE_SHARED_LINKER_FLAGS "")
 endif()
 
-include(CheckCXXCompilerFlag)
-CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
-CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
-if(COMPILER_SUPPORTS_CXX11)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
-elseif(COMPILER_SUPPORTS_CXX0X)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
-else()
-        message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
-endif()
+set(CMAKE_CXX_STANDARD 11)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
 MESSAGE(STATUS "PR-Downloader version: ${PR_DOWNLOADER_VERSION}")
 if   (MINGW)
@@ -113,6 +105,26 @@ else()
 	find_package(ZLIB REQUIRED)
 endif()
 
+find_program(CURL_CONFIG_EXECUTABLE NAMES curl-config ONLY_CMAKE_FIND_ROOT_PATH)
+if (wxWidgets_CONFIG_EXECUTABLE-NOTFOUND)
+        message(FATAL_ERROR "couldn't find curl-config!")
+else()
+        message(STATUS "found curl-config: ${CURL_CONFIG_EXECUTABLE}")
+endif()
+
+if (PREFER_STATIC_LIBS)
+	set(CURLSTATIC "--static")
+else()
+	set(CURLSTATIC "")
+endif()
+
+execute_process(COMMAND ${CURL_CONFIG_EXECUTABLE} "--libs" ${CURLSTATIC}
+        OUTPUT_VARIABLE CURL_LD_FLAGS
+        OUTPUT_STRIP_TRAILING_WHITESPACE )
+message(STATUS "Using CURL_LD_FLAGS: ${CURL_LD_FLAGS}")
+
+
+
 if (PRD_JSONCPP_INTERNAL)
         # use bundled JsonCpp
         set(PRD_JSONCPP_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src/lib/jsoncpp/include)
diff --git a/src/downloader/lib/src/CMakeLists.txt b/src/downloader/lib/src/CMakeLists.txt
index 29df0a7..54f7cde 100644
--- a/src/downloader/lib/src/CMakeLists.txt
+++ b/src/downloader/lib/src/CMakeLists.txt
@@ -32,7 +32,6 @@ add_library(Downloader STATIC
 	FileSystem/HashSHA1.cpp
 	FileSystem/IHash.cpp
 	Util.cpp
-	Logger.cpp
 	Version.cpp
 	lib/base64/base64.cpp
 	${archivessrc}
@@ -59,6 +58,7 @@ set(PRDOWNLOADER_LIBS
 
 target_link_libraries(Downloader
 	${CURL_LIBRARIES}
+	${CURL_LD_FLAGS}
 	${OPENSSL_LIBRARIES}
 	${WIN32LIBS}
 	${PRD_JSONCPP_LIBRARIES}
@@ -82,17 +82,13 @@ set (PRDOWNLOADER "pr-downloader")
 set (PRDOWNLOADER_SHARED ${PRDOWNLOADER}_shared)
 set (PRDOWNLOADER_STATIC ${PRDOWNLOADER}_static)
 
-
-
-
-
-
 OPTION(PRD_SHAREDLIB
 	"Enables compilation of the shared lib" ON)
 
 if (PRD_SHAREDLIB)
 	add_library(${PRDOWNLOADER_SHARED} SHARED
 		pr-downloader.cpp
+		Logger.cpp
 	)
 	if(PRD_DO_INSTALL AND (PRD_DEVELOP_FILES OR (PRD_CONSOLETOOL AND NOT PRD_LINK_STATIC)))
 		INSTALL (TARGETS ${PRDOWNLOADER_SHARED}
@@ -132,6 +128,7 @@ if (PRD_CONSOLETOOL)
 	add_executable(${PRDOWNLOADER}
 		${PRD_ICON}
 		main.cpp
+		Logger.cpp
 	)
 
 	if (PRD_LINK_STATIC)
diff --git a/src/downloader/lib/src/Downloader/CurlWrapper.cpp b/src/downloader/lib/src/Downloader/CurlWrapper.cpp
index e727f2c..981bf13 100644
--- a/src/downloader/lib/src/Downloader/CurlWrapper.cpp
+++ b/src/downloader/lib/src/Downloader/CurlWrapper.cpp
@@ -21,16 +21,17 @@ CurlWrapper::CurlWrapper()
 	curl_easy_setopt(handle, CURLOPT_FAILONERROR, true);
 	curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
 
-	list = NULL;
+	list = nullptr;
 	list = curl_slist_append(list, "Cache-Control: no-cache");
 	curl_easy_setopt(handle, CURLOPT_HTTPHEADER, list);
 }
 
 CurlWrapper::~CurlWrapper()
 {
-	curl_easy_cleanup(handle);
-	handle = NULL;
 	curl_slist_free_all(list); /* free the list again */
+	curl_easy_cleanup(handle);
+	handle = nullptr;
+	list = nullptr;
 }
 
 std::string CurlWrapper::escapeUrl(const std::string& url)
diff --git a/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp b/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp
index 62ac84b..a0fb84b 100644
--- a/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp
+++ b/src/downloader/lib/src/Downloader/Rapid/RapidDownloader.cpp
@@ -83,7 +83,8 @@ bool CRapidDownloader::download_name(IDownload* download, int reccounter,
 			continue;
 		downloaded.insert(sdp.getMD5());
 
-		LOG_DOWNLOAD(sdp.getName().c_str());
+		LOG_INFO ("[Download] %s", sdp.getName().c_str());
+
 		if (!sdp.download(download)) {
 			return false;
 		}
diff --git a/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp b/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp
index 8108865..5836fbc 100644
--- a/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp
+++ b/src/downloader/lib/src/Downloader/Rapid/Sdp.cpp
@@ -149,13 +149,11 @@ bool CSdp::download(IDownload* dl)
         the filename is read from the sdp-list (created at request start)
         filesize is read from the http-data received (could overlap!)
 */
-static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
+static size_t write_streamed_data(const void* buf, size_t size, size_t nmemb,
 				  CSdp* sdp)
 {
 	if (IDownloader::AbortDownloads())
 		return -1;
-	char buf[CURL_MAX_WRITE_SIZE];
-	memcpy(&buf, tmp, CURL_MAX_WRITE_SIZE);
 	if (!sdp->downloadInitialized) {
 		sdp->list_it = sdp->files.begin();
 		sdp->downloadInitialized = true;
@@ -163,9 +161,9 @@ static size_t write_streamed_data(const void* tmp, size_t size, size_t nmemb,
 		sdp->file_name = "";
 		sdp->skipped = 0;
 	}
-	char* buf_start = (char*)&buf;
+	const char* buf_start = (const char*)buf;
 	const char* buf_end = buf_start + size * nmemb;
-	char* buf_pos = buf_start;
+	const char* buf_pos = buf_start;
 
 	while (buf_pos < buf_end) {		// all bytes written?
 		if (sdp->file_handle == NULL) { // no open file, create one
diff --git a/src/downloader/lib/src/Logger.cpp b/src/downloader/lib/src/Logger.cpp
index b70d77e..8553ae3 100644
--- a/src/downloader/lib/src/Logger.cpp
+++ b/src/downloader/lib/src/Logger.cpp
@@ -1,10 +1,54 @@
 /* This file is part of pr-downloader (GPL v2 or later), see the LICENSE file */
 
 #include "Logger.h"
-#include "Util.h"
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <time.h>
+
+// Logging functions in standalone mode
+// prdLogRaw is supposed to flush after printing (mostly to stdout/err
+// for progress bars and such).
+static void prdLogRaw(const char* /*fileName*/, int /*line*/, const char* /*funcName*/,
+                    const char* format, va_list args)
+{
+	vprintf(format, args);
+	fflush(stdout);
+}
+
+// Normal logging
+static void prdLogError(const char* fileName, int line, const char* funcName,
+                      const char* format, va_list args)
+{
+	fprintf(stderr, "[Error] %s:%d:%s():", fileName, line, funcName);
+	vfprintf(stderr, format, args);
+	fprintf(stderr, "\n");
+}
+
+static void prdLogWarn(const char* fileName, int line, const char* funcName,
+                      const char* format, va_list args)
+{
+	printf("[Warn] %s:%d:%s():", fileName, line, funcName);
+	vprintf(format, args);
+	printf("\n");
+}
+
+static void prdLogInfo(const char* fileName, int line, const char* funcName,
+                     const char* format, va_list args)
+{
+	printf("[Info] %s:%d:%s():", fileName, line, funcName);
+	vprintf(format, args);
+	printf("\n");
+}
+
+static void prdLogDebug(const char* fileName, int line, const char* funcName,
+                      const char* format, va_list args)
+{
+	printf("[Debug] %s:%d:%s():", fileName, line, funcName);
+	vprintf(format, args);
+	printf("\n");
+}
+
 
 static bool logEnabled = true;
 
@@ -13,7 +57,8 @@ void LOG_DISABLE(bool disableLogging)
 	logEnabled = !disableLogging;
 }
 
-void L_LOG(L_LEVEL level, const char* format...)
+extern void L_LOG(const char* fileName, int line, const char* funName,
+           L_LEVEL level, const char* format...)
 {
 	if (!logEnabled) {
 		return;
@@ -23,46 +68,35 @@ void L_LOG(L_LEVEL level, const char* format...)
 	va_start(args, format);
 	switch (level) {
 		case L_RAW:
-			vprintf(format, args);
-			fflush(stdout);
+			prdLogRaw(fileName, line, funName, format, args);
 			break;
 		default:
 		case L_ERROR:
-			fprintf(stderr, "[Error] ");
-			vfprintf(stderr, format, args);
-			fprintf(stderr, "\n");
+			prdLogError(fileName, line, funName, format, args);
+			break;
+		case L_WARN:
+			prdLogWarn(fileName, line, funName, format, args);
 			break;
 		case L_INFO:
-			printf("[Info] ");
-			vprintf(format, args);
-			printf("\n");
+			prdLogInfo(fileName, line, funName, format, args);
 			break;
 		case L_DEBUG:
-			printf("[Debug] ");
-			vprintf(format, args);
-			printf("\n");
+			prdLogDebug(fileName, line, funName, format, args);
 			break;
 	}
 	va_end(args);
 }
 
-void LOG_DOWNLOAD(const char* filename)
-{
-	L_LOG(L_RAW, "[Download] %s\n", filename);
-}
-
-void LOG_PROGRESS(long done, long total, bool forceOutput)
+extern void LOG_PROGRESS(long done, long total, bool forceOutput)
 {
-	static unsigned long lastlogtime = 0;
+	static time_t lastlogtime = 0;
 	static float lastPercentage = 0.0f;
 
 	if (!logEnabled) {
 		return;
 	}
 
-	unsigned long now = getTime(); // needs to be here atm to avoid static link
-				       // failure because of circular deps between
-				       // libs
+	const time_t now = time(nullptr);
 
 	if (lastlogtime < now) {
 		lastlogtime = now;
@@ -81,17 +115,17 @@ void LOG_PROGRESS(long done, long total, bool forceOutput)
 		return;
 	lastPercentage = percentage;
 
-	L_LOG(L_RAW, "[Progress] %3.0f%% [", percentage * 100.0f);
+	LOG("[Progress] %3.0f%% [", percentage * 100.0f);
 	int totaldotz = 30; // how wide you want the progress meter to be
 	int dotz = percentage * totaldotz;
 	for (int i = 0; i < totaldotz; i++) {
 		if (i >= dotz)
-			printf(" "); // blank
+			LOG(" "); // blank
 		else
-			printf("="); // full
+			LOG("="); // full
 	}
 	// and back to line begin - do not forget the fflush to avoid output buffering
 	// problems!
-	L_LOG(L_RAW, "] %ld/%ld ", done, total);
-	L_LOG(L_RAW, "\r");
+	LOG("] %ld/%ld ", done, total);
+	LOG("\r");
 }
diff --git a/src/downloader/lib/src/Logger.h b/src/downloader/lib/src/Logger.h
index 0425151..85239d2 100644
--- a/src/downloader/lib/src/Logger.h
+++ b/src/downloader/lib/src/Logger.h
@@ -3,8 +3,6 @@
 #ifndef LOGGER_H
 #define LOGGER_H
 
-#include <stdio.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -15,39 +13,42 @@ enum L_LEVEL {
 	L_ERROR = 1,
 	L_RAW = 2,
 	L_INFO = 3,
-	L_DEBUG = 4
+	L_WARN = 4,
+	L_DEBUG = 5,
 };
 
 /**
 	*	plain log output
 	*/
-void L_LOG(L_LEVEL level, const char* format, ...);
+extern void L_LOG(const char* fileName, int line, const char* funcName,
+           L_LEVEL level, const char* format, ...);
 
 #define LOG(...) \
-	L_LOG(L_RAW, __VA_ARGS__)
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_RAW, __VA_ARGS__)
 
-#define LOG_ERROR(fmt, ...) \
-	L_LOG(L_ERROR, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__)
+#define LOG_ERROR(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_ERROR, __VA_ARGS__)
 
 #define LOG_INFO(...) \
-	L_LOG(L_INFO, __VA_ARGS__)
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_INFO, __VA_ARGS__)
+
+#define LOG_WARN(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_WARN, __VA_ARGS__)
 
 #ifndef NDEBUG
-#define LOG_DEBUG(fmt, ...) \
-	L_LOG(L_DEBUG, "%s:%d:%s(): " fmt, __FILE__, __LINE__, __FUNCTION__, ##__VA_ARGS__);
+#define LOG_DEBUG(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_DEBUG, __VA_ARGS__);
 #else
 #define LOG_DEBUG(fmt, ...)
 #endif
 
-void LOG_DOWNLOAD(const char* filename);
-
 /**
 	*	output progress bar
 	*	@param done bytes already downloaded
 	*	@param total total bytes to download
 	*	@param forceOutput force output
 	*/
-void LOG_PROGRESS(long done, long total, bool forceOutput = false);
+extern void LOG_PROGRESS(long done, long total, bool forceOutput = false);
 
 #ifdef __cplusplus
 }
diff --git a/src/downloader/lib/src/Util.cpp b/src/downloader/lib/src/Util.cpp
index 40a34f3..5025ba1 100644
--- a/src/downloader/lib/src/Util.cpp
+++ b/src/downloader/lib/src/Util.cpp
@@ -4,10 +4,8 @@
 #include "FileSystem/FileSystem.h"
 #include "Logger.h"
 
-#include <stdio.h>
 #include <string.h>
 #include <zlib.h>
-#include <time.h>
 
 std::vector<std::string> tokenizeString(const std::string& str, char c)
 {
@@ -95,11 +93,6 @@ bool urlToPath(const std::string& url, std::string& path)
 	return true;
 }
 
-unsigned long getTime()
-{
-	return time(NULL);
-}
-
 #ifdef WIN32
 #include <windows.h>
 std::wstring s2ws(const std::string& s)
diff --git a/src/downloader/lib/src/Util.h b/src/downloader/lib/src/Util.h
index 385a8f9..0a6377e 100644
--- a/src/downloader/lib/src/Util.h
+++ b/src/downloader/lib/src/Util.h
@@ -45,11 +45,6 @@ unsigned int intmin(int x, int y);
 */
 bool urlToPath(const std::string& url, std::string& path);
 
-/**
- *	returns the time
- */
-unsigned long getTime();
-
 /*
         convert std::wstring to std::string
 */
diff --git a/src/downloader/lib/src/lsl/lslextract/CMakeLists.txt b/src/downloader/lib/src/lsl/lslextract/CMakeLists.txt
index faf71f0..6ac652e 100644
--- a/src/downloader/lib/src/lsl/lslextract/CMakeLists.txt
+++ b/src/downloader/lib/src/lsl/lslextract/CMakeLists.txt
@@ -8,6 +8,7 @@ add_executable(lslextract
 	server/request_parser.cpp
 	server/reply.cpp
 	server/mime_types.cpp
+	${pr-downloader_SOURCE_DIR}/src/Logger.cpp
 )
 FIND_PACKAGE(PNG REQUIRED)
 FIND_PACKAGE(X11 REQUIRED)
@@ -24,7 +25,7 @@ TARGET_LINK_LIBRARIES(lslextract
 )
 
 target_include_directories(lslextract
-	PRIVATE ${libSpringLobby_SOURCE_DIR}/src
-	PRIVATE ${LSL_JSONCPP_INCLUDE_DIR}
+	PRIVATE ${pr-downloader_SOURCE_DIR}/src/lsl
+	PRIVATE ${PRD_JSONCPP_INCLUDE_DIR}
 )
 
diff --git a/src/downloader/lib/src/lsl/lslextract/index.html b/src/downloader/lib/src/lsl/lslextract/index.html
index ee023f9..7080762 100644
--- a/src/downloader/lib/src/lsl/lslextract/index.html
+++ b/src/downloader/lib/src/lsl/lslextract/index.html
@@ -86,7 +86,7 @@ showResult("/maps");
 lslextract is a tool to extract metadata from spring engine content files
 </p>
 <h2>homepage</h2>
-<a href="https://github.com/springlobby/lsl">https://github.com/springlobby/lsl</a>
+<a href="https://github.com/spring/pr-downloader">https://github.com/spring/pr-downloader</a>
 </div>
 <div>
 <h2>List of local content files</h2>
diff --git a/src/downloader/lib/src/lsl/lslextract/lslextract.cpp b/src/downloader/lib/src/lsl/lslextract/lslextract.cpp
index 4fa88d1..78dd29b 100644
--- a/src/downloader/lib/src/lsl/lslextract/lslextract.cpp
+++ b/src/downloader/lib/src/lsl/lslextract/lslextract.cpp
@@ -77,7 +77,7 @@ int main(int argc, char* argv[])
 		return 1;
 	}
 
-	LSL::Util::config().ConfigurePaths(argv[1], argv[2], "");
+	LSL::Util::config().ConfigurePaths(argv[1], argv[2], "", "");
 	LSL::usync().LoadUnitSyncLib(argv[2]);
 
 	runServer("localhost", "9200", "");
diff --git a/src/downloader/lib/src/lsl/lslunitsync/image.cpp b/src/downloader/lib/src/lsl/lslunitsync/image.cpp
index 7a4940a..085b63b 100644
--- a/src/downloader/lib/src/lsl/lslunitsync/image.cpp
+++ b/src/downloader/lib/src/lsl/lslunitsync/image.cpp
@@ -251,11 +251,11 @@ bool UnitsyncImage::Load(const std::string& path) const
 		fclose(f);
 	} catch (cimg_library::CImgIOException& c) {
 		m_data_ptr->clear();
-		LslError("%s:%d (%s) %s failed: %s", __FILE__, __LINE__, __FUNCTION__, path.c_str(), c.what());
+		LslWarning("%s:%d (%s) %s failed: %s", __FILE__, __LINE__, __FUNCTION__, path.c_str(), c.what());
 		return false;
 	} catch (cimg_library::CImgException& c) {
 		m_data_ptr->clear();
-		LslError("%s:%d (%s) %s failed: %s", __FILE__, __LINE__, __FUNCTION__, path.c_str(), c.what());
+		LslWarning("%s:%d (%s) %s failed: %s", __FILE__, __LINE__, __FUNCTION__, path.c_str(), c.what());
 		return false;
 	}
 	return true;
diff --git a/src/downloader/lib/src/lsl/lslutils/logging.h b/src/downloader/lib/src/lsl/lslutils/logging.h
index 157e52d..fcbee21 100644
--- a/src/downloader/lib/src/lsl/lslutils/logging.h
+++ b/src/downloader/lib/src/lsl/lslutils/logging.h
@@ -1,27 +1,18 @@
 #ifndef LSL_LOGGING_H
 #define LSL_LOGGING_H
 
-extern void lsllogdebug(const char* format, ...);
-extern void lslloginfo(const char* format, ...);
-extern void lsllogwarning(const char* format, ...);
-extern void lsllogerror(const char* format, ...);
+#include "../../Logger.h"
 
-#define LslDebug(...)                     \
-	do {                              \
-		lsllogdebug(__VA_ARGS__); \
-	} while (0)
-#define LslInfo(...)                     \
-	do {                                \
-		lslloginfo(__VA_ARGS__); \
-	} while (0)
-#define LslWarning(...)                     \
-	do {                                \
-		lsllogwarning(__VA_ARGS__); \
-	} while (0)
-#define LslError(...)                     \
-	do {                              \
-		lsllogerror(__VA_ARGS__); \
-	} while (0)
+#define LslDebug(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_DEBUG, __VA_ARGS__);
 
+#define LslInfo(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_INFO, __VA_ARGS__);
+
+#define LslWarning(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_WARN, __VA_ARGS__);
+
+#define LslError(...) \
+	L_LOG(__FILE__, __LINE__, __FUNCTION__, L_ERROR, __VA_ARGS__);
 
 #endif // LSL_LOGGING_H
diff --git a/src/downloader/lib/src/main.cpp b/src/downloader/lib/src/main.cpp
index cff2d07..dcabe8b 100644
--- a/src/downloader/lib/src/main.cpp
+++ b/src/downloader/lib/src/main.cpp
@@ -10,7 +10,6 @@
 #include <unistd.h>
 #include <string>
 #include <getopt.h>
-#include <stdio.h>
 #include <list>
 
 // TODO: Many of these enums are not implemented.
@@ -198,7 +197,7 @@ int main(int argc, char** argv)
 				break;
 			}
 			case HTTP_SEARCH: {
-				printf("Not implemented\n");
+				LOG_ERROR("Not implemented");
 				break;
 			}
 			case HELP: {
diff --git a/src/downloader/lib/test/CMakeLists.txt b/src/downloader/lib/test/CMakeLists.txt
index c1165a2..864d236 100644
--- a/src/downloader/lib/test/CMakeLists.txt
+++ b/src/downloader/lib/test/CMakeLists.txt
@@ -13,6 +13,7 @@ Else()
 
 	SET(prd_testsrc
 		${CMAKE_CURRENT_SOURCE_DIR}/test.cpp
+		${pr-downloader_SOURCE_DIR}/src/Logger.cpp
 	)
 
 	ADD_EXECUTABLE(prd_test WIN32 MACOSX_BUNDLE ${prd_testsrc} )
@@ -40,6 +41,7 @@ if (PRD_ENABLE_LSL)
 SET(basic_testSrc
 	${CMAKE_CURRENT_SOURCE_DIR}/lsl/basic.cpp
 	${CMAKE_CURRENT_SOURCE_DIR}/lsl/usync.cpp
+	${pr-downloader_SOURCE_DIR}/src/Logger.cpp
 	)
 
 ADD_EXECUTABLE(libSpringLobby_test WIN32 MACOSX_BUNDLE ${basic_testSrc} )
diff --git a/src/downloader/lib/test/lsl/usync.cpp b/src/downloader/lib/test/lsl/usync.cpp
index d96fb3a..771740e 100644
--- a/src/downloader/lib/test/lsl/usync.cpp
+++ b/src/downloader/lib/test/lsl/usync.cpp
@@ -8,15 +8,10 @@
 #include <cmath>
 #include <iostream>
 
-extern void lsllogerror(char const*, ...)
-{
-}
-extern void lsllogdebug(char const*, ...)
-{
-}
-extern void lsllogwarning(char const*, ...)
-{
-}
+extern void lsllogerror(char const*, ...){}
+extern void lsllogdebug(char const*, ...){}
+extern void lsllogwarning(char const*, ...){}
+extern void lslloginfo(char const*, ...){}
 
 void dummySync()
 {
diff --git a/src/downloader/prdownloader.cpp b/src/downloader/prdownloader.cpp
index 62b3ce9..ee4ca49 100644
--- a/src/downloader/prdownloader.cpp
+++ b/src/downloader/prdownloader.cpp
@@ -21,8 +21,8 @@
 #include "log.h"
 
 #include <list>
-#include <boost/thread/mutex.hpp>
 #include <memory>
+#include <mutex>
 #include <wx/log.h>
 #include <lslunitsync/unitsync.h>
 #include <lslutils/thread.h>
@@ -34,7 +34,7 @@ SLCONFIG("/Spring/PortableDownload", false, "true to download portable versions
 SLCONFIG("/Spring/RapidMasterUrl", "http://repos.springrts.com/repos.gz", "master url for rapid downloads");
 
 static PrDownloader::DownloadProgress* m_progress = nullptr;
-static boost::mutex dlProgressMutex;
+static std::mutex dlProgressMutex;
 
 class DownloadItem : public LSL::WorkItem
 {
@@ -58,7 +58,7 @@ public:
 		wxLogInfo("Starting download of filename: %s, name: %s", m_filename.c_str(), m_name.c_str());
 
 		{
-			boost::mutex::scoped_lock lock(dlProgressMutex);
+			std::lock_guard<std::mutex> lock(dlProgressMutex);
 
 			if (m_progress == nullptr)
 				m_progress = new PrDownloader::DownloadProgress();
@@ -186,7 +186,7 @@ private:
 
 void PrDownloader::GetProgress(DownloadProgress& progress)
 {
-	boost::mutex::scoped_lock lock(dlProgressMutex);
+	std::lock_guard<std::mutex> lock(dlProgressMutex);
 
 	if (m_progress == nullptr) {
 		assert(false);
@@ -227,7 +227,7 @@ int clock_gettime(int dummy, struct timespec *ct)
 
 void updatelistener(int downloaded, int filesize)
 {
-	boost::mutex::scoped_lock lock(dlProgressMutex);
+	std::lock_guard<std::mutex> lock(dlProgressMutex);
 
 	if (m_progress == nullptr)
 		m_progress = new PrDownloader::DownloadProgress();
@@ -267,6 +267,7 @@ PrDownloader::~PrDownloader()
 	GlobalEventManager::Instance()->UnSubscribeAll(this);
 
 	if (!!m_dl_thread) {
+		m_dl_thread->Wait();
 		delete m_dl_thread;
 		m_dl_thread = nullptr;
 	}
@@ -370,7 +371,7 @@ void PrDownloader::UpdateApplication(const std::string& updateurl)
 bool PrDownloader::DownloadUrl(const std::string& httpurl, std::string& res)
 {
 	{
-		boost::mutex::scoped_lock lock(dlProgressMutex);
+		std::lock_guard<std::mutex> lock(dlProgressMutex);
 		if (m_progress == nullptr)
 			m_progress = new PrDownloader::DownloadProgress();
 		m_progress->name = httpurl;
diff --git a/src/gui/aboutbox.cpp b/src/gui/aboutbox.cpp
index 3d90871..247be57 100644
--- a/src/gui/aboutbox.cpp
+++ b/src/gui/aboutbox.cpp
@@ -13,9 +13,10 @@ slAboutBox::slAboutBox()
 {
 	info = new wxAboutDialogInfo();
 
-	info->SetName(TowxString(getSpringlobbyName()));
-	info->SetVersion(TowxString(getSpringlobbyVersion()));
-	info->SetDescription(TowxString(getSpringlobbyName()) + _(" is a cross-platform lobby client for the Spring RTS engine"));
+	info->SetName(TowxString(GetSpringlobbyName()));
+	info->SetVersion(TowxString(GetSpringlobbyVersion()));
+	info->SetDescription(TowxString(GetSpringlobbyName())
+	  + _(" is a cross-platform lobby client for the Spring RTS engine"));
 	//info.SetCopyright(wxEmptyString;
 	info->SetWebSite(_T("http://springlobby.info"));
 	info->SetLicence(_T("GPL v2 or later"));
diff --git a/src/gui/chatpanel.cpp b/src/gui/chatpanel.cpp
index 5d1b1e1..5d2dd98 100644
--- a/src/gui/chatpanel.cpp
+++ b/src/gui/chatpanel.cpp
@@ -948,7 +948,7 @@ bool ChatPanel::Say(const wxString& message) //FIXME: remove all parsing / token
 
 		if (line == _T( "/ver" )) {
 			//!this instance is not replaced with GetAppname for sake of help/debug online
-			OutputLine(_("You have SpringLobby v") + TowxString(getSpringlobbyVersion()), sett().GetChatColorNormal());
+			OutputLine(wxString::Format(_("You have %s."), GetSpringlobbyAgent()), sett().GetChatColorNormal());
 			return true;
 		}
 
diff --git a/src/gui/hosting/battleroomtab.cpp b/src/gui/hosting/battleroomtab.cpp
index 36a536c..3532ccc 100644
--- a/src/gui/hosting/battleroomtab.cpp
+++ b/src/gui/hosting/battleroomtab.cpp
@@ -571,6 +571,8 @@ void BattleRoomTab::UpdateUser(User& user, bool userJustAdded)
 	m_ready_chk->SetValue(bs.ready);
 	// Enable or disable widgets' sensitivity as appropriate.
 	if (bs.spectator) {
+		m_start_btn->SetLabel(_("Spectate"));
+		m_start_btn->SetToolTip(_("Watch a running match (you are a spectator)"));
 		m_side_sel->Disable();
 		m_ally_sel->Disable();
 		m_team_sel->Disable();
@@ -586,6 +588,8 @@ void BattleRoomTab::UpdateUser(User& user, bool userJustAdded)
 			OnAutolaunch();
 		}
 	} else { // we are player
+		m_start_btn->SetLabel(_("Start"));
+		m_start_btn->SetToolTip(_("Start the battle"));
 		m_side_sel->Enable();
 		m_ally_sel->Enable();
 		m_team_sel->Enable();
@@ -625,42 +629,70 @@ void BattleRoomTab::OnPromote(wxCommandEvent& /*unused*/)
 	}
 }
 
+/*
+ * Running? Spec? Founder? Action
+ *    0       0      0     DL -> ready -> Ring -> OpponentCheck -> !start
+ *    0       0      1     DL -> ready -> Ring -> OpponentCheck -> StartHB
+ *    0       1      0     DL -> ready -> "Unspec to play"
+ *    0       1      1     DL -> ready -> "Unspec to play"
+ *    1       0      0     DL -> ready -> start
+ *    1       0      1     DL -> ready -> start
+ *    1       1      0     DL -> ready -> start
+ *    1       1      1     DL -> ready -> start
+ */
 void BattleRoomTab::OnStart(wxCommandEvent& /*unused*/)
 {
 	slLogDebugFunc("");
 	if (m_battle == nullptr)
 		return;
 
-	//start manually clicked, force start
-	m_battle->SetAutolaunchGame(true);
-
-	if (m_battle->IsFounderMe()) {
-		m_battle->GetMe().BattleStatus().ready = true;
-		if (!m_battle->IsEveryoneReady()) {
-			int answer = customMessageBox(SL_MAIN_ICON, _("Some Players are not ready yet\nDo you want to force start?"), _("Not ready"), wxYES_NO | wxCANCEL);
-			if (answer == wxNO)
-				return;
-		}
-
-		m_battle->SaveMapDefaults(); // save map presets
+	if (ui().IsSpringRunning()) {
+		customMessageBoxModal(SL_MAIN_ICON, _("You are already playing/spectating."), _("Error"));
+		return;
+	}
 
-		m_battle->StartHostedBattle();
-	} else {
-		if (ui().NeedsDownload(m_battle)) {
-			wxLogWarning("Cannot start, need to download first!");
-			return;
-		}
+	if (ui().NeedsDownload(m_battle)) {
+		customMessageBoxModal(SL_MAIN_ICON, _("You must download missing content before you"
+		  " can start or wait for the downloads to finish if they had been started already."),
+		  _("Error"));
+		return;
+	}
 
-		if (m_battle->GetFounder().Status().in_game) {
-			if (!ui().IsSpringRunning())
-				m_battle->StartSpring();
-			else
-				customMessageBoxModal(SL_MAIN_ICON, _("Spring is already running."), _("Error"));
-		} else {
-			m_battle->m_autohost_manager->GetAutohostHandler().Start();
-			//customMessageBoxNoModal( SL_MAIN_ICON, _("Host is not ingame."), _("Error") );
+	//start manually clicked, force start
+	m_battle->SetAutolaunchGame(true);
+	m_ready_chk->SetValue(true); OnImReady();
+
+	// Is remote battle running?
+	if (m_battle->GetFounder().Status().in_game) {
+		m_battle->StartSpring();
+	} else { // No, it is not running.
+		if (m_battle->GetMe().BattleStatus().spectator) {
+			customMessageBoxModal(SL_MAIN_ICON,
+			  _("No battle is running. You must be a player to start"), _("Error"));
+		} else { // I am a player
+			if (m_battle->IsEveryoneReady()) {
+				if (m_battle->DoesOpponentExist()) {
+					if (m_battle->IsFounderMe()) {
+						m_battle->SaveMapDefaults(); // save map presets
+						m_battle->StartHostedBattle();
+					} else {
+						m_battle->m_autohost_manager->GetAutohostHandler().Start();
+					}
+				} else {
+					customMessageBoxModal(SL_MAIN_ICON,
+					  _("A battle with no opponents is no battle at all" // ...
+					    " (Hint: add a bot and try again)."), _("Error"));
+				}
+			} else {
+				int answer = customMessageBox(SL_MAIN_ICON,
+				  _("Some players are not ready, ring them?"),
+				  _("Not ready"), wxYES | wxCANCEL);
+				if (answer == wxYES)
+					m_battle->RingNotSyncedAndNotReadyPlayers();
+			}
 		}
 	}
+
 	//reset to value from gui
 	m_battle->SetAutolaunchGame(m_autolaunch_chk->GetValue());
 }
@@ -763,13 +795,18 @@ void BattleRoomTab::OnAutolaunch()
 }
 
 
-void BattleRoomTab::OnImReady(wxCommandEvent& /*unused*/)
+void BattleRoomTab::OnImReady()
 {
 	if (!m_battle)
 		return;
 	m_battle->SetImReady(m_ready_chk->GetValue());
 }
 
+void BattleRoomTab::OnImReady(wxCommandEvent& /*unused*/)
+{
+	OnImReady();
+}
+
 
 void BattleRoomTab::OnLock(wxCommandEvent& /*unused*/)
 {
@@ -839,9 +876,21 @@ void BattleRoomTab::OnImSpec(wxCommandEvent& /*unused*/)
 {
 	if (!m_battle)
 		return;
-	m_battle->ForceSpectator(m_battle->GetMe(), m_spec_chk->GetValue());
-}
 
+	// Prevent taking same team ID as someone else when un-speccing.
+	if (m_spec_chk->IsChecked()) {
+		m_battle->ForceSpectator(m_battle->GetMe(), true);
+	} else {
+		int team = m_battle->GetFreeTeam(/*excludeme=*/false);
+		m_team_sel->SetSelection(team);
+		UserBattleStatus& myStatus = m_battle->GetMe().BattleStatus();
+		// Due to ForceSpectator working on a local copy, one way to implement this is by:
+		int oldteam = myStatus.team;
+		myStatus.team = team;
+		m_battle->ForceSpectator(m_battle->GetMe(), false);
+		myStatus.team = oldteam;
+	}
+}
 
 void BattleRoomTab::OnTeamSel(wxCommandEvent& /*unused*/)
 {
diff --git a/src/gui/hosting/battleroomtab.h b/src/gui/hosting/battleroomtab.h
index cf8871f..a604504 100644
--- a/src/gui/hosting/battleroomtab.h
+++ b/src/gui/hosting/battleroomtab.h
@@ -88,6 +88,7 @@ private:
 	{
 		OnAutolaunch();
 	}
+	void OnImReady();
 	void OnImReady(wxCommandEvent& event);
 	void OnLock(wxCommandEvent& event);
 	void OnAutoHost(wxCommandEvent& event);
diff --git a/src/gui/hosting/hostbattledialog.cpp b/src/gui/hosting/hostbattledialog.cpp
index edde619..d2fca9a 100644
--- a/src/gui/hosting/hostbattledialog.cpp
+++ b/src/gui/hosting/hostbattledialog.cpp
@@ -98,22 +98,20 @@ HostBattleDialog::HostBattleDialog(wxWindow* parent)
 	m_mod_lbl->Wrap(-1);
 	topsizer->Add(m_mod_lbl, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
 
-	wxArrayString m_engine_picChoices;
 	wxBoxSizer* mod_choice_button_sizer2 = new wxBoxSizer(wxHORIZONTAL);
-	m_engine_pic = new wxChoice(m_panel, CHOOSE_ENGINE, wxDefaultPosition, wxDefaultSize, m_engine_picChoices, 0);
-	m_engine_pic->SetToolTip(_("Select the engine version to play."));
-	mod_choice_button_sizer2->Add(m_engine_pic, 0, wxALL, 5);
+	m_engine_choice = new wxChoice(m_panel, CHOOSE_ENGINE);
+	m_engine_choice->SetToolTip(_("Select the engine version to play."));
+	mod_choice_button_sizer2->Add(m_engine_choice, 0, wxALL, 5);
 	topsizer->Add(mod_choice_button_sizer2, 0, wxEXPAND | wxALL, 1);
 
 	m_mod_lbl = new wxStaticText(m_panel, wxID_ANY, _("Game"), wxDefaultPosition, wxDefaultSize, 0);
 	m_mod_lbl->Wrap(-1);
 	topsizer->Add(m_mod_lbl, 0, wxALL | wxALIGN_CENTER_VERTICAL, 5);
 
-	wxArrayString m_mod_picChoices;
 	wxBoxSizer* mod_choice_button_sizer = new wxBoxSizer(wxHORIZONTAL);
-	m_mod_pic = new wxChoice(m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_mod_picChoices, 0);
-	m_mod_pic->SetToolTip(_("Select the game to play."));
-	mod_choice_button_sizer->Add(m_mod_pic, 0, wxALL, 5);
+	m_game_choice = new wxChoice(m_panel, wxID_ANY);
+	m_game_choice->SetToolTip(_("Select the game to play."));
+	mod_choice_button_sizer->Add(m_game_choice, 0, wxALL, 5);
 
 	wxBitmap mp = charArr2wxBitmap(arrow_refresh_png, sizeof(arrow_refresh_png));
 	m_refresh_btn = new wxBitmapButton(m_panel, BTN_REFRESH, mp);
@@ -293,39 +291,39 @@ HostBattleDialog::HostBattleDialog(wxWindow* parent)
 
 void HostBattleDialog::ReloadModList()
 {
-	m_mod_pic->Clear();
+	m_game_choice->Clear();
 
 	wxArrayString modlist = lslTowxArrayString(LSL::usync().GetGameList());
 	wxString last = sett().GetLastHostMod();
 
 	size_t nummods = modlist.Count();
 	for (size_t i = 0; i < nummods; i++) {
-		m_mod_pic->Insert(modlist[i], i);
+		m_game_choice->Insert(modlist[i], i);
 		if (last == modlist[i])
-			m_mod_pic->SetSelection(i);
+			m_game_choice->SetSelection(i);
 	}
 
-	if (m_mod_pic->GetSelection() == wxNOT_FOUND) {
-		m_mod_pic->SetSelection(0);
+	if (m_game_choice->GetSelection() == wxNOT_FOUND) {
+		m_game_choice->SetSelection(0);
 	}
 }
 
 void HostBattleDialog::ReloadEngineList()
 {
-	m_engine_pic->Clear();
+	m_engine_choice->Clear();
 	std::map<std::string, LSL::SpringBundle> versions = SlPaths::GetSpringVersionList();
 	const std::string last = SlPaths::GetCurrentUsedSpringIndex();
 	int i = 0;
 	for (auto pair : versions) {
-		m_engine_pic->Insert(TowxString(pair.first), i);
+		m_engine_choice->Insert(TowxString(pair.first), i);
 		if (last == pair.first) {
-			m_engine_pic->SetSelection(i);
+			m_engine_choice->SetSelection(i);
 		}
 		i++;
 	}
 
-	if (m_engine_pic->GetSelection() == wxNOT_FOUND) {
-		m_engine_pic->SetSelection(0);
+	if (m_engine_choice->GetSelection() == wxNOT_FOUND) {
+		m_engine_choice->SetSelection(0);
 	}
 	//unitsync change needs a refresh of games as well
 	ReloadModList();
@@ -334,13 +332,13 @@ void HostBattleDialog::ReloadEngineList()
 
 void HostBattleDialog::OnOk(wxCommandEvent& /*unused*/)
 {
-	if (m_mod_pic->GetSelection() == wxNOT_FOUND) {
+	if (m_game_choice->GetSelection() == wxNOT_FOUND) {
 		wxLogWarning(_T( "no game selected" ));
 		customMessageBox(SL_MAIN_ICON, _("You have to select a game first."), _("No game selected."), wxOK);
 		return;
 	}
 
-	if (m_engine_pic->GetSelection() == wxNOT_FOUND) {
+	if (m_engine_choice->GetSelection() == wxNOT_FOUND) {
 		wxLogWarning(_T( "no engine selected" ));
 		customMessageBox(SL_MAIN_ICON, _("You have to select a engine version first."), _("No engine selected."), wxOK);
 		return;
@@ -349,7 +347,7 @@ void HostBattleDialog::OnOk(wxCommandEvent& /*unused*/)
 	if (m_desc_text->GetValue().IsEmpty())
 		m_desc_text->SetValue(_T( "(none)" ));
 	sett().SetLastHostDescription(m_desc_text->GetValue());
-	sett().SetLastHostMod(m_mod_pic->GetString(m_mod_pic->GetSelection()));
+	sett().SetLastHostMod(m_game_choice->GetString(m_game_choice->GetSelection()));
 	wxString password = m_pwd_text->GetValue();
 	password.Replace(_T(" "), wxEmptyString);
 	sett().SetLastHostPassword(password);
@@ -439,7 +437,7 @@ void HostBattleDialog::OnUseRelay(wxCommandEvent&)
 
 void HostBattleDialog::OnEngineSelect(wxCommandEvent& /*event*/)
 {
-	SlPaths::SetUsedSpringIndex(STD_STRING(m_engine_pic->GetString(m_engine_pic->GetSelection())));
+	SlPaths::SetUsedSpringIndex(STD_STRING(m_engine_choice->GetString(m_engine_choice->GetSelection())));
 	LSL::usync().ReloadUnitSyncLib();
 	ReloadEngineList();
 }
diff --git a/src/gui/hosting/hostbattledialog.h b/src/gui/hosting/hostbattledialog.h
index 4c93985..51621ef 100644
--- a/src/gui/hosting/hostbattledialog.h
+++ b/src/gui/hosting/hostbattledialog.h
@@ -46,8 +46,8 @@ private:
 	wxStaticText* m_desc_lbl;
 	wxTextCtrl* m_desc_text;
 	wxStaticText* m_mod_lbl;
-	wxChoice* m_mod_pic;
-	wxChoice* m_engine_pic;
+	wxChoice* m_engine_choice;
+	wxChoice* m_game_choice;
 	wxStaticText* m_pwd_lbl;
 	wxTextCtrl* m_pwd_text;
 	wxChoice* m_rank_direction;
diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp
index a04a3c9..306b84f 100644
--- a/src/gui/mainwindow.cpp
+++ b/src/gui/mainwindow.cpp
@@ -117,7 +117,7 @@ EVT_COMMAND(mySHOW_ERROR_MESSAGE, wxEVT_SHOW, MainWindow::OnShowErrorMessage)
 END_EVENT_TABLE()
 
 MainWindow::MainWindow()
-    : wxFrame(NULL, -1, TowxString(getSpringlobbyName()))
+    : wxFrame(NULL, -1, TowxString(GetSpringlobbyName()))
     , WindowAttributesPickle(_T("MAINWINDOW"), this, wxSize(720, 576))
     , m_opts_dialog(NULL)
     , m_autojoin_dialog(NULL)
@@ -639,10 +639,10 @@ void MainWindow::OnMenuAutojoinChannels(wxCommandEvent& /*unused*/)
 void MainWindow::OnMenuSelectLocale(wxCommandEvent& /*unused*/)
 {
 	if (wxGetApp().SelectLanguage()) {
-		customMessageBoxModal(SL_MAIN_ICON,
-				      _("You need to restart SpringLobby for the language change to take effect."),
-				      _("Restart required"),
-				      wxICON_EXCLAMATION | wxOK);
+		customMessageBoxModal(SL_MAIN_ICON, wxString::Format(
+		  _("You need to restart %s for the language change to take effect."),
+		  GetSpringlobbyName()),
+		  _("Restart required"), wxICON_EXCLAMATION | wxOK);
 	}
 }
 
@@ -674,7 +674,8 @@ void MainWindow::OnMenuResetLayout(wxCommandEvent& /*event*/)
 {
 	cfg().Write(_T( "/ResetLayout" ), true);
 	sett().SaveSettings();
-	customMessageBoxModal(SL_MAIN_ICON, _("Please restart SpringLobby now"), wxEmptyString);
+	customMessageBoxModal(SL_MAIN_ICON, wxString::Format(
+	  _("Please restart %s now"), GetSpringlobbyName()), wxEmptyString);
 }
 
 const wxArrayString& MainWindow::GetTabNames()
@@ -728,7 +729,7 @@ void MainWindow::OnMenuPathInfo(wxCommandEvent& /*event*/)
 void MainWindow::OnMenuDownload(wxCommandEvent& /*event*/)
 {
 	wxString lines;
-	if (!ui().AskText(_("Which Archives to download? Put each archive on a single line, for example \ngame:ba:stable\nmap:The Rock Final\nengine:spring 98.0"), _("Download Archives"), lines, true))
+	if (!ui().AskText(_("Which Archives to download? Put each archive on a single line, for example") + _T("\ngame:ba:stable\nmap:The Rock Final\nengine:spring 104.0"), _("Download Archives"), lines, true))
 		return;
 	size_t start = 0;
 	int pos = 0;
diff --git a/src/gui/mapctrl.cpp b/src/gui/mapctrl.cpp
index 705ffd2..a13156e 100644
--- a/src/gui/mapctrl.cpp
+++ b/src/gui/mapctrl.cpp
@@ -1,5 +1,6 @@
 /* This file is part of the Springlobby (GPL v2 or later), see COPYING */
 
+#include <functional>
 #include <wx/panel.h>
 #include <wx/dcclient.h>
 #include <wx/bitmap.h>
@@ -101,7 +102,7 @@ static inline int ReadInt24(const unsigned char* p)
 
 MapCtrl::MapCtrl(wxWindow* parent, int size, IBattle* battle, bool readonly, bool draw_start_types, bool singleplayer)
     : wxPanel(parent, -1, wxDefaultPosition, wxSize(size, size), wxSIMPLE_BORDER | wxFULL_REPAINT_ON_RESIZE)
-    , m_async(boost::bind(&MapCtrl::OnGetMapImageAsyncCompleted, this, _1))
+    , m_async(std::bind(&MapCtrl::OnGetMapImageAsyncCompleted, this, std::placeholders::_1))
     , m_minimap(0)
     , m_metalmap(0)
     , m_heightmap(0)
diff --git a/src/gui/mapgridctrl.cpp b/src/gui/mapgridctrl.cpp
index 66e28d2..a244635 100644
--- a/src/gui/mapgridctrl.cpp
+++ b/src/gui/mapgridctrl.cpp
@@ -1,5 +1,6 @@
 /* This file is part of the Springlobby (GPL v2 or later), see COPYING */
 
+#include <functional>
 #include <wx/dcbuffer.h>
 #include <wx/geometry.h>
 #include <wx/settings.h>
@@ -46,8 +47,8 @@ const wxEventType MapGridCtrl::LoadingCompletedEvt = wxNewEventType();
 
 MapGridCtrl::MapGridCtrl(wxWindow* parent, wxSize size, wxWindowID id)
     : wxPanel(parent, id, wxDefaultPosition, size, wxSIMPLE_BORDER | wxFULL_REPAINT_ON_RESIZE)
-    , m_async_image(boost::bind(&MapGridCtrl::OnGetMapImageAsyncCompleted, this, _1))
-    , m_async_ex(boost::bind(&MapGridCtrl::OnGetMapExAsyncCompleted, this, _1))
+    , m_async_image(std::bind(&MapGridCtrl::OnGetMapImageAsyncCompleted, this, std::placeholders::_1))
+    , m_async_ex(std::bind(&MapGridCtrl::OnGetMapExAsyncCompleted, this, std::placeholders::_1))
     , m_async_ops_count(0)
     , m_selection_follows_mouse(sett().GetMapSelectorFollowsMouse())
     , m_size(0, 0)
@@ -366,6 +367,7 @@ void MapGridCtrl::DrawMap(wxDC& dc, MapData& map, int x, int y)
 		case MapState_NoMinimap:
 			map.priority = 1;
 			UpdateAsyncFetches();
+			[[fallthrough]];
 		// fall through, both when starting fetch and when waiting
 		// for it to finish, we want to show temporary image
 		case MapState_GetMinimap:
diff --git a/src/gui/notifications/libnotify.cpp b/src/gui/notifications/libnotify.cpp
index 06e897d..d7734e9 100644
--- a/src/gui/notifications/libnotify.cpp
+++ b/src/gui/notifications/libnotify.cpp
@@ -26,9 +26,9 @@ void LibnotifyNotification::Show(const wxBitmap& icon, const size_t /*pos*/, con
 	NotifyNotification* n;
 	notify_init("Test");
 #if !defined(NOTIFY_VERSION_MINOR) || (NOTIFY_VERSION_MAJOR == 0 && NOTIFY_VERSION_MINOR < 7)
-	n = notify_notification_new(getSpringlobbyName().c_str(), data.second.mb_str(), NULL, NULL);
+	n = notify_notification_new(GetSpringlobbyName().c_str(), data.second.mb_str(), NULL, NULL);
 #else
-	n = notify_notification_new(getSpringlobbyName().c_str(), data.second.mb_str(), NULL);
+	n = notify_notification_new(GetSpringlobbyName().c_str(), data.second.mb_str(), NULL);
 #endif
 	notify_notification_set_timeout(n, sett().GetNotificationPopupDisplayTime() * 1000);
 
diff --git a/src/gui/options/lobbyoptionstab.cpp b/src/gui/options/lobbyoptionstab.cpp
index 6ceccd0..2c06370 100644
--- a/src/gui/options/lobbyoptionstab.cpp
+++ b/src/gui/options/lobbyoptionstab.cpp
@@ -24,6 +24,7 @@
 #include "gui/mainwindow.h"
 #include "utils/conversion.h"
 #include "utils/uievents.h"
+#include "utils/version.h"
 #include "gui/notifications/notificationmanager.h"
 #include "utils/globalevents.h"
 
@@ -98,9 +99,9 @@ LobbyOptionsTab::LobbyOptionsTab(wxWindow* parent)
 	m_editor_box_sizer->Add(m_editor_loc_sizer, 0, wxEXPAND | wxALL, 2);
 	////////
 	wxStaticBoxSizer* m_autojoin_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Autoconnect"));
-	m_autoconnect_label = new wxStaticText(this,
-					       -1,
-					       _("If checked, SpringLobby will automatically log on to the last used server"));
+	m_autoconnect_label = new wxStaticText(this, -1, wxString::Format (
+	  _("If checked, %s will automatically log on to the last used server"),
+	  GetSpringlobbyName()));
 	m_autojoin = new wxCheckBox(this, -1, _("Autoconnect on lobby start"), wxDefaultPosition, wxDefaultSize, 0);
 	m_autojoin->SetValue(cfg().ReadBool(_T( "/Server/Autoconnect")));
 	m_autojoin_sizer->Add(m_autoconnect_label, 1, wxEXPAND | wxALL, 5);
@@ -109,9 +110,9 @@ LobbyOptionsTab::LobbyOptionsTab(wxWindow* parent)
 	m_main_sizer->Add(m_web_box_sizer, 0, wxEXPAND | wxALL, 5);
 	m_main_sizer->Add(m_editor_box_sizer, 0, wxEXPAND | wxALL, 5);
 	wxStaticBoxSizer* m_updater_sizer = new wxStaticBoxSizer(wxVERTICAL, this, _("Automatic updates"));
-	m_updater_label = new wxStaticText(this,
-					   -1,
-					   _("SpringLobby can check at startup if a newer version is available and automatically download it for you."));
+	m_updater_label = new wxStaticText(this, -1, wxString::Format(
+	  _("%s can check at startup if a newer version is available and automatically download it for you."),
+	  GetSpringlobbyName()));
 	m_updater = new wxCheckBox(this, -1, _("automatically check for updates"), wxDefaultPosition, wxDefaultSize, 0);
 	m_updater->SetValue(cfg().ReadBool(_T("/General/AutoUpdate")));
 	m_updater_sizer->Add(m_updater_label, 1, wxEXPAND | wxALL, 5);
@@ -124,7 +125,8 @@ LobbyOptionsTab::LobbyOptionsTab(wxWindow* parent)
 	m_show_tooltips = new wxCheckBox(this, -1, _("Show Tooltips?"), wxDefaultPosition, wxDefaultSize, 0);
 	m_show_tooltips->SetValue(sett().GetShowTooltips());
 #ifndef __WXMSW__ // on windows this change is immediate
-	m_show_tooltips_label = new wxStaticText(this, -1, _("Requires SpringLobby restart to take effect."));
+	m_show_tooltips_label = new wxStaticText(this, -1, wxString::Format(
+	  _("Requires %s restart to take effect."), GetSpringlobbyName()));
 	m_show_tooltips_sizer->Add(m_show_tooltips_label, 1, wxEXPAND | wxALL, 5);
 #endif
 	m_show_tooltips_sizer->Add(m_show_tooltips, 0, wxEXPAND | wxALL, 5);
diff --git a/src/gui/options/mainoptionstab.cpp b/src/gui/options/mainoptionstab.cpp
index 635d86d..abf7347 100644
--- a/src/gui/options/mainoptionstab.cpp
+++ b/src/gui/options/mainoptionstab.cpp
@@ -27,6 +27,7 @@
 #include "gui/uiutils.h"
 #include "gui/controls.h"
 #include "utils/conversion.h"
+#include "utils/version.h"
 #include "log.h"
 #include "utils/globalevents.h"
 
@@ -166,7 +167,9 @@ void MainOptionsTab::SavePerspective(const wxString& perspective_name)
 }
 
 OptionsDialog::OptionsDialog(wxWindow* parent)
-    : wxDialog(parent, -1, _("SpringLobby Preferences"), wxDefaultPosition, wxSize(1055, 620), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
+    : wxDialog(parent, -1, wxString::Format(_("%s Preferences"), GetSpringlobbyName()),
+	    wxDefaultPosition, wxSize(1055, 620),
+	    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxMAXIMIZE_BOX)
     , WindowAttributesPickle(_T("preferences"), this, wxSize(1055, 620))
 {
 	SetMinSize(wxSize(1055, 620));
diff --git a/src/gui/options/springoptionstab.cpp b/src/gui/options/springoptionstab.cpp
index 9af832e..7f55ec7 100644
--- a/src/gui/options/springoptionstab.cpp
+++ b/src/gui/options/springoptionstab.cpp
@@ -284,11 +284,17 @@ void SpringOptionsTab::OnAddBundle(wxCommandEvent& /*event*/)
 
 			if (!bundle.IsValid() || version.IsEmpty()) {
 				failed = true;
-				failMessage = wxString::Format(_T("%s did not find engine and unitsync executables at %s\n\nPlease ensure that both exist and that you have appropriate access privileges."), getSpringlobbyName().c_str(), bundle.path.c_str());
+				failMessage = wxString::Format(_T(
+				  "%s did not find engine and unitsync executables at %s\n\n"
+				  "Please ensure that both exist and that you have appropriate access privileges."
+				  ), GetSpringlobbyName().c_str(), bundle.path.c_str());
 			}
 		} catch (const LSL::Exceptions::unitsync& e) {
 			failed = true;
-			failMessage = wxString::Format(_T("%s could not obtain the version string from the shared library file %s\n\nPlease provide a valid unitsync file."), getSpringlobbyName().c_str(), bundle.unitsync.c_str());
+			failMessage = wxString::Format(_T(
+			  "%s could not obtain the version string from the shared library file %s\n\n"
+			  "Please provide a valid unitsync file."),
+			  GetSpringlobbyName().c_str(), bundle.unitsync.c_str());
 		}
 		if (failed) {
 			customMessageBox(SL_MAIN_ICON, failMessage, _("Configuration error"), wxOK);
@@ -388,9 +394,10 @@ void SpringOptionsTab::SwitchUnitsync(const std::string& newIndex, const std::st
 	SlPaths::SetUsedSpringIndex(newIndex);
 	if (!LSL::usync().LoadUnitSyncLib(SlPaths::GetUnitSync(newIndex))) { //FIXME: make LoadUnitSyncLib() async (partly done)
 		wxLogWarning(_T( "Cannot load UnitSync" ));
-		customMessageBox(SL_MAIN_ICON,
-				 wxString::Format(_T("%s is unable to load your UnitSync library into the process.\n\nYou might want to take another look at your unitsync setting."), getSpringlobbyName().c_str()),
-				 _("Spring error"), wxOK);
+		customMessageBox(SL_MAIN_ICON, wxString::Format(_T(
+		  "%s is unable to load your UnitSync library into the process.\n\n"
+		  "You might want to take another look at your unitsync setting."),
+		  GetSpringlobbyName().c_str()), _("Spring error"), wxOK);
 		SlPaths::SetUsedSpringIndex(oldIndex);
 		DoRestore();
 	}
diff --git a/src/gui/playback/playbacktab.cpp b/src/gui/playback/playbacktab.cpp
index f12f204..e6f8843 100644
--- a/src/gui/playback/playbacktab.cpp
+++ b/src/gui/playback/playbacktab.cpp
@@ -344,6 +344,10 @@ void PlaybackTab::Deselected()
 
 void PlaybackTab::ReloadList()
 {
+	if (!LSL::usync().IsLoaded()) {
+		wxLogWarning(_("Unitsync library required"));
+		return;
+	}
 	Deselect();
 	m_replay_dataview->Clear();
 	if (m_replay_loader == nullptr) {
diff --git a/src/gui/singleplayertab.cpp b/src/gui/singleplayertab.cpp
index a5ad439..56f60ff 100644
--- a/src/gui/singleplayertab.cpp
+++ b/src/gui/singleplayertab.cpp
@@ -128,15 +128,15 @@ SinglePlayerTab::SinglePlayerTab(wxWindow* parent, MainSinglePlayerTab& msptab)
 	m_mod_lbl = new wxStaticText(this, -1, _("Game:"));
 	m_ctrl_sizer->Add(m_mod_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
 
-	m_mod_pick = new wxChoice(this, SP_MOD_PICK);
-	m_ctrl_sizer->Add(m_mod_pick, 1, wxALL, 5);
+	m_game_choice = new wxChoice(this, SP_MOD_PICK);
+	m_ctrl_sizer->Add(m_game_choice, 1, wxALL, 5);
 
 	m_mod_lbl = new wxStaticText(this, -1, _("Engine:"));
 	m_ctrl_sizer->Add(m_mod_lbl, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
 
-	m_engine_pick = new wxChoice(this, SP_ENGINE_PICK);
-	m_engine_pick->SetToolTip(_("Select the engine version to play."));
-	m_ctrl_sizer->Add(m_engine_pick, 1, wxALL, 5);
+	m_engine_choice = new wxChoice(this, SP_ENGINE_PICK);
+	m_engine_choice->SetToolTip(_("Select the engine version to play."));
+	m_ctrl_sizer->Add(m_engine_choice, 1, wxALL, 5);
 
 	//  m_ctrl_sizer->Add( 0, 0, 1, wxEXPAND, 0 );
 
@@ -203,7 +203,7 @@ void SinglePlayerTab::ReloadMaplist()
 	} else {
 		m_map_pick->SetStringSelection(TowxString(m_battle.GetHostMapName()));
 		if (m_map_pick->GetStringSelection().IsEmpty()) {
-			SetMap(m_mod_pick->GetCount() - 1);
+			SetMap(m_game_choice->GetCount() - 1);
 		}
 	}
 }
@@ -211,15 +211,15 @@ void SinglePlayerTab::ReloadMaplist()
 
 void SinglePlayerTab::ReloadModlist()
 {
-	m_mod_pick->Clear();
-	m_mod_pick->Append(lslTowxArrayString(LSL::usync().GetGameList()));
-	m_mod_pick->Insert(_("-- Select one --"), m_mod_pick->GetCount());
+	m_game_choice->Clear();
+	m_game_choice->Append(lslTowxArrayString(LSL::usync().GetGameList()));
+	m_game_choice->Insert(_("-- Select one --"), m_game_choice->GetCount());
 	if (m_battle.GetHostGameName().empty()) {
-		m_mod_pick->SetSelection(m_mod_pick->GetCount() - 1);
+		m_game_choice->SetSelection(m_game_choice->GetCount() - 1);
 	} else {
-		m_mod_pick->SetStringSelection(TowxString(m_battle.GetHostGameName()));
-		if (m_mod_pick->GetStringSelection().empty()) {
-			SetMod(m_mod_pick->GetCount() - 1);
+		m_game_choice->SetStringSelection(TowxString(m_battle.GetHostGameName()));
+		if (m_game_choice->GetStringSelection().empty()) {
+			SetMod(m_game_choice->GetCount() - 1);
 		}
 	}
 }
@@ -229,22 +229,22 @@ void SinglePlayerTab::ReloadEngineList()
 {
 	SlPaths::ValidatePaths();
 
-	m_engine_pick->Clear();
+	m_engine_choice->Clear();
 
 	std::map<std::string, LSL::SpringBundle> versions = SlPaths::GetSpringVersionList();
 	const std::string last = SlPaths::GetCurrentUsedSpringIndex();
 	int i = 0;
 
 	for (auto pair : versions) {
-		m_engine_pick->Insert(TowxString(pair.first), i);
+		m_engine_choice->Insert(TowxString(pair.first), i);
 		if (last == pair.first) {
-			m_engine_pick->SetSelection(i);
+			m_engine_choice->SetSelection(i);
 		}
 		i++;
 	}
 
-	if (m_engine_pick->GetSelection() == wxNOT_FOUND) {
-		m_engine_pick->SetSelection(0);
+	if (m_engine_choice->GetSelection() == wxNOT_FOUND) {
+		m_engine_choice->SetSelection(0);
 	}
 
 	if (i == 0) {
@@ -299,7 +299,7 @@ void SinglePlayerTab::ResetUsername()
 void SinglePlayerTab::SetMod(unsigned int index)
 {
 	//ui().ReloadUnitSync();
-	if (index >= m_mod_pick->GetCount() - 1) {
+	if (index >= m_game_choice->GetCount() - 1) {
 		m_battle.SetHostGame("", "");
 	} else {
 		try {
@@ -312,13 +312,13 @@ void SinglePlayerTab::SetMod(unsigned int index)
 	m_minimap->UpdateMinimap();
 	m_battle.SendHostInfo(IBattle::HI_Restrictions); // Update restrictions in options.
 	m_battle.SendHostInfo(IBattle::HI_Game_Changed); // reload mod options
-	m_mod_pick->SetSelection(index);
+	m_game_choice->SetSelection(index);
 }
 
 
 bool SinglePlayerTab::ValidSetup() const
 {
-	if (m_mod_pick->GetSelection() == wxNOT_FOUND) {
+	if (m_game_choice->GetSelection() == wxNOT_FOUND) {
 		wxLogWarning(_T("no game selected"));
 		customMessageBox(SL_MAIN_ICON, _("You have to select a game first."), _("Game setup error"));
 		return false;
@@ -352,7 +352,7 @@ void SinglePlayerTab::OnMapSelect(wxCommandEvent& /*unused*/)
 
 void SinglePlayerTab::OnModSelect(wxCommandEvent& /*unused*/)
 {
-	const int index = m_mod_pick->GetCurrentSelection();
+	const int index = m_game_choice->GetCurrentSelection();
 
 	if (index == wxNOT_FOUND) { return; }
 
@@ -364,13 +364,13 @@ void SinglePlayerTab::OnModSelect(wxCommandEvent& /*unused*/)
 
 void SinglePlayerTab::OnEngineSelect(wxCommandEvent& /*event*/)
 {
-	const int index = m_engine_pick->GetSelection();
+	const int index = m_engine_choice->GetSelection();
 
 	if (index == wxNOT_FOUND) {
-		wxLogError("Invalid index selected: %d > %d", index, m_engine_pick->GetCount());
+		wxLogError("Invalid index selected: %d > %d", index, m_engine_choice->GetCount());
 		return;
 	}
-	const std::string selection = STD_STRING(m_engine_pick->GetString(index));
+	const std::string selection = STD_STRING(m_engine_choice->GetString(index));
 	wxLogMessage("Selected engine version %s", selection.c_str());
 
 	SlPaths::SetUsedSpringIndex(selection);
diff --git a/src/gui/singleplayertab.h b/src/gui/singleplayertab.h
index cd4d545..df4aa0e 100644
--- a/src/gui/singleplayertab.h
+++ b/src/gui/singleplayertab.h
@@ -66,8 +66,8 @@ private:
 	MapCtrl* m_minimap;
 	wxWindow* m_nominimap;
 	wxChoice* m_map_pick;
-	wxChoice* m_mod_pick;
-	wxChoice* m_engine_pick;
+	wxChoice* m_engine_choice;
+	wxChoice* m_game_choice;
 	wxStaticText* m_map_lbl;
 	wxStaticText* m_mod_lbl;
 	wxButton* m_select_btn;
diff --git a/src/gui/statusbar.cpp b/src/gui/statusbar.cpp
index 76232ea..7d580c8 100644
--- a/src/gui/statusbar.cpp
+++ b/src/gui/statusbar.cpp
@@ -15,7 +15,7 @@ Statusbar::Statusbar(wxWindow* parent)
 {
 	int w[3] = {460, -1, 120};
 	SetFieldsCount(3, w);
-	PushStatusText(TowxString(getSpringlobbyVersion()), 1);
+	PushStatusText(TowxString(GetSpringlobbyAgent()), 1);
 	taskBar = new TaskBar(this);
 }
 
diff --git a/src/gui/ui.cpp b/src/gui/ui.cpp
index d54d202..ac400d1 100644
--- a/src/gui/ui.cpp
+++ b/src/gui/ui.cpp
@@ -48,7 +48,6 @@
 #include "gui/agreementdialog.h"
 #include "updatehelper.h"
 #include "gui/customdialogs.h"
-#include "httpfile.h"
 #include "gui/textentrydialog.h"
 #include "log.h"
 #include "settings.h"
@@ -62,7 +61,6 @@
 
 
 SLCONFIG("/General/AutoUpdate", true, "Determines if springlobby should check for updates on startup");
-SLCONFIG("/General/LastUpdateCheck", 0L, "Last time springlobby checked for an update");
 SLCONFIG("/GUI/StartTab", (long)MainWindow::PAGE_BATTLELIST, "which tab to show on startup");
 SLCONFIG("/Chat/BroadcastEverywhere", true, "setting to spam the server messages in all channels");
 SLCONFIG("/Server/Autoconnect", false, "Connect to server on startup");
@@ -238,7 +236,7 @@ void Ui::ConsoleHelp()
 		wxLogError(_T("GetActiveChatPanel() failed: couldn't find current active panel."));
 		return;
 	}
-	panel->ClientMessage(_("SpringLobby commands help."));
+	panel->ClientMessage(wxString::Format(_("%s commands help:"), GetSpringlobbyName()));
 	panel->ClientMessage(wxEmptyString);
 	panel->ClientMessage(_("Global commands:"));
 	panel->ClientMessage(_("  \"/away\" - Sets your status to away."));
@@ -254,9 +252,11 @@ void Ui::ConsoleHelp()
 	panel->ClientMessage(_("  \"/part\" - Leaves current channel."));
 	panel->ClientMessage(_("  \"/p\" - Alias to /part."));
 	panel->ClientMessage(_("  \"/rename newalias\" - Changes your nickname to newalias."));
-	panel->ClientMessage(_("  \"/sayver\" - Says what version of SpringLobby you have in chat."));
+	panel->ClientMessage(wxString::Format(
+	  _("  \"/sayver\" - Says what version of %s you have in chat."), GetSpringlobbyName()));
 	panel->ClientMessage(_("  \"/testmd5 text\" - Returns md5-b64 hash of given text."));
-	panel->ClientMessage(_("  \"/ver\" - Displays what version of SpringLobby you have."));
+	panel->ClientMessage(wxString::Format(
+	  _("  \"/ver\" - Displays what version of %s you have."), GetSpringlobbyName()));
 	panel->ClientMessage(_("  \"/clear\" - Clears all text from current chat panel"));
 	panel->ClientMessage(wxEmptyString);
 	panel->ClientMessage(_("Chat commands:"));
@@ -274,11 +274,10 @@ ChatPanel* Ui::GetChannelChatPanel(const wxString& channel)
 ////////////////////////////////////////////////////////////////////////////////////////////
 // EVENTS
 ////////////////////////////////////////////////////////////////////////////////////////////
-
 //! @brief Called when connected to a server
 //!
 //! @todo Display in servertab
-void Ui::OnConnected(IServer& server, const wxString& server_name, const wxString& version, bool /*supported*/)
+void Ui::OnConnected(IServer& server, const wxString& server_name, const wxString& /*version*/, bool /*supported*/)
 {
 	slLogDebugFunc("");
 
@@ -291,14 +290,6 @@ void Ui::OnConnected(IServer& server, const wxString& server_name, const wxStrin
 	mw().GetBattleListTab().OnConnected();
 
 	ReopenServerTab();
-
-	if (version.empty()) {
-		wxLogWarning("default version supplied from server is empty!");
-		return;
-	}
-	std::map<std::string, LSL::SpringBundle> enginebundles = SlPaths::GetSpringVersionList();
-	if (!SlPaths::GetCompatibleVersion(STD_STRING(version)).empty())
-		return;
 }
 
 void Ui::OnLoggedIn()
@@ -747,12 +738,7 @@ void Ui::OnInit()
 		mw().ShowTab(cfg().ReadLong(_T( "/GUI/StartTab" )));
 		//don't ask for updates on first run, that's a bit much for a newbie
 		if (cfg().ReadBool(_T("/General/AutoUpdate"))) {
-			const time_t now = time(0);
-			const size_t lastcheck = cfg().ReadLong(_T("/General/LastUpdateCheck"));
-			if (now - lastcheck > 3600) {
-				CheckForUpdates(false);
-				cfg().Write(_T("/General/LastUpdateCheck"), (long)now);
-			}
+			CheckForUpdates(false);
 		}
 	}
 }
@@ -794,32 +780,37 @@ void Ui::OnLobbyDownloaded(wxCommandEvent& data)
 	mw().Close();
 }
 
-void Ui::CheckForUpdates(bool show)
+void Ui::CheckForUpdates(bool is_interactive)
 {
-	std::string latestversion = GetHttpFile(GetLatestVersionUrl());
-	latestversion = STD_STRING(TowxString(latestversion).Trim().Trim(false));
+	std::string latestversion = GetLatestVersion(is_interactive);
 
 	if (latestversion.empty()) {
-		if (show) {
-			customMessageBoxModal(SL_MAIN_ICON, _("There was an error checking for the latest version.\nPlease try again later.\nIf the problem persists, please use Help->Report Bug to report this bug."), _("Error"));
+		if (is_interactive) {
+			customMessageBoxModal(SL_MAIN_ICON, _(
+			  "There was an error checking for the latest version.\n"
+			  "Please try again later.\n"
+			  "If the problem persists, please use Help->Report Bug to report this bug."),
+			  _("Error"));
 		}
 		return;
 	}
 	//get current rev w/o AUX_VERSION added
-	const std::string myVersion = getSpringlobbyVersion();
+	const std::string myVersion = GetSpringlobbyVersion();
 
 	const wxString msg = _("Your Version: ") + myVersion + _T("\n") + _("Latest Version: ") + latestversion;
 	if (latestversion == myVersion) {
-		if (show) {
-			customMessageBoxModal(SL_MAIN_ICON, _("Your SpringLobby version is up to date.\n\n") + msg, _("Up to Date"));
+		if (is_interactive) {
+			customMessageBoxModal(SL_MAIN_ICON, wxString::Format(
+			  _("Your %s version is up to date."), GetSpringlobbyName())
+			  + _T("\n\n") + msg, _("Up to Date"));
 		}
 		return;
 	}
 #ifdef __WXMSW__
 	const wxString message = wxString::Format(_("Your %s version is not up to date.") + _T("\n\n%s\n\n") + _("Would you like to update to the new version?"),
-						  TowxString(getSpringlobbyName()).c_str(),
+						  TowxString(GetSpringlobbyName()).c_str(),
 						  msg.c_str());
-	const wxString heading = _("Update Springlobby?");
+	const wxString heading = wxString::Format(_("Update %s?"), GetSpringlobbyName());
 	if (!Ask(heading, message))
 		return;
 	try {
@@ -839,7 +830,9 @@ void Ui::CheckForUpdates(bool show)
 #else
 	const wxString motivation = _("Please update to the latest version before reporting bugs.");
 	const wxString doublenl = _T("\n\n");
-	customMessageBoxModal(SL_MAIN_ICON, _("Your SpringLobby version is not up to date.") + doublenl + msg + doublenl + motivation, _("Not up to Date"));
+	customMessageBoxModal(SL_MAIN_ICON,
+	  wxString::Format(_("Your %s version is not up to date."), GetSpringlobbyName())
+	  + doublenl + msg + doublenl + motivation, _("Not up to Date"));
 #endif
 }
 
diff --git a/src/gui/ui.h b/src/gui/ui.h
index a1d2e0a..1e625fb 100644
--- a/src/gui/ui.h
+++ b/src/gui/ui.h
@@ -116,7 +116,7 @@ public:
 
 	//! the welcome box, should be called in all code paths directly after MainWindow might be shown for the first time
 	void FirstRunWelcome();
-	void CheckForUpdates(bool show);
+	void CheckForUpdates(bool is_interactive);
 	void EnableDebug(bool enable);
 	void OnInvalidFingerprintReceived(const std::string& fingerprint, const std::string& expected_fingerprint);
 
diff --git a/src/ibattle.cpp b/src/ibattle.cpp
index 93f9eef..e3e4b00 100644
--- a/src/ibattle.cpp
+++ b/src/ibattle.cpp
@@ -105,16 +105,6 @@ LSL::lslColor IBattle::GetFixColour(int i) const
 	return palette[i];
 }
 
-int IBattle::GetPlayerNum(const User& user) const
-{
-	for (user_map_t::size_type i = 0; i < GetNumUsers(); i++) {
-		if (&GetUser(i) == &user)
-			return i;
-	}
-	ASSERT_EXCEPTION(false, _T("The player is not in this game."));
-	return -1;
-}
-
 class DismissColor
 {
 private:
@@ -306,16 +296,16 @@ void IBattle::OnUserBattleStatusUpdated(User& user, UserBattleStatus status)
 		UserBattleStatus& loopstatus = loopuser.BattleStatus();
 		if (loopstatus.spectator)
 			m_opts.spectators++;
-		if (!loopstatus.IsBot()) {
-			if (!loopstatus.spectator) {
+		else  {
+			PlayerJoinedTeam(loopstatus.team);
+			PlayerJoinedAlly(loopstatus.ally);
+			if (!loopstatus.IsBot()) {
 				if (loopstatus.ready && loopstatus.spectator)
 					m_players_ready++;
 				if (loopstatus.sync)
 					m_players_sync++;
 				if (loopstatus.ready && loopstatus.sync)
 					m_players_ok++;
-				PlayerJoinedTeam(loopstatus.team);
-				PlayerJoinedAlly(loopstatus.ally);
 			}
 		}
 	}
@@ -404,6 +394,12 @@ bool IBattle::IsEveryoneReady() const
 }
 
 
+bool IBattle::DoesOpponentExist() const
+{
+	return (2 <= m_ally_sizes.size());
+}
+
+
 void IBattle::AddStartRect(unsigned int allyno, unsigned int left, unsigned int top, unsigned int right, unsigned int bottom)
 {
 	assert(allyno < MAX_TEAMS);
@@ -704,18 +700,22 @@ UserPosition IBattle::GetFreePosition()
 void IBattle::SetHostMap(const std::string& mapname, const std::string& hash)
 {
 	assert(hash.empty() || LSL::Util::MakeHashUnsigned(hash) == hash);
-	ASSERT_LOGIC(!mapname.empty(), "Battle with empty map name!");
-	if (mapname != m_host_map.name || hash != m_host_map.hash) {
-		m_map_loaded = false;
-		m_host_map.name = mapname;
-		m_host_map.hash = hash;
+	if (mapname == m_host_map.name || hash == m_host_map.hash) {
+		return;
 	}
+	m_map_loaded = mapname.empty();
+	m_host_map.name = mapname;
+	m_host_map.hash = hash;
 }
 
 
 void IBattle::SetLocalMap(const std::string& mapname)
 {
-	ASSERT_LOGIC(!mapname.empty(), "Battle with empty map name!");
+	if (mapname.empty()) {
+		wxLogWarning("Battle with empty map name!");
+		return;
+	}
+
 	LSL::UnitsyncMap map = LSL::usync().GetMap(mapname);
 	if (map.name != m_local_map.name || map.hash != m_local_map.hash) {
 		m_local_map = map;
@@ -729,19 +729,16 @@ void IBattle::SetLocalMap(const std::string& mapname)
 
 const LSL::UnitsyncMap& IBattle::LoadMap()
 {
-	if ((!m_map_loaded) && (!m_host_map.name.empty())) {
-		if (MapExists(true)) { //Check if selected map available for engine?
-			try {
-				m_local_map = LSL::usync().GetMap(m_host_map.name);
-				assert(LSL::Util::MakeHashUnsigned(m_local_map.hash) == m_local_map.hash);
-				bool options_loaded = CustomBattleOptions().loadOptions(LSL::Enum::MapOption, m_host_map.name);
-				//TODO: maybe replace this with "silent" IF operator?
-				ASSERT_EXCEPTION(options_loaded, _T("couldn't load the map options"));
-				m_map_loaded = true;
-			} catch (...) {
-			}
-		}
+	if ((m_map_loaded) || (m_host_map.name.empty()) || !MapExists(true))
+		return m_local_map;
+
+	m_local_map = LSL::usync().GetMap(m_host_map.name);
+	assert(LSL::Util::MakeHashUnsigned(m_local_map.hash) == m_local_map.hash);
+	const bool options_loaded = CustomBattleOptions().loadOptions(LSL::Enum::MapOption, m_host_map.name);
+	if (!options_loaded) {
+		wxLogWarning( _T("couldn't load the map options"));
 	}
+	m_map_loaded = true;
 	return m_local_map;
 }
 
@@ -764,7 +761,7 @@ void IBattle::SetHostGame(const std::string& gamename, const std::string& hash)
 	if ((m_host_game.name == gamename) && (m_host_game.hash == hash)) {
 		return;
 	}
-	m_game_loaded = false;
+	m_game_loaded = gamename.empty();
 	m_host_game.name = gamename;
 	m_host_game.hash = hash;
 }
@@ -787,20 +784,21 @@ void IBattle::SetLocalGame(const LSL::UnitsyncGame& mod)
 
 const LSL::UnitsyncGame& IBattle::LoadGame()
 {
-	ASSERT_LOGIC(!m_host_game.name.empty(), "m_host_game.name.empty() is FALSE");
-	if (m_game_loaded) {
+	if (m_game_loaded || m_host_game.name.empty()) {
 		return m_local_game;
 	}
 	if (!GameExists(true)) {
 		wxLogWarning("Game doesn't exist");
 		return m_local_game;
 	}
-	try {
-		SetLocalGame(LSL::usync().GetGame(m_host_game.name));
-		bool options_loaded = CustomBattleOptions().loadOptions(LSL::Enum::ModOption, m_host_game.name);
-		ASSERT_EXCEPTION(options_loaded, _T("couldn't load the game options"));
-		m_game_loaded = true;
-	} catch (...) {	}
+	SetLocalGame(LSL::usync().GetGame(m_host_game.name));
+	const bool options_loaded = CustomBattleOptions().loadOptions(LSL::Enum::ModOption, m_host_game.name);
+
+	if (!options_loaded) {
+		wxLogWarning("couldn't load the game options");
+	}
+
+	m_game_loaded = true;
 	return m_local_game;
 }
 
@@ -1061,12 +1059,6 @@ bool IBattle::IsFounder(const User& user) const
 		return false;
 }
 
-int IBattle::GetMyPlayerNum() const
-{
-	return GetPlayerNum(GetMe());
-}
-
-
 void IBattle::LoadScriptMMOpts(const std::string& sectionname, const LSL::TDF::PDataList& node)
 {
 	if (!node.ok())
diff --git a/src/ibattle.h b/src/ibattle.h
index 58e75c5..fd5b019 100644
--- a/src/ibattle.h
+++ b/src/ibattle.h
@@ -226,10 +226,6 @@ public:
 	virtual bool IsFounderMe() const;
 	virtual bool IsFounder(const User& user) const;
 
-	virtual int GetMyPlayerNum() const;
-
-	virtual int GetPlayerNum(const User& user) const;
-
 	virtual void SetHostGame(const std::string& gamename, const std::string& hash);
 	virtual void SetLocalGame(const LSL::UnitsyncGame& game);
 	virtual const LSL::UnitsyncGame& LoadGame();
@@ -245,6 +241,7 @@ public:
 	virtual void OnUserRemoved(User& user);
 
 	virtual bool IsEveryoneReady() const;
+	virtual bool DoesOpponentExist() const;
 
 	virtual void ForceSide(User& user, int side);
 	virtual void ForceAlly(User& user, int ally);
diff --git a/src/log.cpp b/src/log.cpp
index 7f35aeb..848851c 100644
--- a/src/log.cpp
+++ b/src/log.cpp
@@ -1,38 +1,62 @@
 /* This file is part of the Springlobby (GPL v2 or later), see COPYING */
 
+#include <cstdio>
+#include <algorithm>
+#include <cstring>
+#include <mutex>
+#include <sys/time.h>
+#include <vector>
+#include <time.h>
+
 #include <wx/log.h>
-#include <boost/thread/mutex.hpp>
 
 #include "log.h"
-#include "utils/conversion.h"
 #include "gui/ui.h"
 #include "gui/mainwindow.h"
-#include "time.h"
-
-#if wxUSE_STD_IOSTREAM
-#include <iostream>
-#endif
+#include "utils/conversion.h"
+#include "downloader/lib/src/Logger.h"
 
 static bool gui = false;
 
+const char* wxLogLevelToString(wxLogLevel level)
+{
+	assert(level < 8); // just in case
+
+	static const char* levelNames[] = {
+	  "Fatal",
+	  "Error",
+	  "Warning",
+	  "Message",
+	  "Status",
+	  "Info",
+	  "Debug",
+	  "Trace"};
+
+	return levelNames[static_cast<int>(level)];
+}
+
 class myLogger : public wxLog
 {
 public:
 	~myLogger()
 	{
-		if (m_logfile != NULL) {
-			fclose(m_logfile);
-		}
+		for (FILE* lf : m_log_files)
+			fclose(lf);
 	}
 	myLogger(bool console, const wxString& logfilepath, bool /*showgui*/)
 	    : wxLog()
-	    , m_console(console)
-	    ,
 	    //		m_gui(showgui),
-	    m_logfile(NULL)
 	{
+		if (console)
+			m_log_files.push_back (stdout);
 		if (!logfilepath.empty()) {
-			m_logfile = fopen(C_STRING(logfilepath), "wb+"); // even if it returns null, wxLogStderr will switch to stderr logging, so it's fine
+			// even if it returns null, wxLogStderr will switch to stderr logging, so it's fine
+			// TODO: it will?
+			FILE* log = fopen(C_STRING(logfilepath), "wb+");
+			if (nullptr == log)
+				wxLogError ("Unable to open log file %s for writing!", logfilepath);
+			else
+				m_log_files.push_back (log);
 		}
 	}
 
@@ -57,7 +81,7 @@ public:
 	// catch and process all log messages
 	void DoLogRecord(wxLogLevel loglevel, const wxString& msg, const wxLogRecordInfo& info) override
 	{
-		boost::mutex::scoped_lock lock(m_mutex);
+		std::lock_guard<std::mutex> lock(m_mutex);
 
 		if (gui && (loglevel == wxLOG_Error || loglevel == wxLOG_FatalError)) // show user only errors
 		{
@@ -66,15 +90,37 @@ public:
 			ui().mw().GetEventHandler()->QueueEvent(event);
 		}
 
-
-		const std::string std_msg = stdprintf("%s %s %s:%d %s\n", GetTimeString().c_str(), LogLevelToString(loglevel).c_str(), info.filename, info.line, (STD_STRING(wxString(msg))).c_str());
-		if (m_console) {
-			std::cout << std_msg;
-		}
-		if (m_logfile != NULL) {
-			fwrite(std_msg.c_str(), std_msg.length(), 1, m_logfile);
-			fflush(m_logfile);
+		// only print the last src_fn_size chars of file name
+		const int src_fn_size = 20;
+		const int src_fn_offset = std::max(0, static_cast<int>(std::strlen(info.filename)) - src_fn_size);
+		const char* src_fn = info.filename + src_fn_offset;
+
+		const std::string log_prefix = stdprintf("%s %-7s %20.20s:%-4d",
+		  GetTimeString().c_str(), wxLogLevelToString(loglevel),
+		  src_fn, info.line);
+
+		char delim = ' '; // indicates that this is a new message, continuations use '+'
+		// sol=Start-Of-Line, eol=End-Of-Line. We have at least one execution of the below loop.
+		// eol should be one past the end character for substring length = eol - sol to work
+		for (size_t sol = 0, eol = 0; eol < msg.Len(); sol = ++eol) {
+			eol = msg.find("\n", sol);
+			if (wxString::npos == eol) {
+				eol = msg.Len();
+				if (sol >= eol) // real end condition
+					break;
+			}
+			wxString line_msg = msg.Mid(sol, eol-sol);
+
+			for (FILE* lf : m_log_files) {
+				fwrite(log_prefix.c_str(), log_prefix.length(), 1, lf);
+				fwrite(&delim, 1, 1, lf);
+				fwrite(line_msg.c_str(), line_msg.length(), 1, lf);
+				fwrite("\n", 1, 1, lf);
+			}
+			delim = '+'; // not first line any more
 		}
+
+		Flush();
 		/*
 	  if (m_gui) {
 		  ChatPanel* p = ui().mw().GetChatTab().AddChatPanel();
@@ -84,35 +130,16 @@ public:
 	  }*/
 	}
 
-	std::string LogLevelToString(wxLogLevel level)
-	{
-		assert(level < 8); // just in case
-
-		const char* levelName[] = {
-		    "Fatal",
-		    "Error",
-		    "Warning",
-		    "Message",
-		    "Status",
-		    "Info",
-		    "Debug",
-		    "Trace"};
-
-		return std::string(levelName[(int)level]);
-	}
-
 	void Flush() override
 	{
-		if (m_logfile != NULL) {
-			fflush(m_logfile);
-		}
+		for (FILE* lf : m_log_files)
+			fflush(lf);
 	}
 
 private:
-	bool m_console;
 	//	bool m_gui;
-	FILE* m_logfile;
-	boost::mutex m_mutex;
+	std::vector<FILE*> m_log_files;
+	std::mutex m_mutex;
 };
 
 
@@ -177,54 +204,45 @@ void Logger::ShowDebugWindow(bool show)
 */
 }
 
-extern void lsllogerror(const char* format, ...)
+extern void LOG_PROGRESS(long /*done*/, long /*total*/, bool /*forceOutput*/)
 {
-	char buf[1024];
-	va_list args;
-	va_start(args, format);
-	const int len = vsnprintf(buf, 1024, format, args);
-	va_end(args);
-	if (len > 0) {
-		const std::string msg(buf, len);
-		wxLogWarning("Error: FIXME: %s", msg.c_str()); //FIXME: lsl throws a lot of errors
-	}
 }
 
-extern void lsllogdebug(const char* format, ...)
+void LOG_DISABLE(bool /*disableLogging*/)
 {
-	char buf[1024];
-	va_list args;
-	va_start(args, format);
-	const int len = vsnprintf(buf, 1024, format, args);
-	va_end(args);
-	if (len > 0) {
-		const std::string msg(buf, len);
-		wxLogDebug("%s", msg.c_str());
-	}
 }
 
-extern void lsllogwarning(const char* format, ...)
+extern void L_LOG(const char* fileName, int line, const char* funcName,
+           L_LEVEL level, const char* format...)
 {
-	char buf[1024];
 	va_list args;
 	va_start(args, format);
-	const int len = vsnprintf(buf, 1024, format, args);
-	va_end(args);
-	if (len > 0) {
-		const std::string msg(buf, len);
-		wxLogWarning("%s", msg.c_str());
-	}
-}
-
-extern void lslloginfo(const char* format, ...)
-{
 	char buf[1024];
-	va_list args;
-	va_start(args, format);
-	const int len = vsnprintf(buf, 1024, format, args);
+	// for some reason wxLogger().LogV() fails on windows, see #826
+	const int res = vsnprintf(buf, sizeof(buf), format, args);
 	va_end(args);
-	if (len > 0) {
-		const std::string msg(buf, len);
-		wxLogInfo("%s", msg.c_str());
+
+	wxLogLevel lvl;
+	switch (level) {
+		case L_RAW:
+			lvl = wxLOG_Debug;
+			break;
+		default:
+		case L_ERROR:
+			lvl = wxLOG_Error;
+			break;
+		case L_WARN:
+			lvl = wxLOG_Warning;
+			break;
+		case L_INFO:
+			lvl = wxLOG_Info;
+			break;
+		case L_DEBUG:
+			lvl = wxLOG_Debug;
+			break;
 	}
+
+	assert(res >= 0);
+	const wxLogRecordInfo info(fileName, line, funcName, PRD_LOG_COMPONENT);
+	wxLog::OnLog(lvl, buf, info);
 }
diff --git a/src/log.h b/src/log.h
index 89a8027..a2bc991 100644
--- a/src/log.h
+++ b/src/log.h
@@ -6,6 +6,10 @@
 #include <string>
 #include <wx/log.h>
 
+#define PRD_LOG_COMPONENT "prd"
+
+const char* wxLogLevelToString(wxLogLevel level);
+
 class wxString;
 class wxLogWindow;
 class wxWindow;
diff --git a/src/socket.cpp b/src/socket.cpp
index dfbb281..5a2715d 100644
--- a/src/socket.cpp
+++ b/src/socket.cpp
@@ -28,15 +28,9 @@ lsl/networking/socket.cpp
 
 #include "socket.h"
 #include "inetclass.h"
+#include "address.h"
 #include "utils/conversion.h"
 
-#ifdef __WXMSW__
-#include <iphlpapi.h>
-#elif defined(linux)
-#include <sys/ioctl.h>
-#include <net/if.h>
-#endif
-
 #ifdef SSL_SUPPORT
 #include <openssl/bio.h>
 #include <openssl/ssl.h>
@@ -44,106 +38,6 @@ lsl/networking/socket.cpp
 #include <openssl/x509.h>
 #endif
 
-#ifdef __WXMSW__
-
-bool GetMacType(std::vector<unsigned char>& mac, const unsigned int mactype)
-{
-	IP_ADAPTER_INFO AdapterInfo[16];      // Allocate information for 16 cards
-	DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
-
-	DWORD dwStatus = GetAdaptersInfo(AdapterInfo, &dwBufLen); // Get info
-	if (dwStatus == ERROR_BUFFER_OVERFLOW) {
-		wxLogError(wxString::Format("To small buffer size: %d", dwStatus));
-		return false;
-	}
-	if (dwStatus != NO_ERROR)
-		return false; // Check status
-
-	for (size_t i = 0; i < dwBufLen / sizeof(AdapterInfo); i++) {
-		if ((mactype != 0) && (AdapterInfo[i].Type != mactype)) //skip not wanted type
-			continue;
-		if (AdapterInfo[i].AddressLength == 0) {
-			wxLogWarning("Zero Address length for adapter");
-			continue;
-		}
-		mac.resize(AdapterInfo[i].AddressLength);
-		mac.assign(AdapterInfo[i].Address, AdapterInfo[i].Address + AdapterInfo[i].AddressLength);
-		for (size_t j = 0; j < mac.size(); j++) {
-			if (mac[j] != 0) {
-				return true;
-			}
-		}
-	}
-	return false;
-}
-
-
-bool GetMac(std::vector<unsigned char>& mac)
-{
-	if (GetMacType(mac, MIB_IF_TYPE_ETHERNET))
-		return true;
-	if (GetMacType(mac, IF_TYPE_IEEE80211))
-		return true;
-	return (GetMacType(mac, 0));
-}
-
-#elif defined(__APPLE__)
-
-bool GetMac(std::vector<unsigned char>& mac)
-{
-	//FIXME: implement this, http://lists.freebsd.org/pipermail/freebsd-hackers/2004-June/007415.html
-	return false;
-}
-
-#else
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <net/if.h>
-#include <netpacket/packet.h>
-#include <ifaddrs.h>
-
-bool GetMac(std::vector<unsigned char>& mac)
-{
-	ifaddrs* ifap = 0;
-	if (getifaddrs(&ifap) == 0) {
-		ifaddrs* iter = ifap;
-		while (iter) {
-			sockaddr_ll* sal = reinterpret_cast<sockaddr_ll*>(iter->ifa_addr);
-			if (sal->sll_family == AF_PACKET) {
-				mac.resize(sal->sll_halen);
-				mac.assign(sal->sll_addr, sal->sll_addr + sal->sll_halen);
-				for (size_t i = 0; i < mac.size(); i++) {
-					if (mac[i] != 0) {
-						freeifaddrs(ifap);
-						return true;
-					}
-				}
-			}
-			iter = iter->ifa_next;
-		}
-		freeifaddrs(ifap);
-	}
-	return false;
-}
-
-#endif
-
-std::string MacToString(std::vector<unsigned char>& mac)
-{
-	std::string res;
-	for (size_t i = 0; i < mac.size(); i++) {
-		char buf[3];
-		snprintf(buf, sizeof(buf), "%02X", mac[i]);
-		if (!res.empty())
-			res += ":";
-		res.append(buf, 2);
-	}
-	return res;
-}
-
 std::string _GetHandle()
 {
 	std::vector<unsigned char> mac;
@@ -252,7 +146,7 @@ void Socket::DoSSLHandshake()
 
 void Socket::StartTLS(const std::string& fingerprint)
 {
-	wxLogMessage("Starting TLS...");
+	wxLogMessage("Starting TLS... %s", fingerprint.c_str());
 	m_excepted_fingerprint = fingerprint;
 	assert(!m_starttls);
 	m_starttls = true;
diff --git a/src/springlobbyapp.cpp b/src/springlobbyapp.cpp
index 4d1a3cc..b892ce6 100644
--- a/src/springlobbyapp.cpp
+++ b/src/springlobbyapp.cpp
@@ -79,7 +79,7 @@ SpringLobbyApp::SpringLobbyApp()
     , m_log_console(true)
     , m_log_window_show(false)
     , m_crash_handle_disable(false)
-    , m_appname(_T("SpringLobby"))
+    , m_appname(GetSpringlobbyName())
 {
 #if wxUSE_UNIX
 	/*
@@ -143,7 +143,7 @@ bool SpringLobbyApp::OnInit()
 	//initialize all loggers, we'll use the returned pointer to set correct parent window later
 	wxLogWindow* loggerwin = Logger::InitializeLoggingTargets(0, m_log_console, m_log_file_path, m_log_window_show, m_log_verbosity);
 
-	wxLogMessage(_T("SpringLobby %s started"), TowxString(getSpringlobbyVersion()).c_str());
+	wxLogMessage(_T("%s started"), TowxString(GetSpringlobbyAgent()).c_str());
 
 	//this needs to called _before_ mainwindow instance is created
 	wxInitAllImageHandlers();
@@ -301,7 +301,7 @@ bool SpringLobbyApp::OnCmdLineParsed(wxCmdLineParser& parser)
 			return false; // not a syntax error, but program should stop if user asked for command line usage
 
 		if (parser.Found(_T("version"))) {
-			wxLogMessage(TowxString(getSpringlobbyVersion()).c_str());
+			wxLogMessage(TowxString(GetSpringlobbyVersion()).c_str());
 			return false;
 		}
 		return true;
diff --git a/src/springlobbyapp.h b/src/springlobbyapp.h
index b7ebe9d..3ec5852 100644
--- a/src/springlobbyapp.h
+++ b/src/springlobbyapp.h
@@ -15,20 +15,21 @@ class SpringLobbyApp : public wxApp
 public:
 	SpringLobbyApp();
 
-	virtual bool OnInit();
-	virtual int OnExit();
+	bool OnInit() override;
+	int OnExit() override;
 
-	virtual void OnFatalException();
+	void OnFatalException() override;
 
 	// System Events
 	bool SelectLanguage();
 
-	virtual void OnInitCmdLine(wxCmdLineParser& parser);
-	virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
+	void OnInitCmdLine(wxCmdLineParser& parser) override;
+	bool OnCmdLineParsed(wxCmdLineParser& parser) override;
 
-	void OnQuit(wxCommandEvent& data);
 
 private:
+	void OnQuit(wxCommandEvent& data);
+
 	bool quit_called;
 
 	wxTranslationHelper* m_translationhelper;
diff --git a/src/springsettings/frame.cpp b/src/springsettings/frame.cpp
index 47da556..d87d6f8 100644
--- a/src/springsettings/frame.cpp
+++ b/src/springsettings/frame.cpp
@@ -276,7 +276,7 @@ void settings_frame::OnMenuChoice(wxCommandEvent& event)
 				detailTab = 0;
 				audioTab = 0;
 				//				hotkeyTab = 0;
-				SetTitle(TowxString(getSpringlobbyName()) + _("(simple mode)"));
+				SetTitle(TowxString(GetSpringlobbyName()) + _("(simple mode)"));
 				if (!sett().getDisableWarning()) {
 					customMessageBox(SS_MAIN_ICON, expertModeWarning, _("Hint"), wxOK);
 				}
@@ -325,7 +325,7 @@ void settings_frame::switchToExpertMode()
 
 	notebook->DeletePage(0);
 	simpleTab = 0;
-	SetTitle(TowxString(getSpringlobbyName()) + _("(expert mode)"));
+	SetTitle(TowxString(GetSpringlobbyName()) + _("(expert mode)"));
 	/*uiTab->updateControls(UPDATE_ALL);
 	detailTab->updateControls(UPDATE_ALL);
 	qualityTab->updateControls(UPDATE_ALL);
diff --git a/src/sysinfo.cpp b/src/sysinfo.cpp
index 0e85a12..ab0b1e7 100644
--- a/src/sysinfo.cpp
+++ b/src/sysinfo.cpp
@@ -7,6 +7,7 @@
 #include <wx/log.h>
 #include <wx/filename.h>
 #include <wx/string.h>
+#include "log.h"
 #include "utils/conversion.h"
 #include "utils/slpaths.h"
 #include "utils/version.h"
@@ -58,9 +59,9 @@ std::string GetSpringlobbyInfo()
 {
 	static const std::string nl = std::string("\n");
 	std::string res;
-	res = getSpringlobbyAgent() + nl;
+	res = GetSpringlobbyAgent() + nl;
 	const bool configwriteable = wxFileName::IsFileWritable(TowxString(SlPaths::GetConfigPath()));
-	res += stdprintf("SpringLobby config file: %s (%swritable)\n",
+	res += stdprintf("Configuration file: %s (%swritable)\n",
 			 SlPaths::GetConfigPath().c_str(),
 			 BtS(configwriteable, "", "not ").c_str());
 	Paths paths;
@@ -71,7 +72,7 @@ std::string GetSpringlobbyInfo()
 		if (path.empty()) {
 			continue;
 		}
-		
+
 #if defined(__WIN32__) || defined(_MSC_VER)
 		path = Utf8ToLocalEncoding(path.c_str());
 #endif
@@ -112,6 +113,11 @@ std::string GetSpringlobbyInfo()
 	res += stdprintf("Portable mode: %s\n", BtS(SlPaths::IsPortableMode()).c_str());
 
 	res += stdprintf(("Compiled with wxWidgets %d.%d.%d.%d"), wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER, wxSUBRELEASE_NUMBER) + nl;
+	res += stdprintf("Global log level: %lu (up to and including %s)\n",
+	  wxLog::GetLogLevel(), wxLogLevelToString (wxLog::GetLogLevel()));
+	res += stdprintf("PR-Downloader log level: %lu (up to and including %s)\n",
+	  wxLog::GetComponentLevel(PRD_LOG_COMPONENT),
+	  wxLogLevelToString (wxLog::GetComponentLevel(PRD_LOG_COMPONENT)));
 	res += "Started with: \n";
 	for (int i = 0; i < wxTheApp->argc; ++i)
 		res += STD_STRING(wxTheApp->argv[i]) + std::string(" ");
diff --git a/src/tasserver.cpp b/src/tasserver.cpp
index c57e7aa..7844287 100644
--- a/src/tasserver.cpp
+++ b/src/tasserver.cpp
@@ -381,7 +381,8 @@ void TASServer::Login()
 		localaddr = "*";
 	m_id_transmission = false;
 	SendCmd("LOGIN", stdprintf("%s %s 0 %s %s\t%u\ta m sp cl p",
-				   GetUserName().c_str(), pass.c_str(), localaddr.c_str(), getSpringlobbyAgent().c_str(), m_crc.GetCRC()));
+	  GetUserName().c_str(), pass.c_str(), localaddr.c_str(),
+	  GetSpringlobbyAgent().c_str(), m_crc.GetCRC()));
 	m_id_transmission = true;
 }
 
@@ -431,7 +432,8 @@ void TASServer::Notify()
 	if (m_last_ping > PING_TIME) { //Send a PING every 30 seconds
 		if (interval > PING_TIME) {
 			m_last_net_packet = 0; //assume local clock is broken and we received a packed within time
-			m_se->OnServerMessage(stdprintf("Springlobby hung or stale clock. Got no timer for %d msec", interval));
+			m_se->OnServerMessage(stdprintf("%s hung or stale clock. Got no timer for %d msec",
+			  GetSpringlobbyName().c_str(), interval));
 		}
 		m_last_ping = 0;
 		Ping();
@@ -976,22 +978,25 @@ void TASServer::ParseJson(const std::string& jsonstr)
 	}
 
 	if (!js.isObject()) {
-		wxLogWarning("Invalid json, object excepted: %s", jsonstr.c_str());
+		m_se->OnServerMessage(stdprintf("Invalid json, object excepted: %s", jsonstr.c_str()));
 		return;
 	}
-
-	if (!js["SAID"].isObject()) {
-		wxLogWarning("Invalid json, object excepted: %s", jsonstr.c_str());
+	if (js["FAILED"].isObject()) {
+		m_se->OnServerMessage(js["FAILED"]["msg"].asString());
 		return;
 	}
 
-	Json::Value said = js["SAID"];
-	cfg().Write(wxString::Format("/Channels/%s/lastid", said["chanName"].asString()), said["id"].asInt());
-	m_se->OnChannelSaid(said["chanName"].asString(), said["userName"].asString(), said["msg"].asString());
+	if (js["SAID"].isObject()) {
+		Json::Value said = js["SAID"];
+		cfg().Write(wxString::Format("/Channels/%s/lastid", said["chanName"].asString()), said["id"].asInt());
+		m_se->OnChannelSaid(said["chanName"].asString(), said["userName"].asString(), said["msg"].asString());
+		//TODO: store last id for channel
+		//said["time"].asInt64();
+		//said["id"].asUInt64();
+		return;
+	}
 
-	//TODO: store last id for channel
-	//said["time"].asInt64();
-	//said["id"].asUInt64();
+	wxLogWarning("Unknown command received: %s", jsonstr.c_str());
 }
 
 
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 201edce..e9a5031 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -52,6 +52,7 @@ Set(test_src
 	"${springlobby_SOURCE_DIR}/src/utils/slconfig.cpp"
 	"${springlobby_SOURCE_DIR}/src/utils/slpaths.cpp"
 	"${springlobby_SOURCE_DIR}/src/utils/conversion.cpp"
+	"${springlobby_SOURCE_DIR}/src/downloader/lib/src/Logger.cpp"
 )
 
 set(test_libs
@@ -80,12 +81,16 @@ set(test_name lobbyid)
 Set(test_src
 	"${CMAKE_CURRENT_SOURCE_DIR}/lobbyid.cpp"
 	"${springlobby_SOURCE_DIR}/src/utils/crc.cpp"
+	"${springlobby_SOURCE_DIR}/src/address.cpp"
 )
 
 set(test_libs
 	${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}
 	${Boost_SYSTEM_LIBRARY}
 )
+if(WIN32)
+	set(test_libs ${test_libs} iphlpapi)
+endif()
 add_springlobby_test(${test_name} "${test_src}" "${test_libs}" "-DTEST")
 ################################################################################
 set(test_name lslconversion)
@@ -113,6 +118,7 @@ Set(test_src
 	"${springlobby_SOURCE_DIR}/src/utils/conversion.cpp"
 	"${springlobby_SOURCE_DIR}/src/downloader/lib/src/lsl/lslutils/misc.cpp"
 	"${springlobby_SOURCE_DIR}/src/downloader/lib/src/lsl/lslutils/conversion.cpp"
+	"${springlobby_SOURCE_DIR}/src/downloader/lib/src/Logger.cpp"
 )
 
 set(test_libs
diff --git a/src/tests/lobbyid.cpp b/src/tests/lobbyid.cpp
index ee3f74a..055c0bf 100644
--- a/src/tests/lobbyid.cpp
+++ b/src/tests/lobbyid.cpp
@@ -5,6 +5,7 @@
 
 #include <stdio.h>
 #include "utils/crc.h"
+#include "address.h"
 
 BOOST_AUTO_TEST_CASE(lobbyid)
 {
@@ -39,3 +40,11 @@ BOOST_AUTO_TEST_CASE(lobbyid)
 	m_crc.UpdateData("The quick brown fox jumps over the lazy dog");
 	BOOST_CHECK(m_crc.GetCRC() == 1095738169); // == 414fa339, http://rosettacode.org/wiki/CRC-32#C.2B.2B
 }
+
+BOOST_AUTO_TEST_CASE(getmac)
+{
+	std::vector<unsigned char> mac;
+	GetMac(mac);
+	const std::string smac = MacToString(mac);
+	printf("%s\n", smac.c_str());
+}
diff --git a/src/updatehelper.cpp b/src/updatehelper.cpp
index 566ed6d..d439440 100644
--- a/src/updatehelper.cpp
+++ b/src/updatehelper.cpp
@@ -2,10 +2,15 @@
 
 #include "updatehelper.h"
 
+#include "httpfile.h"
 #include "utils/conversion.h"
 #include "utils/slconfig.h"
+#include "utils/version.h"
+#include <time.h>
 
+SLCONFIG("/General/LastUpdateCheck", 0L, "Last time springlobby checked for an update");
 SLCONFIG("/General/UpdateChannel", "release", "update channel to use (release or develop)");
+#define VERSION_CHECK_INTERVAL 1*60*60
 
 static bool isReleaseChannel()
 {
@@ -28,3 +33,28 @@ std::string GetLatestVersionUrl()
 	}
 	return std::string("http://springlobby.info/temp/builds/develop/current.txt");
 }
+
+static time_t GetTime()
+{
+	time_t now = time(nullptr);
+	if (static_cast<time_t>(-1) == now) {
+		std::string msg = "time() broke: ";
+		msg += strerror (errno);
+		throw std::runtime_error (msg.c_str());
+	}
+	return now;
+}
+
+std::string GetLatestVersion(bool use_cached)
+{
+	static std::string latest_version = GetSpringlobbyVersion();
+	const time_t now = GetTime();
+	const time_t last_check_time = cfg().ReadLong(_T("/General/LastUpdateCheck"));
+
+	if (latest_version.empty() || !use_cached || now > (last_check_time + VERSION_CHECK_INTERVAL)) {
+		latest_version = GetHttpFile(GetLatestVersionUrl());
+		latest_version = STD_STRING(TowxString(latest_version).Trim().Trim(false));
+		cfg().Write(_T("/General/LastUpdateCheck"), (long)now);
+	}
+	return latest_version;
+}
diff --git a/src/updatehelper.h b/src/updatehelper.h
index b0e823f..2fc838d 100644
--- a/src/updatehelper.h
+++ b/src/updatehelper.h
@@ -7,5 +7,9 @@
 
 std::string GetDownloadUrl(const std::string& version);
 std::string GetLatestVersionUrl();
+// returns current version; if use_cached and check timer has not expired
+//         empty string   ; if download failed
+//         latest version ; otherwise
+std::string GetLatestVersion(bool use_cached = true);
 
 #endif
diff --git a/src/utils/conversion.cpp b/src/utils/conversion.cpp
index fd79d9d..de3a2b5 100644
--- a/src/utils/conversion.cpp
+++ b/src/utils/conversion.cpp
@@ -25,6 +25,9 @@ std::string stdprintf(const char* format, ...)
 	va_start(args, format);
 	const int count = vsnprintf(buf, 1024, format, args);
 	va_end(args);
+	if (count <= 0) {
+		return "";
+	}
 	return std::string(buf, std::min(count, 1024));
 }
 
diff --git a/src/utils/platform.cpp b/src/utils/platform.cpp
index d47becf..a5c3191 100644
--- a/src/utils/platform.cpp
+++ b/src/utils/platform.cpp
@@ -162,7 +162,11 @@ static wxString escapeStr(const wxString& str)
 	return _T("\"") + str + _T("\"");
 }
 
+#ifdef __WXMSW__
 int RunProcess(const wxString& cmd, const wxArrayString& params, const bool async, const bool root)
+#else
+int RunProcess(const wxString& cmd, const wxArrayString& params, const bool /*async*/, const bool /*root*/)
+#endif
 {
 	wxString paramstring;
 	for (wxString param : params) {
diff --git a/src/utils/slpaths.cpp b/src/utils/slpaths.cpp
index 422e9de..f25381b 100644
--- a/src/utils/slpaths.cpp
+++ b/src/utils/slpaths.cpp
@@ -56,12 +56,12 @@ SLCONFIG("/Spring/DownloadDir", TowxString(LSL::Util::EnsureDelimiter(GetMyDocum
 
 std::string SlPaths::GetLocalConfigPath()
 {
-	return GetExecutableFolder() + getSpringlobbyName(true) + ".conf";
+	return GetExecutableFolder() + GetSpringlobbyName(true) + ".conf";
 }
 
 std::string SlPaths::GetDefaultConfigPath()
 {
-	return GetConfigfileDir() + getSpringlobbyName(true) + ".conf";
+	return GetConfigfileDir() + GetSpringlobbyName(true) + ".conf";
 }
 
 bool SlPaths::IsPortableMode()
@@ -405,7 +405,7 @@ std::string SlPaths::GetConfigfileDir()
 #ifndef WIN32
 	path += ".";
 #endif
-	path += getSpringlobbyName(true);
+	path += GetSpringlobbyName(true);
 	return LSL::Util::EnsureDelimiter(path);
 }
 
diff --git a/src/utils/version.cpp b/src/utils/version.cpp
index 79fbf38..9918af6 100644
--- a/src/utils/version.cpp
+++ b/src/utils/version.cpp
@@ -7,25 +7,25 @@
 #include SPRINGLOBBY_CONFIGH
 #include "version.h"
 
-const std::string getSpringlobbyName(bool lowercase)
+const std::string GetSpringlobbyName(bool lowercase)
 {
 	if (lowercase)
 		return "springlobby";
 	return "SpringLobby";
 }
 
-const std::string getSpringlobbyVersion()
+const std::string GetSpringlobbyVersion()
 {
 	const static std::string version(VERSION);
 	return version;
 }
 
-const std::string getSpringlobbyAgent()
+const std::string GetSpringlobbyAgent()
 {
-	std::string agent = getSpringlobbyName() + " ";
-	agent += getSpringlobbyVersion();
+	std::string agent = GetSpringlobbyName() + " ";
+	agent += GetSpringlobbyVersion();
 	agent += " (";
-#if WIN32
+#if defined(_WIN32) || defined(WIN32) || defined(__CYGWIN__) || defined(__MINGW32__)
 	agent += "win";
 #elif __APPLE__
 	agent += "osx";
diff --git a/src/utils/version.h b/src/utils/version.h
index 8da3269..ba70f5c 100644
--- a/src/utils/version.h
+++ b/src/utils/version.h
@@ -5,8 +5,8 @@
 
 #include <string>
 
-const std::string getSpringlobbyVersion();
-const std::string getSpringlobbyAgent();
-const std::string getSpringlobbyName(bool lowercase = false);
+const std::string GetSpringlobbyVersion();
+const std::string GetSpringlobbyAgent();
+const std::string GetSpringlobbyName(bool lowercase = false);
 
 #endif
diff --git a/tools/mxe_create_builddir.sh b/tools/mxe_create_builddir.sh
index adf1b6a..84faced 100755
--- a/tools/mxe_create_builddir.sh
+++ b/tools/mxe_create_builddir.sh
@@ -2,7 +2,7 @@
 
 set -e
 
-COMMIT=34451075836cdd23cb03b69ef285cf4a4ac9489f
+COMMIT=0dcf498f9563fd35eff0273e1b56929fdce60383
 
 if [ ! -d mxe ]; then
 	git clone https://github.com/mxe/mxe.git
@@ -17,9 +17,9 @@ git reset --hard $COMMIT
 
 (
 	echo 'JOBS := 2'
-	echo 'MXE_TARGETS := i686-w64-mingw32.static'
+	echo 'MXE_TARGETS := i686-w64-mingw32.static.posix'
 	echo 'LOCAL_PKG_LIST := openssl boost curl wxwidgets'
-	echo '.DEFAULT local-pkg-list:'
+	echo '.DEFAULT_GOAL  := local-pkg-list'
 	echo 'local-pkg-list: $(LOCAL_PKG_LIST)'
 ) > settings.mk
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/springlobby.git



More information about the Pkg-games-commits mailing list