diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 000000000..3443096d5 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,253 @@ +## Building from source + +In order to build SuperTuxKart from source, you'll need both the code and the assets (See for more information): + +```bash +git clone https://github.com/supertuxkart/stk-code stk-code +svn co https://svn.code.sf.net/p/supertuxkart/code/stk-assets stk-assets +``` + +## Building SuperTuxKart on Linux + +### Dependencies + +To build SuperTuxKart from source, you'll need to install the following packages: + + * OpenGL (mesa) + * OpenAL (recommended: openal-soft-devel) + * Ogg (libogg-dev) + * Vorbis (libvorbis-dev) + * Freetype (libfreetype6-dev) + * libcurl (libcurl-devel) + * libbluetooth (bluez-devel) + * libpng (libpng-devel) + * zlib (zlib-devel) + * jpeg (libjpeg-turbo-devel) + +Ubuntu command: + +```bash +sudo apt-get install build-essential cmake libbluetooth-dev \ +libcurl4-openssl-dev libenet-dev libfreetype6-dev libfribidi-dev \ +libgl1-mesa-dev libglew-dev libjpeg-dev libogg-dev libopenal-dev libpng-dev \ +libssl-dev libvorbis-dev libxrandr-dev libx11-dev pkg-config zlib1g-dev +``` +Fedora command: + +```bash +sudo dnf install @development-tools cmake bluez-libs-devel \ +openssl-devel libcurl-devel freetype-devel fribidi-devel mesa-libGL-devel \ +libjpeg-turbo-devel libogg-devel openal-soft-devel libpng-devel \ +libvorbis-devel libXrandr-devel libGLEW pkgconf zlib-devel +``` +### In-game recorder + +To build the in-game recorder for STK, you have to install +libopenglrecorder from your distribution, or compile it yourself from [here](https://github.com/Benau/libopenglrecorder). +Compilation instruction is explained there. If you don't need this feature, pass `-DBUILD_RECORDER=off` to cmake. + +### Compiling + +To compile SuperTuxKart, run the following commands inside `stk-code` directory: + +```bash +mkdir cmake_build +cd cmake_build +cmake .. +make -j4 +``` +STK can then be run from the build directory with `bin/supertuxkart` + +#### Keeping your build up to date + +To recompile the latest code without redownloading the entire source, first run the ```svn up``` command inside the 'stk-assets' directory, then run the following commands inside the 'stk-code' directory: + +```bash +git pull +cd cmake_build +cmake .. +make -j4 +``` + +##### Build Speed Optimization + +"-j4" is an example, for a faster build, use "-jx" instead, where "x" is the amount of CPU threads you have, minus one. "-j$(nproc)" usually works. + +### Further options + +To create a debug version of STK, run: + +```bash +cmake .. -DCMAKE_BUILD_TYPE=Debug +``` + +You can install your build system-wide: + +```bash +sudo make install +``` + +The default install location is `/usr/local`, i.e. the data files will +be written to `/usr/local/share/games/supertuxkart`, the executable +will be copied to `/usr/local/bin`. To change the default installation +location, specify `CMAKE_INSTALL_PREFIX` when running cmake, e.g.: +`cmake .. -DCMAKE_INSTALL_PREFIX=/opt/stk` + + + +## Building SuperTuxKart on Windows +To Build SuperTuxKart on Windows, follow these instructions: + +1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/). The free Visual Studio Community edition works fine. +2. Download the SuperTuxKart source package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), and unpack it. +*Note: If you downloaded the source package from here: [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), then both `stk-code` and `stk-assets` **must** be in the same directory, otherwise the build can result in failure* +3. Download the Windows dependencies package from either [SuperTuxKart download area: Dependencies - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/) +or [SuperTuxKart on GitHub - Dependencies](https://github.com/supertuxkart/dependencies), and unpack it; then, copy the `dependencies` directory from either the `windows` or the `windows_64bit` directories into the `stk-code` directory, rename it to `dependencies-64bit` if you want to compile a 64bit build. +4. Download CMake from here: [CMake - download page](https://cmake.org/download/), install it; once CMake is installed, double click on the CMake icon on your desktop, and point it towards your `stk-code` directory in the 'Where is the source code' field, and point it to a directory called `build` or `bld` inside the stk-code directory. +5. Press 'Configure'; CMake will ask you if it is OK to create the aforementioned directory, press `Yes`. CMake will then ask you about your version of Visual Studio. +Confirm your selection; *Please look at the table below to avoid confusion between version numbers and releases of Visual Studio*; +CMake will begin creating the required files for the build in the directory. +6. Navigate to your build directory and open the `SuperTuxKart.sln` file; Visual Studio will now load the solution. +7. In the 'Solution Explorer', right click on the `supertuxkart` project and select "Set as StartUp project" +8. Open the 'Build' menu and select 'Build Solution'; or, press the default keyboard shortcut: `CTRL + SHIFT + B` to build the solution. + +*Note: To avoid confusion between releases and versions, refer to this table:* + +Visual Studio Release | Version +----------------------|------------ +Visual Studio 2017| 15 +Visual Studio 2015| 14 +Visual Studio 2013| 13 + +## Building SuperTuxKart on Windows (from PowerShell/Command line) +1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/), the free Visual Studio Community edition works fine. + +2. Download a source package from either [SuperTuxKart 0.9.2 download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/0.9.2) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control) +NOTE: the `stk-code` and `stk-assets` directories **must** be in the same directory +3. Download the Windows dependencies package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/) +or [SuperTuxKart on GitHub - Dependencies](https://github.com/supertuxkart/dependencies) +and unpack the archive; once unpacked, copy the `dependencies` directory from either the `windows` or the `windows_64bit` directories into the `stk-code` directory +4. Download CMake from here: [CMake - download page](https://cmake.org/download/); and install it. Navigate to the `stk-code` directory; and create an directory called "build": +```cmd +mkdir build +cd build +``` +5. Once inside the build directory; run CMake to start the compilation process: +```cmd +cmake .. +``` +6. Now that CMake finished configuring and creating the necessary files for the build, run the build command in the same directory: +```cmd +msbuild.exe SuperTuxKart.sln +``` +SuperTuxKart can now be run as `bin\Debug\supertuxkart.exe` or `bin\Release\supertuxkart.exe` + +## Building SuperTuxKart on macOS + +### Getting Started + +Install the developer tools, either from the OS X Install DVD or from Apple's website. + +If you have never built anything before, you have create `/usr/local/include/` first: + +```bash +sudo mkdir -p /usr/local/include/ +``` + +Symlink the `include`-folder of OpenGL framework to `/usr/local/include/GL` (Unix programs have an easier time finding it this way): + +```bash +sudo ln -s /System/Library/Frameworks/OpenGL.framework/Versions/A/Headers/ /usr/local/include/GL +``` + +On OS X 10.9.5, you might need the following workaround: + +```bash +sudo ln -s `xcrun --show-sdk-path`/usr/include/ /usr/include +sudo ln -s `xcrun --show-sdk-path`/System/Library/Frameworks/OpenGL.framework/Headers/ /usr/local/include/OpenGL +``` +The first link is required in order to find libcurl, the second to find opengl. + +### CMake + +CMake is used to build STK. At this time CMake will not make a binary that is ready for distribution. + +You'll have to run these commands inside your stk-code directory. + + +### STK 0.9.4 or later (or latest git) + +Install homebrew ( https://brew.sh/) +Install all of the dependencies using homebrew : + +```bash +brew install libogg +brew install libvorbis +brew install openal-soft +brew install freetype +brew install curl +brew install openssl@1.1 +brew install fribidi +brew install glew +``` + +Build STK +```bash +mkdir cmake_build +cd cmake_build +CMAKE_PREFIX_PATH=/usr/local/opt/freetype/:/usr/local/opt/curl/:/usr/local/opt/libogg/:/usr/local/opt/libogg/:/usr/local/opt/libvorbis/:/usr/local/opt/openssl\@1.1/:/usr/local/opt/glew/:/usr/local/opt/fribidi/ /usr/local/opt/cmake/bin/cmake .. -DFREETYPE_INCLUDE_DIRS=/usr/local/opt/freetype/include/freetype2/ -DUSE_SYSTEM_GLEW=1 -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include/ -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib +make +``` + +#### (Optional) packaging for distribution + +By default, the executable that is produced is not ready for distribution. Install https://github.com/auriamg/macdylibbundler + +```bash +dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ +``` + +then copy the datafiles into /SuperTuxKart.app/Contents/Resources/data + + +### STK 0.9.3 or earlier + +Download pre-built dependencies from [here](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/OSX/) and put the frameworks in [hard disk root]/Library/Frameworks + +Building with clang: + +```bash +mkdir cmake_build +cd cmake_build +cmake .. +make +``` + +Building with GCC: +```bash +mkdir cmake_build +cd cmake_build +cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/g++ -DCMAKE_C_COMPILER=/usr/bin/gcc +make +``` + +Building on 10.10 with 10.9 compatibility: +```bash +cmake .. -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 +``` + +#### Xcode + +Place an additional copy of the dependencies into `Users//Library/Frameworks`. +Then cd to your cloned stk-code directory and execute the following commands: + +```bash +mkdir xcode_build && cd xcode_build +cmake .. -GXcode +``` + +Use Finder to navigate to your stk-code/xcode_build folder and open the newly generated Xcode project (`SuperTuxKart.xcodeproj`). + +You can then build the project in Xcode using Product -> Build + +Note: Xcode is much less well tested than makefiles, so there may be issues when trying to use Xcode. diff --git a/README.md b/README.md index fe132907f..0bd4e7070 100644 --- a/README.md +++ b/README.md @@ -30,246 +30,4 @@ The export utilities perform the needed transformation, so in Blender you just ## Building from source -In order to build SuperTuxKart from source, you'll need both the code and the assets (See for more information): - -```bash -git clone https://github.com/supertuxkart/stk-code stk-code -svn co https://svn.code.sf.net/p/supertuxkart/code/stk-assets stk-assets -``` - -## Building SuperTuxKart on Linux - -### Dependencies - -To build SuperTuxKart from source, you'll need to install the following packages: - - * OpenGL (mesa) - * OpenAL (recommended: openal-soft-devel) - * Ogg (libogg-dev) - * Vorbis (libvorbis-dev) - * Freetype (libfreetype6-dev) - * libcurl (libcurl-devel) - * libbluetooth (bluez-devel) - * libpng (libpng-devel) - * zlib (zlib-devel) - * jpeg (libjpeg-turbo-devel) - -Ubuntu command: - -```bash -sudo apt-get install build-essential cmake libbluetooth-dev \ -libcurl4-gnutls-dev libfreetype6-dev libfribidi-dev libgl1-mesa-dev \ -libjpeg-dev libogg-dev libopenal-dev libpng-dev libvorbis-dev libxrandr-dev \ -mesa-common-dev pkg-config zlib1g-dev -``` -### In-game recorder - -To build the in-game recorder for STK, you have to install -libopenglrecorder from your distribution, or compile it yourself from [here](https://github.com/Benau/libopenglrecorder). -Compilation instruction is explained there. If you don't need this feature, pass `-DBUILD_RECORDER=off` to cmake. - -### Compiling - -To compile SuperTuxKart, run the following commands inside `stk-code` directory: - -```bash -mkdir cmake_build -cd cmake_build -cmake .. -make -j4 -``` -STK can then be run from the build directory with `bin/supertuxkart` - -#### Keeping your build up to date - -To recompile the latest code without redownloading the entire source, first run the ```svn up``` command inside the 'stk-assets' directory, then run the following commands inside the 'stk-code' directory: - -```bash -git pull -cd cmake_build -cmake .. -make -j4 -``` - -##### Build Speed Optimization - -"-j4" is an example, for a faster build, use "-jx" instead, where "x" is the amount of CPU threads you have, minus one. - -### Further options - -To create a debug version of STK, run: - -```bash -cmake .. -DCMAKE_BUILD_TYPE=Debug -``` - -You can install your build system-wide: - -```bash -sudo make install -``` - -The default install location is `/usr/local`, i.e. the data files will -be written to `/usr/local/share/games/supertuxkart`, the executable -will be copied to `/usr/local/bin`. To change the default installation -location, specify `CMAKE_INSTALL_PREFIX` when running cmake, e.g.: -`cmake .. -DCMAKE_INSTALL_PREFIX=/opt/stk` - - - -## Building SuperTuxKart on Windows -To Build SuperTuxKart on Windows, follow these instructions: - -1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/). The free Visual Studio Community edition works fine. -2. Download the SuperTuxKart source package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), and unpack it. -*Note: If you downloaded the source package from here: [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control), then both `stk-code` and `stk-assets` **must** be in the same directory, otherwise the build can result in failure* -3. Download the Windows dependencies package from either [SuperTuxKart download area: Dependencies - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/) -or [SuperTuxKart on GitHub - Dependencies](https://github.com/supertuxkart/dependencies), and unpack it; then, copy the `dependencies` directory from either the `windows` or the `windows_64bit` directories into the `stk-code` directory, rename it to `dependencies-64bit` if you want to compile a 64bit build. -4. Download CMake from here: [CMake - download page](https://cmake.org/download/), install it; once CMake is installed, double click on the CMake icon on your desktop, and point it towards your `stk-code` directory in the 'Where is the source code' field, and point it to a directory called `build` or `bld` inside the stk-code directory. -5. Press 'Configure'; CMake will ask you if it is OK to create the aforementioned directory, press `Yes`. CMake will then ask you about your version of Visual Studio. -Confirm your selection; *Please look at the table below to avoid confusion between version numbers and releases of Visual Studio*; -CMake will begin creating the required files for the build in the directory. -6. Navigate to your build directory and open the `SuperTuxKart.sln` file; Visual Studio will now load the solution. -7. In the 'Solution Explorer', right click on the `supertuxkart` project and select "Set as StartUp project" -8. Open the 'Build' menu and select 'Build Solution'; or, press the default keyboard shortcut: `CTRL + SHIFT + B` to build the solution. - -*Note: To avoid confusion between releases and versions, refer to this table:* - -Visual Studio Release | Version -----------------------|------------ -Visual Studio 2017| 15 -Visual Studio 2015| 14 -Visual Studio 2013| 13 - -## Building SuperTuxKart on Windows (from PowerShell/Command line) -1. Download and install Visual Studio from here: [Visual Studio - Download](https://www.visualstudio.com/downloads/), the free Visual Studio Community edition works fine. - -2. Download a source package from either [SuperTuxKart 0.9.2 download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart/0.9.2) or [SuperTuxKart.net - Source Control](https://supertuxkart.net/Source_control) -NOTE: the `stk-code` and `stk-assets` directories **must** be in the same directory -3. Download the Windows dependencies package from either [SuperTuxKart download area - SourceForge.net](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/Windows/) -or [SuperTuxKart on GitHub - Dependencies](https://github.com/supertuxkart/dependencies) -and unpack the archive; once unpacked, copy the `dependencies` directory from either the `windows` or the `windows_64bit` directories into the `stk-code` directory -4. Download CMake from here: [CMake - download page](https://cmake.org/download/); and install it. Navigate to the `stk-code` directory; and create an directory called "build": -```cmd -mkdir build -cd build -``` -5. Once inside the build directory; run CMake to start the compilation process: -```cmd -cmake .. -``` -6. Now that CMake finished configuring and creating the necessary files for the build, run the build command in the same directory: -```cmd -msbuild.exe SuperTuxKart.sln -``` -SuperTuxKart can now be run as `bin\Debug\supertuxkart.exe` or `bin\Release\supertuxkart.exe` - -## Building SuperTuxKart on macOS - -### Getting Started - -Install the developer tools, either from the OS X Install DVD or from Apple's website. - -If you have never built anything before, you have create `/usr/local/include/` first: - -```bash -sudo mkdir -p /usr/local/include/ -``` - -Symlink the `include`-folder of OpenGL framework to `/usr/local/include/GL` (Unix programs have an easier time finding it this way): - -```bash -sudo ln -s /System/Library/Frameworks/OpenGL.framework/Versions/A/Headers/ /usr/local/include/GL -``` - -On OS X 10.9.5, you might need the following workaround: - -```bash -sudo ln -s `xcrun --show-sdk-path`/usr/include/ /usr/include -sudo ln -s `xcrun --show-sdk-path`/System/Library/Frameworks/OpenGL.framework/Headers/ /usr/local/include/OpenGL -``` -The first link is required in order to find libcurl, the second to find opengl. - -### CMake - -CMake is used to build STK. At this time CMake will not make a binary that is ready for distribution. - -You'll have to run these commands inside your stk-code directory. - - -### STK 0.9.4 or later (or latest git) - -Install homebrew ( https://brew.sh/) -Install all of the dependencies using homebrew : - -```bash -brew install libogg -brew install libvorbis -brew install openal-soft -brew install freetype -brew install curl -brew install openssl@1.1 -brew install fribidi -brew install glew -``` - -Build STK -```bash -mkdir cmake_build -cd cmake_build -CMAKE_PREFIX_PATH=/usr/local/opt/freetype/:/usr/local/opt/curl/:/usr/local/opt/libogg/:/usr/local/opt/libogg/:/usr/local/opt/libvorbis/:/usr/local/opt/openssl\@1.1/:/usr/local/opt/glew/:/usr/local/opt/fribidi/ /usr/local/opt/cmake/bin/cmake .. -DFREETYPE_INCLUDE_DIRS=/usr/local/opt/freetype/include/freetype2/ -DUSE_SYSTEM_GLEW=1 -DOPENAL_INCLUDE_DIR=/usr/local/opt/openal-soft/include/ -DOPENAL_LIBRARY=/usr/local/opt/openal-soft/lib/libopenal.dylib -make -``` - -#### (Optional) packaging for distribution - -By default, the executable that is produced is not ready for distribution. Install https://github.com/auriamg/macdylibbundler - -```bash -dylibbundler -od -b -x ./bin/SuperTuxKart.app/Contents/MacOS/supertuxkart -d ./bin/SuperTuxKart.app/Contents/libs/ -p @executable_path/../libs/ -``` - -then copy the datafiles into /SuperTuxKart.app/Contents/Resources/data - - -### STK 0.9.3 or earlier - -Download pre-built dependencies from [here](https://sourceforge.net/projects/supertuxkart/files/SuperTuxKart%20Dependencies/OSX/) and put the frameworks in [hard disk root]/Library/Frameworks - -Building with clang: - -```bash -mkdir cmake_build -cd cmake_build -cmake .. -make -``` - -Building with GCC: -```bash -mkdir cmake_build -cd cmake_build -cmake .. -DCMAKE_CXX_COMPILER=/usr/bin/g++ -DCMAKE_C_COMPILER=/usr/bin/gcc -make -``` - -Building on 10.10 with 10.9 compatibility: -```bash -cmake .. -DCMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9 -``` - -#### Xcode - -Place an additional copy of the dependencies into `Users//Library/Frameworks`. -Then cd to your cloned stk-code directory and execute the following commands: - -```bash -mkdir xcode_build && cd xcode_build -cmake .. -GXcode -``` - -Use Finder to navigate to your stk-code/xcode_build folder and open the newly generated Xcode project (`SuperTuxKart.xcodeproj`). - -You can then build the project in Xcode using Product -> Build - -Note: Xcode is much less well tested than makefiles, so there may be issues when trying to use Xcode. +Building instructions can be found in [`INSTALL.md`](/INSTALL.md) diff --git a/cmake/FindFribidi.cmake b/cmake/FindFribidi.cmake index 4ef0405e8..70fa2cd8c 100644 --- a/cmake/FindFribidi.cmake +++ b/cmake/FindFribidi.cmake @@ -9,7 +9,7 @@ # FRIBIDI_LIBRARIES # Fribidi library list -if(UNIX) +if(UNIX AND NOT APPLE) include(FindPkgConfig) pkg_check_modules(FRIBIDI fribidi) else() diff --git a/data/skins/forest/glasscheckbox_checked.png b/data/skins/forest/glasscheckbox_checked.png index 7a381159c..7b5fd70f5 100644 Binary files a/data/skins/forest/glasscheckbox_checked.png and b/data/skins/forest/glasscheckbox_checked.png differ diff --git a/data/skins/forest/glasscheckbox_checked_deactivated.png b/data/skins/forest/glasscheckbox_checked_deactivated.png index a08213dc1..a7af601ec 100644 Binary files a/data/skins/forest/glasscheckbox_checked_deactivated.png and b/data/skins/forest/glasscheckbox_checked_deactivated.png differ diff --git a/data/skins/forest/glasscheckbox_checked_focus.png b/data/skins/forest/glasscheckbox_checked_focus.png index fd84bd6e4..9d2d0c6aa 100644 Binary files a/data/skins/forest/glasscheckbox_checked_focus.png and b/data/skins/forest/glasscheckbox_checked_focus.png differ diff --git a/data/skins/ocean/glasscheckbox_checked.png b/data/skins/ocean/glasscheckbox_checked.png index d9b404a7f..4da054d19 100644 Binary files a/data/skins/ocean/glasscheckbox_checked.png and b/data/skins/ocean/glasscheckbox_checked.png differ diff --git a/data/skins/ocean/glasscheckbox_checked_deactivated.png b/data/skins/ocean/glasscheckbox_checked_deactivated.png index a08213dc1..a7af601ec 100644 Binary files a/data/skins/ocean/glasscheckbox_checked_deactivated.png and b/data/skins/ocean/glasscheckbox_checked_deactivated.png differ diff --git a/data/skins/ocean/glasscheckbox_checked_focus.png b/data/skins/ocean/glasscheckbox_checked_focus.png index d3212f63b..85643a316 100644 Binary files a/data/skins/ocean/glasscheckbox_checked_focus.png and b/data/skins/ocean/glasscheckbox_checked_focus.png differ diff --git a/data/skins/peach/glasscheckbox_checked.png b/data/skins/peach/glasscheckbox_checked.png index 906c87a0a..09cc593e6 100644 Binary files a/data/skins/peach/glasscheckbox_checked.png and b/data/skins/peach/glasscheckbox_checked.png differ diff --git a/data/skins/peach/glasscheckbox_checked_deactivated.png b/data/skins/peach/glasscheckbox_checked_deactivated.png index a08213dc1..a7af601ec 100644 Binary files a/data/skins/peach/glasscheckbox_checked_deactivated.png and b/data/skins/peach/glasscheckbox_checked_deactivated.png differ diff --git a/data/skins/peach/glasscheckbox_checked_focus.png b/data/skins/peach/glasscheckbox_checked_focus.png index 7585347d6..482a55b42 100644 Binary files a/data/skins/peach/glasscheckbox_checked_focus.png and b/data/skins/peach/glasscheckbox_checked_focus.png differ diff --git a/data/skins/ruby/glasscheckbox_checked.png b/data/skins/ruby/glasscheckbox_checked.png index e69bd416b..5ad4ff025 100644 Binary files a/data/skins/ruby/glasscheckbox_checked.png and b/data/skins/ruby/glasscheckbox_checked.png differ diff --git a/data/skins/ruby/glasscheckbox_checked_deactivated.png b/data/skins/ruby/glasscheckbox_checked_deactivated.png index a08213dc1..a7af601ec 100644 Binary files a/data/skins/ruby/glasscheckbox_checked_deactivated.png and b/data/skins/ruby/glasscheckbox_checked_deactivated.png differ diff --git a/data/skins/ruby/glasscheckbox_checked_focus.png b/data/skins/ruby/glasscheckbox_checked_focus.png index 8e0dbd328..4cfdd05ce 100644 Binary files a/data/skins/ruby/glasscheckbox_checked_focus.png and b/data/skins/ruby/glasscheckbox_checked_focus.png differ diff --git a/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp b/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp index e8bbb3eb2..aad4b0867 100644 --- a/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp +++ b/lib/irrlicht/source/Irrlicht/COGLES2Driver.cpp @@ -2753,26 +2753,26 @@ namespace video void COGLES2CallBridge::setBlendFunc(GLenum source, GLenum destination) { - if(BlendSource != source || BlendDestination != destination) - { + //if(BlendSource != source || BlendDestination != destination) + //{ glBlendFunc(source, destination); BlendSource = source; BlendDestination = destination; - } + //} } void COGLES2CallBridge::setBlend(bool enable) { - if(Blend != enable) - { + //if(Blend != enable) + //{ if (enable) glEnable(GL_BLEND); else glDisable(GL_BLEND); Blend = enable; - } + //} } void COGLES2CallBridge::setCullFaceFunc(GLenum mode) diff --git a/src/addons/addons_manager.cpp b/src/addons/addons_manager.cpp index 72ec42e74..b89aa963f 100644 --- a/src/addons/addons_manager.cpp +++ b/src/addons/addons_manager.cpp @@ -18,6 +18,8 @@ \page addons Addons */ +#ifndef SERVER_ONLY + #include "addons/addons_manager.hpp" #include "addons/news_manager.hpp" @@ -614,3 +616,4 @@ void AddonsManager::saveInstalled() xml_installed.close(); } // saveInstalled +#endif diff --git a/src/addons/addons_manager.hpp b/src/addons/addons_manager.hpp index 2aa096e2d..345f2758a 100644 --- a/src/addons/addons_manager.hpp +++ b/src/addons/addons_manager.hpp @@ -19,6 +19,8 @@ #ifndef HEADER_ADDONS_MANAGER_HPP #define HEADER_ADDONS_MANAGER_HPP +#ifndef SERVER_ONLY + #include #include #include @@ -89,5 +91,6 @@ public: }; // class AddonsManager extern AddonsManager *addons_manager; -#endif +#endif +#endif diff --git a/src/addons/news_manager.cpp b/src/addons/news_manager.cpp index 9ca39aab8..78c8a262b 100644 --- a/src/addons/news_manager.cpp +++ b/src/addons/news_manager.cpp @@ -15,6 +15,8 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +#ifndef SERVER_ONLY + #include "addons/news_manager.hpp" #include "config/user_config.hpp" @@ -490,3 +492,5 @@ bool NewsManager::conditionFulfilled(const std::string &cond) } // conditionFulfilled // ---------------------------------------------------------------------------- + +#endif diff --git a/src/addons/news_manager.hpp b/src/addons/news_manager.hpp index e249a83a8..3819cd8df 100644 --- a/src/addons/news_manager.hpp +++ b/src/addons/news_manager.hpp @@ -18,6 +18,8 @@ #ifndef HEADER_NEWS_MANAGER_HPP #define HEADER_NEWS_MANAGER_HPP +#ifndef SERVER_ONLY + #include #include @@ -143,4 +145,4 @@ public: extern NewsManager *news_manager; #endif - +#endif diff --git a/src/challenges/story_mode_status.cpp b/src/challenges/story_mode_status.cpp index 266f6548d..65ab04976 100644 --- a/src/challenges/story_mode_status.cpp +++ b/src/challenges/story_mode_status.cpp @@ -31,6 +31,7 @@ StoryModeStatus::StoryModeStatus(const XMLNode *node) { m_points = 0; + m_points_before = 0; m_next_unlock_points = 0; m_first_time = true; m_easy_challenges = 0; @@ -79,6 +80,7 @@ bool StoryModeStatus::isLocked(const std::string& feature) //----------------------------------------------------------------------------- void StoryModeStatus::computeActive() { + int old_points = m_points; m_points = 0; m_next_unlock_points = 0; m_easy_challenges = 0; @@ -182,6 +184,9 @@ void StoryModeStatus::computeActive() // now we have the number of points. + if (old_points != m_points) + m_points_before = old_points; + unlockFeatureByList(); //Actually lock the tracks diff --git a/src/challenges/story_mode_status.hpp b/src/challenges/story_mode_status.hpp index 94a7ee1c2..5f1da7423 100644 --- a/src/challenges/story_mode_status.hpp +++ b/src/challenges/story_mode_status.hpp @@ -62,6 +62,7 @@ private: const ChallengeStatus *m_current_challenge; int m_points; + int m_points_before; // used for unlocks int m_next_unlock_points; /** Set to false after the initial stuff (intro, select kart, etc.) */ @@ -101,6 +102,9 @@ public: /** Returns the number of points accumulated. */ int getPoints () const { return m_points; } // ------------------------------------------------------------------------ + /** Returns the number of points before the previous point increase */ + int getPointsBefore () const { return m_points_before; } + // ------------------------------------------------------------------------ /** Returns the number of points needed by the next unlockable. 0 if none. */ int getNextUnlockPoints () const { return m_next_unlock_points; } // ------------------------------------------------------------------------ diff --git a/src/config/player_profile.hpp b/src/config/player_profile.hpp index 519f5f5c3..5f20c9dda 100644 --- a/src/config/player_profile.hpp +++ b/src/config/player_profile.hpp @@ -230,6 +230,8 @@ public: // ------------------------------------------------------------------------ unsigned int getPoints() const { return m_story_mode_status->getPoints(); } // ------------------------------------------------------------------------ + unsigned int getPointsBefore() const { return m_story_mode_status->getPointsBefore(); } + // ------------------------------------------------------------------------ unsigned int getNextUnlockPoints() const { return m_story_mode_status->getNextUnlockPoints(); } // ------------------------------------------------------------------------ void setFirstTime(bool b) { m_story_mode_status->setFirstTime(b); } diff --git a/src/config/user_config.hpp b/src/config/user_config.hpp index f5c08f0de..040509811 100644 --- a/src/config/user_config.hpp +++ b/src/config/user_config.hpp @@ -994,6 +994,10 @@ namespace UserConfigParams PARAM_PREFIX BoolUserConfigParam m_everything_unlocked PARAM_DEFAULT( BoolUserConfigParam(false, "everything_unlocked", "Enable all karts and tracks") ); + + PARAM_PREFIX StringUserConfigParam m_commandline + PARAM_DEFAULT( StringUserConfigParam("", "commandline", + "Allows to set commandline args in config file") ); // TODO? implement blacklist for new irrlicht device and GUI PARAM_PREFIX std::vector m_blacklist_res; diff --git a/src/guiengine/skin.cpp b/src/guiengine/skin.cpp index 996cab11d..c1ebe765c 100644 --- a/src/guiengine/skin.cpp +++ b/src/guiengine/skin.cpp @@ -2498,4 +2498,4 @@ void Skin::setSize (EGUI_DEFAULT_SIZE which, s32 texture_size) void Skin::setSpriteBank (IGUISpriteBank *bank) { m_fallback_skin->setSpriteBank(bank); -} // setSpriteBank +} // setSpriteBank diff --git a/src/guiengine/widgets/icon_button_widget.cpp b/src/guiengine/widgets/icon_button_widget.cpp index de608928a..7503ec42f 100644 --- a/src/guiengine/widgets/icon_button_widget.cpp +++ b/src/guiengine/widgets/icon_button_widget.cpp @@ -160,6 +160,9 @@ void IconButtonWidget::add() m_element = btn; m_id = m_element->getID(); + if (!m_is_visible) + m_element->setVisible(false); + // ---- label if any const stringw& message = getText(); if (message.size() > 0) @@ -222,6 +225,11 @@ void IconButtonWidget::add() m_label->setVisible(false); } + if (!m_is_visible) + { + m_label->setVisible(false); + } + setLabelFont(); m_label->setRightToLeft(translations->isRTLText(message)); diff --git a/src/io/assets_android.cpp b/src/io/assets_android.cpp index 17877f10c..7977dcc43 100644 --- a/src/io/assets_android.cpp +++ b/src/io/assets_android.cpp @@ -60,10 +60,18 @@ void AssetsAndroid::init() paths.push_back(getenv("SUPERTUXKART_DATADIR")); if (global_android_app->activity->externalDataPath) + { + m_file_manager->checkAndCreateDirectoryP( + global_android_app->activity->externalDataPath); paths.push_back(global_android_app->activity->externalDataPath); + } if (global_android_app->activity->internalDataPath) + { + m_file_manager->checkAndCreateDirectoryP( + global_android_app->activity->internalDataPath); paths.push_back(global_android_app->activity->internalDataPath); + } if (getenv("EXTERNAL_STORAGE")) paths.push_back(getenv("EXTERNAL_STORAGE")); diff --git a/src/items/item.hpp b/src/items/item.hpp index b1ea7f98d..326a831c8 100644 --- a/src/items/item.hpp +++ b/src/items/item.hpp @@ -146,6 +146,7 @@ public: } // ItemState(ItemType) // ------------------------------------------------------------------------ + virtual ~ItemState() {} void setDisappearCounter(); void update(int ticks); virtual void collected(const AbstractKart *kart); diff --git a/src/items/item_manager.cpp b/src/items/item_manager.cpp index 493c03084..80862f7f5 100644 --- a/src/items/item_manager.cpp +++ b/src/items/item_manager.cpp @@ -543,6 +543,8 @@ void ItemManager::switchItems() ItemState::ItemType new_type = m_switch_to[(*i)->getType()]; + if (new_type == (*i)->getType()) + continue; if(m_switch_ticks<0) (*i)->switchTo(new_type, m_item_mesh[(int)new_type], m_item_lowres_mesh[(int)new_type]); else diff --git a/src/items/item_manager.hpp b/src/items/item_manager.hpp index 98764421a..e5473e466 100644 --- a/src/items/item_manager.hpp +++ b/src/items/item_manager.hpp @@ -30,10 +30,12 @@ #include #include +#include #include #include class Kart; +class STKPeer; /** * \ingroup items @@ -129,7 +131,8 @@ public: bool randomItemsForArena(const AlignedArray& pos); // ------------------------------------------------------------------------ /** Only used in the NetworkItemManager. */ - virtual void setItemConfirmationTime(int host_id, int ticks) + virtual void setItemConfirmationTime(std::weak_ptr peer, + int ticks) { assert(false); } diff --git a/src/items/network_item_manager.cpp b/src/items/network_item_manager.cpp index 0a08b20c8..ecb11d39a 100644 --- a/src/items/network_item_manager.cpp +++ b/src/items/network_item_manager.cpp @@ -24,7 +24,7 @@ #include "network/protocols/game_protocol.hpp" #include "network/rewind_manager.hpp" #include "network/stk_host.hpp" - +#include "network/stk_peer.hpp" //----------------------------------------------------------------------------- /** Creates one instance of the item manager. */ @@ -42,16 +42,19 @@ NetworkItemManager::NetworkItemManager() : Rewinder(/*can be deleted*/false), ItemManager() { - m_last_confirmed_item_ticks.lock(); - m_last_confirmed_item_ticks.getData().clear(); + m_last_confirmed_item_ticks.clear(); if (NetworkConfig::get()->isServer()) { - m_last_confirmed_item_ticks.getData() - .resize(STKHost::get()->getPeerCount(), 0); + auto peers = STKHost::get()->getPeers(); + for (auto& p : peers) + { + if (!p->isValidated()) + continue; + m_last_confirmed_item_ticks[p] = 0; + } } - m_last_confirmed_item_ticks.unlock(); } // NetworkItemManager //----------------------------------------------------------------------------- @@ -141,23 +144,32 @@ Item* NetworkItemManager::dropNewItem(ItemState::ItemType type, /** Called by the GameProtocol when a confirmation for an item event is * received by a host. Once all hosts have confirmed an event, it can be * deleted and won't be send to any clients again. - * \param host_id Host identification of the host confirming the latest - * event time received. + * \param peer Peer confirming the latest event time received. * \param ticks Time at which the last event was received. */ -void NetworkItemManager::setItemConfirmationTime(int host_id, int ticks) +void NetworkItemManager::setItemConfirmationTime(std::weak_ptr peer, + int ticks) { assert(NetworkConfig::get()->isServer()); - m_last_confirmed_item_ticks.lock(); - if (ticks > m_last_confirmed_item_ticks.getData()[host_id]) - m_last_confirmed_item_ticks.getData()[host_id] = ticks; + if (ticks > m_last_confirmed_item_ticks.at(peer)) + m_last_confirmed_item_ticks.at(peer) = ticks; - // Now discard unneeded events, i.e. all events that have - // been confirmed by all clients: - int min_time = 999999; - for (auto i : m_last_confirmed_item_ticks.getData()) - if (i < min_time) min_time = i; - m_last_confirmed_item_ticks.unlock(); + // Now discard unneeded events and expired (disconnected) peer, i.e. all + // events that have been confirmed by all clients: + int min_time = std::numeric_limits::max(); + for (auto it = m_last_confirmed_item_ticks.begin(); + it != m_last_confirmed_item_ticks.end();) + { + if (it->first.expired()) + { + it = m_last_confirmed_item_ticks.erase(it); + } + else + { + if (it->second < min_time) min_time = it->second; + it++; + } + } // Find the last entry before the minimal confirmed time. // Since the event list is sorted, all events up to this @@ -169,7 +181,6 @@ void NetworkItemManager::setItemConfirmationTime(int host_id, int ticks) m_item_events.getData().erase(m_item_events.getData().begin(), p); m_item_events.unlock(); - // TODO: Get informed when a client drops out!!! } // setItemConfirmationTime //----------------------------------------------------------------------------- @@ -290,7 +301,6 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) if(iei.isItemCollection()) { int index = iei.getIndex(); - ItemState *item_state = m_confirmed_state[index]; // An item on the track was collected: AbstractKart *kart = World::getWorld()->getKart(iei.getKartId()); m_confirmed_state[index]->collected(kart); @@ -322,7 +332,8 @@ void NetworkItemManager::restoreState(BareNetworkString *buffer, int count) } // while count >0 // Inform the server which events have been received. - GameProtocol::lock()->sendItemEventConfirmation(World::getWorld()->getTimeTicks()); + if (auto gp = GameProtocol::lock()) + gp->sendItemEventConfirmation(World::getWorld()->getTimeTicks()); // Forward the confirmed item state till the world time: int dt = World::getWorld()->getTimeTicks() - current_time; diff --git a/src/items/network_item_manager.hpp b/src/items/network_item_manager.hpp index f300e1d0c..16a30d55f 100644 --- a/src/items/network_item_manager.hpp +++ b/src/items/network_item_manager.hpp @@ -25,6 +25,11 @@ #include "utils/cpp2011.hpp" #include "utils/synchronised.hpp" +#include +#include + +class STKPeer; + /** \ingroup items * The network item manager is responsible for handling all network related * item manager tasks - synchronisation between clients and servers. It @@ -47,7 +52,8 @@ private: int m_confirmed_state_time; /** Stores on the server the latest confirmed tick from each client. */ - Synchronised< std::vector > m_last_confirmed_item_ticks; + std::map, int32_t, + std::owner_less > > m_last_confirmed_item_ticks; /** List of all items events. */ Synchronised< std::vector > m_item_events; @@ -64,8 +70,9 @@ public: void sendItemUpdate(); void saveInitialState(); - virtual void reset(); - virtual void setItemConfirmationTime(int host_id, int ticks) OVERRIDE; + virtual void reset() OVERRIDE; + virtual void setItemConfirmationTime(std::weak_ptr peer, + int ticks) OVERRIDE; virtual void collectedItem(Item *item, AbstractKart *kart) OVERRIDE; virtual Item* dropNewItem(ItemState::ItemType type, const AbstractKart *kart, const Vec3 *xyz=NULL) OVERRIDE; diff --git a/src/karts/kart.cpp b/src/karts/kart.cpp index feaf322bd..a65f076f4 100644 --- a/src/karts/kart.cpp +++ b/src/karts/kart.cpp @@ -1687,6 +1687,21 @@ void Kart::update(int ticks) } // update +//----------------------------------------------------------------------------- +void Kart::handleRewoundTransform() +{ + if (!m_controller->isLocalPlayerController()) + { + if (RewindManager::get()->isRewinding()) + m_rewound_transforms.push_back(getTrans()); + else if (!m_rewound_transforms.empty()) + { + setTrans(m_rewound_transforms.front()); + m_rewound_transforms.pop_front(); + } + } +} // handleRewoundTransform + //----------------------------------------------------------------------------- /** Updates the local speed based on the current physical velocity. The value * is smoothed exponentially to avoid camera stuttering (camera distance @@ -2765,7 +2780,8 @@ void Kart::loadData(RaceManager::KartType type, bool is_animated_model) m_skidmarks = new SkidMarks(*this); } - if (CVS->isGLSL() && !CVS->isShadowEnabled()) + if (CVS->isGLSL() && !CVS->isShadowEnabled() && m_kart_properties + ->getShadowMaterial()->getSamplerPath(0) != "unicolor_white") { m_shadow = new Shadow(m_kart_properties->getShadowMaterial(), *this); } diff --git a/src/karts/kart.hpp b/src/karts/kart.hpp index 7a3fb0983..5133d3305 100644 --- a/src/karts/kart.hpp +++ b/src/karts/kart.hpp @@ -32,6 +32,7 @@ #include "karts/abstract_kart.hpp" #include "utils/no_copy.hpp" +#include #include class AbstractKartAnimation; @@ -250,6 +251,8 @@ protected: int m_ticks_last_crash; RaceManager::KartType m_type; + std::deque m_rewound_transforms; + /** To prevent using nitro in too short bursts */ int m_min_nitro_ticks; @@ -547,6 +550,9 @@ public: virtual void playSound(SFXBuffer* buffer) OVERRIDE; // ------------------------------------------------------------------------ virtual bool isVisible() OVERRIDE; + // ------------------------------------------------------------------------ + void handleRewoundTransform(); + }; // Kart diff --git a/src/karts/kart_rewinder.cpp b/src/karts/kart_rewinder.cpp index a1c52b235..275b64fb2 100644 --- a/src/karts/kart_rewinder.cpp +++ b/src/karts/kart_rewinder.cpp @@ -60,15 +60,39 @@ void KartRewinder::reset() void KartRewinder::saveTransform() { m_saved_transform = getTrans(); + m_rewound_transforms.clear(); } // saveTransform // ---------------------------------------------------------------------------- void KartRewinder::computeError() { + // Local player kart doesn't need showing in the past + if (m_rewound_transforms.empty()) + return; + + std::deque copied = m_rewound_transforms; + // Find the closest position that matches previous rewound one + Vec3 saved_position = m_saved_transform.getOrigin(); + while (!copied.empty()) + { + Vec3 cur_position = copied.front().getOrigin(); + if ((cur_position - saved_position).length() < 0.25f) + { + setTrans(copied.front()); + copied.pop_front(); + std::swap(m_rewound_transforms, copied); + return; + } + copied.pop_front(); + } + + // Use newly rewound one if no matching transformation + setTrans(m_rewound_transforms.front()); + m_rewound_transforms.pop_front(); //btTransform error = getTrans() - m_saved_transform; - Vec3 pos_error = getTrans().getOrigin() - m_saved_transform.getOrigin(); - btQuaternion rot_error(0, 0, 0, 1); - Kart::addError(pos_error, rot_error); + //Vec3 pos_error = getTrans().getOrigin() - m_saved_transform.getOrigin(); + //btQuaternion rot_error(0, 0, 0, 1); + //Kart::addError(pos_error, rot_error); } // computeError // ---------------------------------------------------------------------------- diff --git a/src/karts/moveable.cpp b/src/karts/moveable.cpp index 0ca87bd8a..0f195933c 100644 --- a/src/karts/moveable.cpp +++ b/src/karts/moveable.cpp @@ -106,7 +106,7 @@ void Moveable::updateGraphics(float dt, const Vec3& offset_xyz, #endif } #ifndef SERVER_ONLY - Vec3 xyz=getXYZ()+offset_xyz - m_positional_error; + Vec3 xyz=getXYZ()+offset_xyz; m_node->setPosition(xyz.toIrrVector()); btQuaternion r_all = getRotation()*rotation; if(btFuzzyZero(r_all.getX()) && btFuzzyZero(r_all.getY()-0.70710677f) && diff --git a/src/main.cpp b/src/main.cpp index 8e17dacf1..e6ea3d0fd 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1574,7 +1574,9 @@ void initRest() // This only initialises the non-network part of the add-ons manager. The // online section of the add-ons manager will be initialised from a // separate thread running in network HTTP. +#ifndef SERVER_ONLY addons_manager = new AddonsManager(); +#endif Online::ProfileManager::create(); // The request manager will start the login process in case of a saved @@ -1583,7 +1585,9 @@ void initRest() // achievement managers to be created, which can only be created later). PlayerManager::create(); Online::RequestManager::get()->startNetworkThread(); +#ifndef SERVER_ONLY NewsManager::get(); // this will create the news manager +#endif music_manager = new MusicManager(); SFXManager::create(); @@ -1664,8 +1668,10 @@ void askForInternetPermission() Online::RequestManager::IPERM_ALLOWED; UserConfigParams::m_internet_status = Online::RequestManager::IPERM_ALLOWED; +#ifndef SERVER_ONLY if (need_to_start_news_manager) NewsManager::get()->init(false); +#endif GUIEngine::ModalDialog::dismiss(); } // onConfirm // -------------------------------------------------------- @@ -1731,6 +1737,8 @@ int main(int argc, char *argv[] ) // handle all command line options that do not need (or must // not have) other managers initialised: initUserConfig(); + + CommandLine::addArgsFromUserConfig(); handleCmdLinePreliminary(); @@ -1806,6 +1814,7 @@ int main(int argc, char *argv[] ) //handleCmdLine() needs InitTuxkart() so it can't be called first if(!handleCmdLine()) exit(0); +#ifndef SERVER_ONLY addons_manager->checkInstalledAddons(); // Load addons.xml to get info about add-ons even when not @@ -1827,6 +1836,7 @@ int main(int argc, char *argv[] ) } } } +#endif if(UserConfigParams::m_unit_testing) { @@ -1959,6 +1969,7 @@ int main(int argc, char *argv[] ) StateManager::get()->enterGameState(); } +#ifndef SERVER_ONLY // If an important news message exists it is shown in a popup dialog. const core::stringw important_message = NewsManager::get()->getImportantMessage(); @@ -1968,7 +1979,7 @@ int main(int argc, char *argv[] ) MessageDialog::MESSAGE_DIALOG_OK, NULL, true); } // if important_message - +#endif // Replay a race // ============= @@ -2119,11 +2130,13 @@ static void cleanSuperTuxKart() // was deleted (in cleanUserConfig below), but before STK finishes and // the OS takes all threads down. +#ifndef SERVER_ONLY if(!NewsManager::get()->waitForReadyToDeleted(2.0f)) { Log::info("Thread", "News manager not stopping, exiting anyway."); } NewsManager::deallocate(); +#endif if(!Online::RequestManager::get()->waitForReadyToDeleted(5.0f)) { @@ -2144,7 +2157,9 @@ static void cleanSuperTuxKart() // The add-ons manager might still be called from a currenty running request // in the request manager, so it can not be deleted earlier. +#ifndef SERVER_ONLY if(addons_manager) delete addons_manager; +#endif ServersManager::deallocate(); cleanUserConfig(); diff --git a/src/modes/world.cpp b/src/modes/world.cpp index 4806f3d47..58c8da013 100644 --- a/src/modes/world.cpp +++ b/src/modes/world.cpp @@ -1056,6 +1056,16 @@ void World::update(int ticks) Physics::getInstance()->update(ticks); + if (NetworkConfig::get()->isNetworking() && + NetworkConfig::get()->isClient()) + { + for (int i = 0 ; i < kart_amount; i++) + { + if (!m_karts[i]->isEliminated()) + static_cast(m_karts[i])->handleRewoundTransform(); + } + } + PROFILER_PUSH_CPU_MARKER("World::update (projectiles)", 0xa0, 0x7F, 0x00); projectile_manager->update(ticks); PROFILER_POP_CPU_MARKER(); diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 5d735caa1..e6e1853f5 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -322,6 +322,11 @@ void ClientLobby::update(int ticks) case PLAYING: break; case RACE_FINISHED: + if (!RaceEventManager::getInstance()->protocolStopped() || + !GameProtocol::emptyInstance()) + return; + if (!m_received_server_result) + m_received_server_result = true; break; case DONE: m_state.store(EXITING); @@ -762,16 +767,9 @@ void ClientLobby::raceFinished(Event* event) // stop race protocols RaceEventManager::getInstance()->stop(); - RaceEventManager::getInstance()->getProtocol()->requestTerminate(); GameProtocol::lock()->requestTerminate(); - - while (!RaceEventManager::getInstance()->protocolStopped()) - StkTime::sleep(1); - while (!GameProtocol::emptyInstance()) - StkTime::sleep(1); - - m_received_server_result = true; + m_state.store(RACE_FINISHED); } // raceFinished //----------------------------------------------------------------------------- diff --git a/src/network/protocols/game_protocol.cpp b/src/network/protocols/game_protocol.cpp index b33a5380a..ed1ba0b2a 100644 --- a/src/network/protocols/game_protocol.cpp +++ b/src/network/protocols/game_protocol.cpp @@ -101,9 +101,6 @@ bool GameProtocol::notifyEventAsynchronous(Event* event) NetworkString &data = event->data(); uint8_t message_type = data.getUInt8(); - if (message_type != GP_CONTROLLER_ACTION && - message_type != GP_STATE) - printf(""); switch (message_type) { case GP_CONTROLLER_ACTION: handleControllerAction(event); break; @@ -298,10 +295,9 @@ void GameProtocol::sendItemEventConfirmation(int ticks) void GameProtocol::handleItemEventConfirmation(Event *event) { assert(NetworkConfig::get()->isServer()); - int host_id = event->getPeer()->getHostId(); - int ticks = event->data().getTime(); - NetworkItemManager::get()->setItemConfirmationTime(host_id, ticks); - + int ticks = event->data().getTime(); + NetworkItemManager::get()->setItemConfirmationTime(event->getPeerSP(), + ticks); } // handleItemEventConfirmation // ---------------------------------------------------------------------------- diff --git a/src/network/protocols/server_lobby.cpp b/src/network/protocols/server_lobby.cpp index 40d0d3641..4282fec81 100644 --- a/src/network/protocols/server_lobby.cpp +++ b/src/network/protocols/server_lobby.cpp @@ -99,6 +99,9 @@ ServerLobby::ServerLobby() : LobbyProtocol(NULL) "STK addons server, don't bother host one if you don't have the " "corresponding permission, they will be rejected if so."); } + m_result_ns = getNetworkString(); + m_result_ns->setSynchronous(true); + m_waiting_for_reset = false; } // ServerLobby //----------------------------------------------------------------------------- @@ -110,6 +113,7 @@ ServerLobby::~ServerLobby() { unregisterServer(true/*now*/); } + delete m_result_ns; } // ~ServerLobby //----------------------------------------------------------------------------- @@ -142,6 +146,8 @@ void ServerLobby::setup() m_peers_votes.clear(); m_server_delay = 0.0; m_timeout.store(std::numeric_limits::max()); + m_waiting_for_reset = false; + Log::info("ServerLobby", "Reset server to initial state."); } // setup @@ -426,6 +432,21 @@ void ServerLobby::asynchronousUpdate() void ServerLobby::update(int ticks) { // Reset server to initial state if no more connected players + if (m_waiting_for_reset) + { + if ((RaceEventManager::getInstance() && + !RaceEventManager::getInstance()->protocolStopped()) || + !GameProtocol::emptyInstance()) + return; + + RaceResultGUI::getInstance()->backToLobby(); + std::lock_guard lock(m_connection_mutex); + m_game_setup->stopGrandPrix(); + m_state = NetworkConfig::get()->isLAN() ? + ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS; + setup(); + } + if ((m_state.load() > ACCEPTING_CLIENTS || m_game_setup->isGrandPrixStarted()) && STKHost::get()->getPeerCount() == 0 && @@ -434,13 +455,12 @@ void ServerLobby::update(int ticks) if (RaceEventManager::getInstance() && RaceEventManager::getInstance()->isRunning()) { - stopCurrentRace(); + RaceEventManager::getInstance()->stop(); + RaceEventManager::getInstance()->getProtocol()->requestTerminate(); + GameProtocol::lock()->requestTerminate(); } - std::lock_guard lock(m_connection_mutex); - m_game_setup->stopGrandPrix(); - m_state = NetworkConfig::get()->isLAN() ? - ACCEPTING_CLIENTS : REGISTER_SELF_ADDRESS; - setup(); + m_waiting_for_reset = true; + return; } // Reset for ranked server if in kart / track selection has only 1 player @@ -502,6 +522,22 @@ void ServerLobby::update(int ticks) checkRaceFinished(); } break; + case WAIT_FOR_RACE_STOPPED: + if (!RaceEventManager::getInstance()->protocolStopped() || + !GameProtocol::emptyInstance()) + return; + + // This will go back to lobby in server (and exit the current race) + RaceResultGUI::getInstance()->backToLobby(); + // Reset for next state usage + resetPeersReady(); + // Set the delay before the server forces all clients to exit the race + // result screen and go back to the lobby + m_timeout.store((float)StkTime::getRealTime() + 15.0f); + m_state = RESULT_DISPLAY; + sendMessageToPeers(m_result_ns, /*reliable*/ true); + Log::info("ServerLobby", "End of game message sent"); + break; case RESULT_DISPLAY: if (checkPeersReady() || StkTime::getRealTime() > m_timeout.load()) @@ -811,28 +847,32 @@ void ServerLobby::checkRaceFinished() if (!RaceEventManager::getInstance()->isRaceOver()) return; Log::info("ServerLobby", "The game is considered finish."); + // notify the network world that it is stopped + RaceEventManager::getInstance()->stop(); - // Reset for next state usage - resetPeersReady(); - NetworkString* total = getNetworkString(); - total->setSynchronous(true); - total->addUInt8(LE_RACE_FINISHED); + // stop race protocols before going back to lobby (end race) + RaceEventManager::getInstance()->getProtocol()->requestTerminate(); + GameProtocol::lock()->requestTerminate(); + + // Save race result before delete the world + m_result_ns->clear(); + m_result_ns->addUInt8(LE_RACE_FINISHED); if (m_game_setup->isGrandPrix()) { // fastest lap int fastest_lap = static_cast(World::getWorld())->getFastestLapTicks(); - total->addUInt32(fastest_lap); + m_result_ns->addUInt32(fastest_lap); // all gp tracks - total->addUInt8((uint8_t)m_game_setup->getTotalGrandPrixTracks()) + m_result_ns->addUInt8((uint8_t)m_game_setup->getTotalGrandPrixTracks()) .addUInt8((uint8_t)m_game_setup->getAllTracks().size()); for (const std::string& gp_track : m_game_setup->getAllTracks()) - total->encodeString(gp_track); + m_result_ns->encodeString(gp_track); // each kart score and total time auto& players = m_game_setup->getPlayers(); - total->addUInt8((uint8_t)players.size()); + m_result_ns->addUInt8((uint8_t)players.size()); for (unsigned i = 0; i < players.size(); i++) { int last_score = race_manager->getKartScore(i); @@ -846,7 +886,7 @@ void ServerLobby::checkRaceFinished() player->setScore(cur_score); player->setOverallTime(overall_time); } - total->addUInt32(last_score).addUInt32(cur_score) + m_result_ns->addUInt32(last_score).addUInt32(cur_score) .addFloat(overall_time); } } @@ -854,23 +894,14 @@ void ServerLobby::checkRaceFinished() { int fastest_lap = static_cast(World::getWorld())->getFastestLapTicks(); - total->addUInt32(fastest_lap); + m_result_ns->addUInt32(fastest_lap); } if (NetworkConfig::get()->isRankedServer()) { computeNewRankings(); submitRankingsToAddons(); } - - stopCurrentRace(); - // Set the delay before the server forces all clients to exit the race - // result screen and go back to the lobby - m_timeout.store((float)StkTime::getRealTime() + 15.0f); - m_state = RESULT_DISPLAY; - sendMessageToPeers(total, /*reliable*/ true); - delete total; - Log::info("ServerLobby", "End of game message sent"); - + m_state.store(WAIT_FOR_RACE_STOPPED); } // checkRaceFinished //----------------------------------------------------------------------------- @@ -940,13 +971,13 @@ void ServerLobby::computeNewRankings() { result = 0.0; ranking_importance = mode_factor * - MAX_SCALING_TIME * MAX_POINTS_PER_SECOND * player_factors; + scalingValueForTime(MAX_SCALING_TIME) * player_factors; } else if (!players[j]) { result = 1.0; ranking_importance = mode_factor * - MAX_SCALING_TIME * MAX_POINTS_PER_SECOND * player_factors; + scalingValueForTime(MAX_SCALING_TIME) * player_factors; } else { @@ -964,10 +995,11 @@ void ServerLobby::computeNewRankings() (player1_time - player2_time) / (player2_time / 20.0); result = std::max(0.0, 0.5 - result); } + + double max_time = std::min(std::max(player1_time, player2_time), + MAX_SCALING_TIME); ranking_importance = mode_factor * - std::min( - std::max(player1_time, player2_time), MAX_SCALING_TIME) * - MAX_POINTS_PER_SECOND * player_factors; + scalingValueForTime(max_time) * player_factors; } // Compute the ranking change scores_change[i] += @@ -1040,6 +1072,15 @@ double ServerLobby::getModeSpread() return 1.4; } // getModeSpread +//----------------------------------------------------------------------------- +/** Compute the scaling value of a given time + * Short races are more random, so we don't use strict proportionality + */ +double ServerLobby::scalingValueForTime(double time) +{ + return time * sqrt(time / 120.0) * MAX_POINTS_PER_SECOND; +} // scalingValueForTime + //----------------------------------------------------------------------------- /** Manages the distribution of the base points. * Gives half of the points progressively @@ -1052,35 +1093,12 @@ double ServerLobby::distributeBasePoints(uint32_t online_id) unsigned num_races = m_num_ranked_races.at(online_id); if (num_races < 45) { - return - (BASE_RANKING_POINTS / 2000.0 * std::max((45u - num_races), 4u) * - 2.0); + return BASE_RANKING_POINTS / 2000.0 * std::max((45u - num_races), 4u); } else return 0.0; } // distributeBasePoints -//----------------------------------------------------------------------------- -/** Stop any race currently in server, should only be called in main thread. - */ -void ServerLobby::stopCurrentRace() -{ - // notify the network world that it is stopped - RaceEventManager::getInstance()->stop(); - - // stop race protocols before going back to lobby (end race) - RaceEventManager::getInstance()->getProtocol()->requestTerminate(); - GameProtocol::lock()->requestTerminate(); - - while (!RaceEventManager::getInstance()->protocolStopped()) - StkTime::sleep(1); - while (!GameProtocol::emptyInstance()) - StkTime::sleep(1); - - // This will go back to lobby in server (and exit the current race) - RaceResultGUI::getInstance()->backToLobby(); -} // stopCurrentRace - //----------------------------------------------------------------------------- /** Called when a client disconnects. * \param event The disconnect event. diff --git a/src/network/protocols/server_lobby.hpp b/src/network/protocols/server_lobby.hpp index dbe9c612e..df4de3457 100644 --- a/src/network/protocols/server_lobby.hpp +++ b/src/network/protocols/server_lobby.hpp @@ -16,6 +16,7 @@ #include class BareNetworkString; +class NetworkString; class NetworkPlayerProfile; class STKPeer; @@ -34,6 +35,7 @@ public: WAIT_FOR_RACE_STARTED, // Wait for all clients to have started the race DELAY_SERVER, // Additional server delay RACING, // racing + WAIT_FOR_RACE_STOPPED, // Wait server for stopping all race protocols RESULT_DISPLAY, // Show result screen ERROR_LEAVE, // shutting down server EXITING @@ -104,7 +106,7 @@ private: /* Ranking related variables */ // If updating the base points, update the base points distribution in DB const double BASE_RANKING_POINTS = 4000.0; - const double MAX_SCALING_TIME = 600.0; + const double MAX_SCALING_TIME = 500.0; const double MAX_POINTS_PER_SECOND = 0.125; /** Online id to profile map, handling disconnection in ranked server */ @@ -119,6 +121,10 @@ private: /** Number of ranked races done for each current players */ std::map m_num_ranked_races; + bool m_waiting_for_reset; + + NetworkString* m_result_ns; + // connection management void clientDisconnected(Event* event); void connectionRequested(Event* event); @@ -183,8 +189,6 @@ private: uint32_t online_id, const irr::core::stringw& online_name); std::tuple handleVote(); - void stopCurrentRace(); - void getRankingForPlayer(std::shared_ptr p); void submitRankingsToAddons(); void computeNewRankings(); @@ -193,6 +197,8 @@ private: double distributeBasePoints(uint32_t online_id); double getModeFactor(); double getModeSpread(); + double scalingValueForTime(double time); + void checkRaceFinished(); public: ServerLobby(); @@ -207,7 +213,6 @@ public: void signalRaceStartToClients(); void startSelection(const Event *event=NULL); void checkIncomingConnectionRequests(); - void checkRaceFinished(); void finishedLoadingWorld() OVERRIDE; ServerState getCurrentState() const { return m_state.load(); } void updateBanList(); diff --git a/src/network/rewind_manager.cpp b/src/network/rewind_manager.cpp index feeee4a93..2431b94b4 100644 --- a/src/network/rewind_manager.cpp +++ b/src/network/rewind_manager.cpp @@ -162,17 +162,20 @@ void RewindManager::addNetworkState(BareNetworkString *buffer, int ticks) void RewindManager::saveState(bool local_save) { PROFILER_PUSH_CPU_MARKER("RewindManager - save state", 0x20, 0x7F, 0x20); - GameProtocol::lock()->startNewState(local_save); + auto gp = GameProtocol::lock(); + if (!gp) + return; + gp->startNewState(local_save); AllRewinder::const_iterator rewinder; for (rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder) { // TODO: check if it's worth passing in a sufficiently large buffer from // GameProtocol - this would save the copy operation. BareNetworkString *buffer = (*rewinder)->saveState(); - if (buffer && buffer->size() >= 0) + if (buffer) { m_overall_state_size += buffer->size(); - GameProtocol::lock()->addState(buffer); + gp->addState(buffer); } // size >= 0 delete buffer; // buffer can be freed } @@ -186,10 +189,14 @@ void RewindManager::saveState(bool local_save) */ void RewindManager::saveLocalState() { + auto gp = GameProtocol::lock(); + if (!gp) + return; + int ticks = World::getWorld()->getTimeTicks(); saveState(/*local_state*/true); - NetworkString *state = GameProtocol::lock()->getState(); + NetworkString *state = gp->getState(); // Copy the data to a new string, making the buffer in // GameProtocol availble for again. @@ -208,7 +215,6 @@ void RewindManager::saveLocalState() void RewindManager::restoreState(BareNetworkString *data) { data->reset(); - int index = 0; for (auto rewinder = m_all_rewinder.begin(); rewinder != m_all_rewinder.end(); ++rewinder) @@ -230,7 +236,6 @@ void RewindManager::update(int ticks_not_used) m_all_rewinder.size() == 0 || m_is_rewinding) return; - float time = World::getWorld()->getTime(); int ticks = World::getWorld()->getTimeTicks(); m_not_rewound_ticks.store(ticks, std::memory_order_relaxed); @@ -245,7 +250,8 @@ void RewindManager::update(int ticks_not_used) // Save state saveState(/**allow_local_save*/false); PROFILER_PUSH_CPU_MARKER("RewindManager - send state", 0x20, 0x7F, 0x40); - GameProtocol::lock()->sendState(); + if (auto gp = GameProtocol::lock()) + gp->sendState(); PROFILER_POP_CPU_MARKER(); m_last_saved_state = ticks; } // update diff --git a/src/network/rewind_queue.cpp b/src/network/rewind_queue.cpp index 81aa39ee8..ea13f1ce7 100644 --- a/src/network/rewind_queue.cpp +++ b/src/network/rewind_queue.cpp @@ -210,7 +210,6 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind, // Only a client ever rewinds. So the rewind time should be the latest // received state before current world time (if any) *rewind_ticks = -9999; - bool adjust_next = false; // FIXME: making m_network_events sorted would prevent the need to // go through the whole list of events @@ -261,7 +260,8 @@ void RewindQueue::mergeNetworkData(int world_ticks, bool *needs_rewind, // any server message should be in the client's past - but it can // happen during debugging) we need to rewind to getTicks (in order // to get the latest state). - if (NetworkConfig::get()->isClient() && (*i)->getTicks() <= world_ticks) + if (NetworkConfig::get()->isClient() && (*i)->getTicks() <= world_ticks + && (*i)->isState()) { // We need rewind if we receive an event in the past. This will // then trigger a rewind later. Note that we only rewind to the diff --git a/src/online/profile_manager.cpp b/src/online/profile_manager.cpp index 07583ba1f..2768fb2f1 100644 --- a/src/online/profile_manager.cpp +++ b/src/online/profile_manager.cpp @@ -255,16 +255,18 @@ bool ProfileManager::inPersistent(const uint32_t id) */ OnlineProfile* ProfileManager::addPersistent(OnlineProfile * profile) { - if (inPersistent(profile->getID())) + uint32_t profile_id = profile->getID(); + + if (inPersistent(profile_id)) { - m_profiles_persistent[profile->getID()]->merge(profile); + m_profiles_persistent[profile_id]->merge(profile); } else { - m_profiles_persistent[profile->getID()] = profile; + m_profiles_persistent[profile_id] = profile; } - return m_profiles_persistent[profile->getID()]; + return m_profiles_persistent[profile_id]; } // addPersistent // ------------------------------------------------------------------------ diff --git a/src/physics/btKart.cpp b/src/physics/btKart.cpp old mode 100644 new mode 100755 index 7586cdf4a..95b812e35 --- a/src/physics/btKart.cpp +++ b/src/physics/btKart.cpp @@ -353,17 +353,17 @@ void btKart::getVisualContactPoint(float visual_rotation, m_visual_wheels_touch_ground = true; short int old_group = 0; + if (m_chassisBody->getBroadphaseHandle()) + { + old_group = m_chassisBody->getBroadphaseHandle() + ->m_collisionFilterGroup; + m_chassisBody->getBroadphaseHandle()->m_collisionFilterGroup = 0; + } for (int index = 2; index <= 3; index++) { // Map index 0-1 to wheel 2-3 (which are the rear wheels) btWheelInfo &wheel = m_wheelInfo[index]; updateWheelTransformsWS(wheel, false); - if (m_chassisBody->getBroadphaseHandle()) - { - old_group = m_chassisBody->getBroadphaseHandle() - ->m_collisionFilterGroup; - m_chassisBody->getBroadphaseHandle()->m_collisionFilterGroup = 0; - } btScalar max_susp_len = wheel.getSuspensionRestLength() + wheel.m_maxSuspensionTravel; diff --git a/src/states_screens/addons_screen.cpp b/src/states_screens/addons_screen.cpp index 4ba06209a..f50f9ec4d 100644 --- a/src/states_screens/addons_screen.cpp +++ b/src/states_screens/addons_screen.cpp @@ -234,7 +234,7 @@ void AddonsScreen::tearDown() */ void AddonsScreen::loadList() { - +#ifndef SERVER_ONLY // Get the filter by words. GUIEngine::TextBoxWidget* w_filter_name = getWidget("filter_name"); @@ -416,6 +416,7 @@ void AddonsScreen::loadList() else getWidget("category")->select("tab_update", PLAYER_ID_GAME_MASTER); +#endif } // loadList // ---------------------------------------------------------------------------- @@ -452,6 +453,7 @@ void AddonsScreen::onColumnClicked(int column_id) void AddonsScreen::eventCallback(GUIEngine::Widget* widget, const std::string& name, const int playerID) { +#ifndef SERVER_ONLY if (name == "back") { StateManager::get()->escapePressed(); @@ -509,7 +511,7 @@ void AddonsScreen::eventCallback(GUIEngine::Widget* widget, { loadList(); } - +#endif } // eventCallback // ---------------------------------------------------------------------------- @@ -534,6 +536,7 @@ void AddonsScreen::setLastSelected() void AddonsScreen::onUpdate(float dt) { +#ifndef SERVER_ONLY if (m_reloading) { if(UserConfigParams::m_internet_status!=RequestManager::IPERM_ALLOWED) @@ -579,5 +582,5 @@ void AddonsScreen::onUpdate(float dt) m_show_tips = false; } } - +#endif } // onUpdate diff --git a/src/states_screens/addons_screen.hpp b/src/states_screens/addons_screen.hpp index 3b12e3254..339ec49c6 100644 --- a/src/states_screens/addons_screen.hpp +++ b/src/states_screens/addons_screen.hpp @@ -46,7 +46,6 @@ class AddonsScreen : public GUIEngine::Screen, friend class GUIEngine::ScreenSingleton; private: AddonsScreen(); - AddonsManager *m_addons; AddonsLoading *m_load; void loadInformations(); /** Icon for installed addon, which can be updated. */ diff --git a/src/states_screens/dialogs/addons_loading.cpp b/src/states_screens/dialogs/addons_loading.cpp index 2dbe92fca..663194b99 100644 --- a/src/states_screens/dialogs/addons_loading.cpp +++ b/src/states_screens/dialogs/addons_loading.cpp @@ -45,8 +45,10 @@ using namespace irr::gui; */ AddonsLoading::AddonsLoading(const std::string &id) - : ModalDialog(0.8f, 0.8f), - m_addon(*(addons_manager->getAddon(id)) ) + : ModalDialog(0.8f, 0.8f) +#ifndef SERVER_ONLY + , m_addon(*(addons_manager->getAddon(id)) ) +#endif { m_icon_shown = false; @@ -82,6 +84,7 @@ AddonsLoading::~AddonsLoading() void AddonsLoading::beforeAddingWidgets() { +#ifndef SERVER_ONLY /* Init the icon here to be able to load a single image*/ m_icon = getWidget ("icon" ); m_progress = getWidget("progress"); @@ -180,6 +183,7 @@ void AddonsLoading::beforeAddingWidgets() unit = _LTR("%s KB", 1); core::stringw size = _("Size: %s", unit.c_str()); getWidget("size")->setText(size, false); +#endif } // AddonsLoading // ---------------------------------------------------------------------------- @@ -205,6 +209,7 @@ bool AddonsLoading::onEscapePressed() GUIEngine::EventPropagation AddonsLoading::processEvent(const std::string& event_source) { +#ifndef SERVER_ONLY GUIEngine::RibbonWidget* actions_ribbon = getWidget("actions"); @@ -252,12 +257,14 @@ GUIEngine::EventPropagation AddonsLoading::processEvent(const std::string& event voteClicked(); return GUIEngine::EVENT_BLOCK; } +#endif return GUIEngine::EVENT_LET; } // processEvent // ---------------------------------------------------------------------------- void AddonsLoading::voteClicked() { +#ifndef SERVER_ONLY if (PlayerManager::isCurrentLoggedIn()) { // We need to keep a copy of the addon id, since dismiss() will @@ -266,11 +273,13 @@ void AddonsLoading::voteClicked() dismiss(); new VoteDialog(addon_id); } +#endif } // voteClicked // ---------------------------------------------------------------------------- void AddonsLoading::onUpdate(float delta) { +#ifndef SERVER_ONLY if(m_progress->isVisible()) { float progress = m_download_request->getProgress(); @@ -308,6 +317,7 @@ void AddonsLoading::onUpdate(float delta) } m_icon_shown = true; } +#endif } // onUpdate // ---------------------------------------------------------------------------- @@ -316,13 +326,14 @@ void AddonsLoading::onUpdate(float delta) **/ void AddonsLoading::startDownload() { +#ifndef SERVER_ONLY std::string save = "tmp/" + StringUtils::getBasename(m_addon.getZipFileName()); m_download_request = new Online::HTTPRequest(save, /*manage mem*/false, /*priority*/5); m_download_request->setURL(m_addon.getZipFileName()); m_download_request->queue(); - +#endif } // startDownload // ---------------------------------------------------------------------------- @@ -353,6 +364,7 @@ void AddonsLoading::stopDownload() */ void AddonsLoading::doInstall() { +#ifndef SERVER_ONLY delete m_download_request; m_download_request = NULL; @@ -383,12 +395,14 @@ void AddonsLoading::doInstall() } track_manager->loadTrackList(); +#endif } // doInstall // ---------------------------------------------------------------------------- void AddonsLoading::doUninstall() { +#ifndef SERVER_ONLY delete m_download_request; m_download_request = NULL; bool error = !addons_manager->uninstall(m_addon); @@ -418,4 +432,5 @@ void AddonsLoading::doUninstall() AddonsScreen::getInstance()->loadList(); dismiss(); } +#endif } // doUninstall diff --git a/src/states_screens/dialogs/addons_loading.hpp b/src/states_screens/dialogs/addons_loading.hpp index cdc91c6e8..1c217641a 100644 --- a/src/states_screens/dialogs/addons_loading.hpp +++ b/src/states_screens/dialogs/addons_loading.hpp @@ -41,7 +41,9 @@ private: GUIEngine::IconButtonWidget *m_icon; /** The addon to load. */ +#ifndef SERVER_ONLY Addon m_addon; +#endif void startDownload(); void stopDownload(); void doInstall(); diff --git a/src/states_screens/dialogs/vote_dialog.cpp b/src/states_screens/dialogs/vote_dialog.cpp index 923f65120..697ea6c16 100644 --- a/src/states_screens/dialogs/vote_dialog.cpp +++ b/src/states_screens/dialogs/vote_dialog.cpp @@ -93,6 +93,7 @@ bool VoteDialog::onEscapePressed() */ void VoteDialog::sendVote() { +#ifndef SERVER_ONLY /** A vote request. The callback will update the addon manager with the * new average. The VoteDialog polls this request till it is finished * to inform the user about the new average. @@ -125,7 +126,7 @@ void VoteDialog::sendVote() m_rating_widget->setActive(false); m_cancel_widget->setActive(false); - +#endif } // sendVote // ----------------------------------------------------------------------------- diff --git a/src/states_screens/feature_unlocked.cpp b/src/states_screens/feature_unlocked.cpp index 06664f7da..591a5f5f9 100644 --- a/src/states_screens/feature_unlocked.cpp +++ b/src/states_screens/feature_unlocked.cpp @@ -165,10 +165,6 @@ FeatureUnlockedCutScene::FeatureUnlockedCutScene() : CutsceneScreen("feature_unlocked.stkgui") { m_key_angle = 0; - -#ifdef USE_IRRLICHT_BUG_WORKAROUND - m_avoid_irrlicht_bug = NULL; -#endif } // FeatureUnlockedCutScene // ---------------------------------------------------------------------------- @@ -181,12 +177,6 @@ void FeatureUnlockedCutScene::loadedFromFile() void FeatureUnlockedCutScene::onCutsceneEnd() { -#ifdef USE_IRRLICHT_BUG_WORKAROUND - if (m_avoid_irrlicht_bug) - irr_driver->removeNode(m_avoid_irrlicht_bug); - m_avoid_irrlicht_bug = NULL; -#endif - m_unlocked_stuff.clearAndDeleteAll(); #ifndef SERVER_ONLY if (CVS->isGLSL()) @@ -205,8 +195,10 @@ void FeatureUnlockedCutScene::onCutsceneEnd() void FeatureUnlockedCutScene::findWhatWasUnlocked(RaceManager::Difficulty difficulty,std::vector& unlocked) { PlayerProfile *player = PlayerManager::getCurrentPlayer(); - int points_before = player->getPoints(); - int points_now = points_before + CHALLENGE_POINTS[difficulty]; + + // The number of points is updated before this function is called + int points_before = player->getPointsBefore(); + int points_now = player->getPoints(); std::vector tracks; std::vector gps; @@ -362,18 +354,6 @@ void FeatureUnlockedCutScene::init() #ifdef DEBUG m_unlocked_stuff[n].m_root_gift_node->setName("unlocked kart"); -#endif -#ifdef USE_IRRLICHT_BUG_WORKAROUND - // If a mesh with this material is added, irrlicht will - // display the 'continue' text (otherwise the text is - // not visible). This is a terrible work around, but allows - // stk to be released without waiting for the next - // irrlicht version. - video::SMaterial m; - m.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; - scene::IMesh* mesh = - irr_driver->createTexturedQuadMesh(&m, 0, 0); - m_avoid_irrlicht_bug = irr_driver->addMesh(mesh); #endif } #ifndef SERVER_ONLY @@ -475,6 +455,7 @@ void FeatureUnlockedCutScene::onUpdate(float dt) m_global_time += dt; const int unlockedStuffCount = m_unlocked_stuff.size(); + // When the chest has opened but the items are not yet at their final position if (m_global_time > GIFT_EXIT_FROM && m_global_time < GIFT_EXIT_TO) { float progress_factor = (m_global_time - GIFT_EXIT_FROM) / (GIFT_EXIT_TO - GIFT_EXIT_FROM); @@ -489,30 +470,21 @@ void FeatureUnlockedCutScene::onUpdate(float dt) // when there are more than 1 unlocked items, make sure they each // have their own path when they move - if (unlockedStuffCount > 1) - { - if (n == 1) pos.X -= 1.0f*dt*float( int((n + 1)/2) ); - else if (n > 1) pos.X += 1.0f*dt*(n - 0.3f); + // and that they won't end offscreen in usual situations - //else pos.X += 6.2f*dt*float( int((n + 1)/2) ); - //Log::info("FeatureUnlockedCutScene", "Object %d moving by %f", n, - // (n % 2 == 0 ? -4.0f : 4.0f)*float( n/2 + 1 )); - } - else - { - //pos.X -= 2.0f*dt; - } - - //if (m_global_time > GIFT_EXIT_FROM + 2.0f) pos.Z -= 2.0f*dt; + // Put the trophy in center + float pos_value = (n == 0) ? unlockedStuffCount/2 : + (n == unlockedStuffCount/2) ? 0 : n; + float offset = (float) pos_value - ((float) unlockedStuffCount)/2.0f + 0.5f; + offset *= (unlockedStuffCount <= 3) ? 1.4f : + (unlockedStuffCount <= 5) ? 1.2f : 1.0f; + pos.X += offset*dt; pos.Z = smoothed_progress_factor * -4.0f; m_unlocked_stuff[n].m_root_gift_node->setPosition(pos); } } - else if (m_global_time < GIFT_EXIT_FROM) - { - } for (int n=0; ngetDeviceManager()->clearLatestUsedDevice(); +#ifndef SERVER_ONLY if (addons_manager->isLoading()) { IconButtonWidget* w = getWidget("addons"); @@ -152,6 +153,7 @@ void MainMenuScreen::init() const core::stringw &news_text = NewsManager::get()->getNextNewsMessage(); w->setText(news_text, true); w->update(0.01f); +#endif RibbonWidget* r = getWidget("menu_bottomrow"); // FIXME: why do I need to do this manually @@ -174,6 +176,7 @@ void MainMenuScreen::init() void MainMenuScreen::onUpdate(float delta) { +#ifndef SERVER_ONLY PlayerProfile *player = PlayerManager::getCurrentPlayer(); if(PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_GUEST || PlayerManager::getCurrentOnlineState() == PlayerProfile::OS_SIGNED_IN) @@ -222,6 +225,7 @@ void MainMenuScreen::onUpdate(float delta) const core::stringw &news_text = NewsManager::get()->getNextNewsMessage(); w->setText(news_text, true); } +#endif } // onUpdate // ---------------------------------------------------------------------------- @@ -229,6 +233,7 @@ void MainMenuScreen::onUpdate(float delta) void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, const int playerID) { +#ifndef SERVER_ONLY if(name=="user-id") { UserScreen::getInstance()->push(); @@ -534,6 +539,7 @@ void MainMenuScreen::eventCallback(Widget* widget, const std::string& name, { OnlineProfileAchievements::getInstance()->push(); } +#endif } // eventCallback // ---------------------------------------------------------------------------- @@ -546,6 +552,7 @@ void MainMenuScreen::tearDown() void MainMenuScreen::onDisabledItemClicked(const std::string& item) { +#ifndef SERVER_ONLY if (item == "addons") { if (UserConfigParams::m_internet_status != RequestManager::IPERM_ALLOWED) @@ -565,4 +572,5 @@ void MainMenuScreen::onDisabledItemClicked(const std::string& item) new MessageDialog( _("Please wait while the add-ons are loading")); } } +#endif } // onDisabledItemClicked diff --git a/src/states_screens/options_screen_ui.cpp b/src/states_screens/options_screen_ui.cpp index 3179d64c1..a0635763d 100644 --- a/src/states_screens/options_screen_ui.cpp +++ b/src/states_screens/options_screen_ui.cpp @@ -239,6 +239,7 @@ void OptionsScreenUI::init() void OptionsScreenUI::eventCallback(Widget* widget, const std::string& name, const int playerID) { +#ifndef SERVER_ONLY if (name == "options_choice") { std::string selection = ((RibbonWidget*)widget)->getSelectionIDString(PLAYER_ID_GAME_MASTER); @@ -387,7 +388,7 @@ void OptionsScreenUI::eventCallback(Widget* widget, const std::string& name, con OptionsScreenUI::getInstance()->push(); } - +#endif } // eventCallback // ----------------------------------------------------------------------------- diff --git a/src/states_screens/register_screen.cpp b/src/states_screens/register_screen.cpp index fa253d2eb..dcad9e46e 100644 --- a/src/states_screens/register_screen.cpp +++ b/src/states_screens/register_screen.cpp @@ -107,6 +107,15 @@ void RegisterScreen::init() makeEntryFieldsVisible(); local_username->setFocusForPlayer(PLAYER_ID_GAME_MASTER); + + // The behaviour of the screen is slightly different at startup, i.e. + // when it is the first screen: cancel will exit the game, and in + // this case no 'back' error should be shown. + bool has_player_profile = (PlayerManager::get()->getNumPlayers() > 0); + getWidget("back")->setVisible(has_player_profile); + getWidget("cancel")->setLabel(has_player_profile + ? _("Cancel") + : _("Exit game")); } // init // ----------------------------------------------------------------------------- @@ -236,6 +245,13 @@ void RegisterScreen::doRegister() { stringw local_name = getWidget("local_username") ->getText().trim(); + + if (local_name.empty()) + { + m_info_widget->setErrorColor(); + m_info_widget->setText(_("User name cannot be empty."), false); + return; + } handleLocalName(local_name); diff --git a/src/states_screens/user_screen.cpp b/src/states_screens/user_screen.cpp index 4332ce8c0..d1300e207 100644 --- a/src/states_screens/user_screen.cpp +++ b/src/states_screens/user_screen.cpp @@ -17,6 +17,7 @@ #include "states_screens/user_screen.hpp" +#include "addons/news_manager.hpp" #include "audio/sfx_manager.hpp" #include "challenges/unlock_manager.hpp" #include "config/player_manager.hpp" @@ -26,6 +27,7 @@ #include "guiengine/widgets/label_widget.hpp" #include "guiengine/widgets/list_widget.hpp" #include "guiengine/widgets/text_box_widget.hpp" +#include "online/request_manager.hpp" #include "states_screens/dialogs/message_dialog.hpp" #include "states_screens/dialogs/kart_color_slider_dialog.hpp" #include "states_screens/dialogs/recovery_dialog.hpp" @@ -326,18 +328,49 @@ void BaseUserScreen::eventCallback(Widget* widget, } else if (name == "online") { - // If online access is not allowed, do not accept an online account - // but advice the user where to enable this option. + // If online access is not allowed, + // give the player the choice to enable this option. if (m_online_cb->getState()) { if (UserConfigParams::m_internet_status == Online::RequestManager::IPERM_NOT_ALLOWED) { - m_info_widget->setText( - _("Internet access is disabled, please enable it in the options"), - true); + irr::core::stringw message = + _("Internet access is disabled. Do you want to enable it ?"); + + class ConfirmInternet : public MessageDialog::IConfirmDialogListener + { + BaseUserScreen *m_parent_screen; + private: + GUIEngine::CheckBoxWidget *m_cb; + public: + virtual void onConfirm() + { + UserConfigParams::m_internet_status = + Online::RequestManager::IPERM_ALLOWED; +#ifndef SERVER_ONLY + NewsManager::get()->init(false); +#endif + m_parent_screen->makeEntryFieldsVisible(); + ModalDialog::dismiss(); + } // onConfirm + virtual void onCancel() + { + m_cb->setState(false); + m_parent_screen->makeEntryFieldsVisible(); + ModalDialog::dismiss(); + } // onCancel + // ------------------------------------------------------------ + ConfirmInternet(BaseUserScreen *parent, GUIEngine::CheckBoxWidget *online_cb) + { + m_parent_screen = parent; + m_cb = online_cb; + } + }; // ConfirmInternet + SFXManager::get()->quickSound( "anvil" ); - m_online_cb->setState(false); + new MessageDialog(message, MessageDialog::MESSAGE_DIALOG_CONFIRM, + new ConfirmInternet(this, m_online_cb), true); } } makeEntryFieldsVisible(); diff --git a/src/utils/command_line.cpp b/src/utils/command_line.cpp index c68332326..df62a93ec 100644 --- a/src/utils/command_line.cpp +++ b/src/utils/command_line.cpp @@ -32,12 +32,28 @@ std::string CommandLine::m_exec_name=""; void CommandLine::init(unsigned int argc, char *argv[]) { if (argc > 0) + { m_exec_name = argv[0]; + } - for(unsigned int i=1; i config_args; + config_args = StringUtils::split(UserConfigParams::m_commandline, ' '); + + for (std::string config_arg : config_args) + { + m_argv.push_back(config_arg); + } +} + // ---------------------------------------------------------------------------- bool CommandLine::has(const std::string &option) { diff --git a/src/utils/command_line.hpp b/src/utils/command_line.hpp index 84abc5de8..aae6d2400 100644 --- a/src/utils/command_line.hpp +++ b/src/utils/command_line.hpp @@ -79,6 +79,7 @@ private: public: static void init(unsigned int argc, char *argv[]); + static void addArgsFromUserConfig(); static void reportInvalidParameters(); static bool has(const std::string &option); // ------------------------------------------------------------------------